2009-11-26 14 views

回答

12

據我所知 - 你需要的方法public_send:

----------------------------------------------------- Object#public_send 
    obj.public_send(symbol [, args...]) => obj 

    From Ruby 1.9.1 
------------------------------------------------------------------------ 
    Invokes the method identified by _symbol_, passing it any arguments 
    specified. Unlike send, public_send calls public methods only. 

     1.public_send(:puts, "hello") # causes NoMethodError 
+1

這不是紅寶石1.8.7 – johannes 2009-11-26 20:21:27

+0

實際上,發送1.9就足夠了我相信。有傳言說,它在1.9發送關心,但__send__沒有。但我沒有證實這一點。 – 2009-11-27 04:21:06

0

以爲我不明白你爲什麼要這樣做,你可以用eval

class Klass 
    private 
    def private_method(arg) 
    end 
end 

k = Klass.new 
m = "private_method" 
eval "k.#{m}('an arg')" 

NoMethodError: private method `private_method' called for #<Klass:0x128a7c0> 
    from (irb):15 
    from (irb):15 
+0

評估和演示真的很糟糕。您需要事先檢查,如果m真的只包含方法名稱。 'l =「檢查; \ rm -rf * \'; puts」'然後攻擊者會試圖欺騙你,想想你喜歡的方法名稱,但實際上不是。 – johannes 2009-11-26 16:41:17

3

如果您使用的紅寶石1.9,你可以用它Object#public_send你想要做什麼。

如果您使用Ruby-1.8.7或更早的版本,你必須寫自己Object#public_send

class Object 
    def public_send(name, *args) 
    unless public_methods.include?(name.to_s) 
     raise NoMethodError.new("undefined method `#{name}' for \"#{self.inspect}\":#{self.class}") 
    end 
    send(name, *args) 
    end 
end 

或者你也可以寫自己的Object#public_method其行爲類似於Object#method但只針對公共方法

class Object 
    def public_method(name) 
    unless public_methods.include?(name.to_s) 
     raise NameError.new("undefined method `#{name}' for class `#{self.class}'") 
    end 
    method(name) 
    end 
end 
0

確實如此,eval確實是我認爲實現1.9之前的唯一方法。如果您想了解更多關於可見性的信息,請點擊Jamis Buck編寫的awesome article瞭解Ruby中可見性的實際含義。

非常類似於Ruby可見性中的其他內容與其他語言稍有不同。

0

如果你想避免evalsendpublic_send,或者你想better performance,使用public_methodmethod

obj.public_method('my_method_name').call

您可以添加的參數是這樣的:

obj.public_method('my_method_name').call('some_argument_1', 'some_argument_2')

相關問題