如何动态添加attr_reader

时间:2011-03-31 22:39:29

标签: ruby

我希望以下代码按预期工作,但它给了我一个NoMethodError(私有方法`foo'调用#< MyClass ...)

class MyClass
end

my_object = MyClass.new

my_object.instance_variable_set(:@foo, "bar")
MyClass.send("attr_reader", :foo)

puts my_object.foo

问题是我在更大的应用程序中使用完全相同的代码并且它的工作方式与我期望的完全相同,但是当我将其简化为最基本的示例时,它会失败。

(我知道还有很多其他方法可以做我在Ruby上做的事情)

6 个答案:

答案 0 :(得分:9)

使用Module#class_eval

通过执行此操作,该块会将您置于MyClass的上下文中,从而允许您调用attr_reader

ruby-1.9.2-p136 :028 > my_object.instance_variable_set(:@foo, "bar")
 => "bar" 
ruby-1.9.2-p136 :029 > MyClass.class_eval{attr_reader :foo}
 => nil 
ruby-1.9.2-p136 :030 > my_object.foo
 => "bar" 

答案 1 :(得分:3)

有趣的问题,我发现这个解决方案运行正常:

MyClass.class_eval("attr_reader :foo")

答案 2 :(得分:2)

让我们假设您想要为该类的特定实例创建一个访问器(我假设您在该实例上运行时就是这种情况。

您可以简单地打开实例的单例类并使用instance_eval添加访问者

class MyClass
end
my_instance = MyClass.new
my_instance.singleton_class.instance_eval { attr_accessor :foo }
my_instance.foo = :bar
my_instance.foo # => :bar

答案 3 :(得分:1)

@MikeLewis的答案很好,但为什么不重新开课呢?

irb(main):001:0> class MyClass; end
#=> nil
irb(main):002:0> m = MyClass.new
#=> #<MyClass:0x2d43ae0>
irb(main):003:0> class MyClass; attr_accessor :foo; end
#=> nil
irb(main):004:0> m.foo = 42
#=> 42

答案 4 :(得分:0)

只需强制该方法公开:

MyClass.send("public", :foo)

我不知道为什么在某些情况下它是私密的。

答案 5 :(得分:0)

对此我感到困惑,但是一种可行的解决方案是使用MyClass.send(:public, :foo)(即

)显式公开attribute_reader。
class MyClass
end

my_object = MyClass.new

my_object.instance_variable_set(:@foo, "bar")
MyClass.send(:attr_reader, :foo)
MyClass.send(:public, :foo)

puts my_object.foo