这是我认为您正在尝试创建的那种模式:
class Foo
def self.all_properties
@all_properties ||= []
end
def self.property( pr_name )
attr_reader pr_name.to_sym
instance_variable_set( "@default_#{pr_name.to_s}", [pr_name.to_s] )
all_properties << pr_name.to_sym
end
def set_default_properties
self.class.all_properties.each do | pr_name |
default = self.class.instance_variable_get( "@default_#{pr_name.to_s}" )
instance_variable_set( "@#{pr_name}", default.clone )
end
end
def initialize
set_default_properties
end
end
class Bar < Foo
property :foo
end
p Bar.new.foo
它比您最初想象的要复杂。您必须将托管属性列表及其默认值放在某处。我在上面使用类实例变量 @all_properties
和@default_foo
. 您可以使用比问题中更多的元编程将它们转发到每个实例中 - 基本上,必须在实例化期间进行定义时隐藏在类中的默认值的副本。为什么?因为类定义在实例化过程中不会重新运行,所以它只会预先发生一次(除非您开始在构造函数中即时修改类 - 但这是不寻常的!)
请注意,clone
上面代码中的 不足以防止实例相互干扰。我还没有实现深度克隆(留给任何阅读代码的人作为练习),但是该行的以下变体将适用于现有代码,因为默认数据的结构始终相同:
instance_variable_set( "@#{pr_name}", [ default[0].clone ] )