我想在调用某个方法时创建一个实例变量,并将其设置为默认值。然后,实例应该只能获取变量但不能设置变量。这是展示我的问题的一段代码:
class Foo
def self.bar(var)
attr_reader name.to_sym
instance_variable_set("@#{var.to_s}",[var.to_s])
end
end
class Bar < Foo
bar :foo
end
puts Bar.new.foo
当我运行此代码时,我希望获得["foo"]
,但我获得nil
。这似乎是一个范围问题,但是在摆弄代码一段时间之后,我似乎并没有把它弄好。
修改 我刚刚发现了一篇非常好的文章(读到最后),它非常简洁地解决了这个问题。 Click Me
答案 0 :(得分:1)
我想这是你想要创造的那种模式:
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 ] )