在 Adrian 的发现的基础上,这里有一种修改 Virtus 以允许您想要的方法。所有规格都通过此修改。
本质上,Virtus 已经有了 parent 的概念AttributeSet
,但只有在包含Virtus.model
在class中时才会这样。我们也可以扩展它来考虑实例,甚至允许extend(Virtus.model)
在同一个对象中有多个(尽管这听起来不是最理想的):
require 'virtus'
module Virtus
class AttributeSet
def self.create(descendant)
if descendant.respond_to?(:superclass) && descendant.superclass.respond_to?(:attribute_set)
parent = descendant.superclass.public_send(:attribute_set)
elsif !descendant.is_a?(Module)
if descendant.respond_to?(:attribute_set, true) && descendant.send(:attribute_set)
parent = descendant.send(:attribute_set)
elsif descendant.class.respond_to?(:attribute_set)
parent = descendant.class.attribute_set
end
end
descendant.instance_variable_set('@attribute_set', AttributeSet.new(parent))
end
end
end
class User
include Virtus.model
attribute :name, String, default: 'John', lazy: true
end
user = User.new
user.extend(Virtus.model)
user.attribute(:active, Virtus::Attribute::Boolean, default: true, lazy: true)
p user.to_h # => {:name=>"John", :active=>true}
user.extend(Virtus.model) # useless, but to show it works too
user.attribute(:foo, Virtus::Attribute::Boolean, default: false, lazy: true)
p user.to_h # => {:name=>"John", :active=>true, :foo=>false}
也许这值得给 Virtus 做个 PR,你怎么看?