在类作用域方法中设置实例变量

时间:2013-09-11 13:05:21

标签: ruby

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

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

1 个答案:

答案 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 ] )