1

我想在调用某个方法时创建一个实例变量并将其设置为默认值。然后实例应该只能获取变量但不能设置它。这是一段代码来展示我的问题:

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. 这似乎是范围的问题,但是在摆弄了一段时间的代码之后,我似乎并没有把它弄好。

编辑: 我刚刚发现了一篇非常好的文章(读到最后),它非常简洁地解决了这个问题。点击我

4

1 回答 1

2

这是我认为您正在尝试创建的那种模式:

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 ] )
于 2013-09-11T13:25:43.683 回答