我正在使用Virtus(基本上是来自DataMapper的Property API)来构建一个远程API,但是我不认为 Virtus是这里的问题,我认为这是我对Ruby正在做什么。
我想通过使用语法:
来允许强制使用给定类型的属性Node[AnotherClass]
它只是简单地生成Node的子类并返回该新类。那部分是有效的。但由于某种原因,它具有不良副作用。从Virtus::Attribute::Object
下降的所有其他对象实际上也是Node子类本身。我无法解释它,但我认为它必须是与继承模型相关的预期ruby行为。任何人都可以指出我正确的方向吗?
(请注意,如果gem install virtus
),则以下代码无需修改即可运行。
require "virtus"
class JsonModel
include Virtus
end
class Node < Virtus::Attribute::Object
attr_reader :type
class << self
def [](type)
raise ArgumentError, "Child nodes may only be other JsonModel classes" unless type <= JsonModel
@generated_class_map ||= {}
@generated_class_map[type] ||= Class.new(self) do
default lambda { |m, a| type.new }
define_method :type do
type
end
define_method :coerce do |value|
value.kind_of?(Hash) ? type.new(value) : value
end
end
end
end
end
class ChildModel < JsonModel
end
class ParentModel < JsonModel
attribute :child, Node[ChildModel]
attribute :string, String
end
# This should be String, but it's a descendant of Node??
puts ParentModel.attributes[:string].class.ancestors.inspect
答案 0 :(得分:1)
我已将代码缩减为以下内容,但行为仍然相同。
Class.new(Node)
的存在是导致:string
属性在其祖先中拥有Node
的原因。
require "virtus"
class JsonModel
include Virtus
end
class Node < Virtus::Attribute::Object
end
# this does it...
Class.new(Node)
class ParentModel < JsonModel
attribute :string, String
end
# This should be String, but it's a descendant of Node??
puts ParentModel.attributes[:string].class.ancestors.inspect
我不熟悉Virtus,但我猜这与Virtus实现属性类型的方式有关。