2011-03-31 36 views
11

我希望如期下面的代碼工作,但它給了我(呼籲#< MyClass的...私有方法'富」)如何動態地添加attr_reader

class MyClass 
end 

my_object = MyClass.new 

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

puts my_object.foo 

的問題是NoMethodError我在一個更大的應用程序中使用完全相同的代碼,它的工作原理與我所期望的完全相同,但是當我將其簡化爲這個最基本的示例時,它就會失敗。

(我的理解有許多其他方法可以做到什麼,我在Ruby中正在做)

+1

的例子在IRB的作品,但不是紅寶石... – 2011-03-31 22:44:12

+0

@jleedev - 我發現同樣的事情(無論是在紅寶石1.8.6和Ruby 1.8.7企業)。 irb很棒,但是如果你從一個文件運行完全相同的命令......你認爲這是Ruby實現中的一個錯誤(REE主要是redid垃圾收集器)? – 2011-03-31 22:59:34

回答

0

就強制法成爲公衆:

MyClass.send("public", :foo) 

我不知道爲什麼它是私人的一些案例。

+0

這假設'foo'方法已經被定義,對於一些實例變量可能不是這種情況。 – Phrogz 2011-03-31 23:03:13

+0

這是迄今爲止最好的答案,但我仍然好奇爲什麼它在某些情況下是私人的,而不是其他情況。 – Leroy22 2011-03-31 23:48:06

3

有趣的問題,我發現這個解決方案正常工作:

MyClass.class_eval("attr_reader :foo") 
+0

我建議使用塊形式(per @MikeLewis'answer)而不是字符串形式,這樣就不需要運行時解析/解析。 – Phrogz 2011-03-31 23:02:22

+0

是的,你是對的,我剛發現這個工作解決方案很快就沒有尋找更好的方法。 – 2011-04-01 09:44:00

5

使用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" 
+0

我想知道是否能夠爲一個特定的類實例做到這一點。 – 2014-08-14 13:59:53

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 
+0

如果這是一個寶石,你正在調整:'Module ModuleName; end' 原因: 類型錯誤:模塊名是不是一類 \t從(IRB):15 \t從/ usr/bin中/ IRB:12:'

「' – Crisfole 2016-09-16 19:39:27

+0

@Crisfole也許是因爲它是一個'module'而不是一個班級。 – Phrogz 2016-09-17 01:51:33

+0

我必須有寶石混合。我以爲我試圖重新打開這個 - > https://github.com/dcparker/ruby-gmail/blob/master/lib/gmail.rb#L3-L6。也許我忘了運行捆綁軟件.... – Crisfole 2016-09-17 13:17:42

1

假設爲您要創建的類(我假設的該特定實例的訪問的瞬間是如此,因爲你是在實例運行。

你可以簡單地打開實例的單例類,並使用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