使用动态方法调用(#send
或#method
)会忽略方法的可见性
有没有一种简单的方法可以动态调用一个调用私有方法失败的方法?
答案 0 :(得分: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 :(得分:6)
使用public_send
代替send
:
my_object.public_send :method, *args
这是Ruby 1.9的新功能,因此对于较旧的Ruby,您可以require 'backports/1.9.1/kernel/public_send'
。
答案 2 :(得分:3)
如果您使用的是ruby-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
答案 3 :(得分: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
答案 4 :(得分:0)
确实如此,eval确实是我认为在1.9之前实际做到这一点的唯一方法。如果你想了解更多关于可见性的信息,Jamis Buck写了一篇awesome article关于可见性在Ruby中实际意味着什么的方法。
与Ruby中的其他内容非常相似,与其他语言略有不同。
答案 5 :(得分:0)
如果您想避开eval
,send
或public_send
,或者想要better performance,请使用public_method
method:
obj.public_method('my_method_name').call
您可以添加如下参数:
obj.public_method('my_method_name').call('some_argument_1', 'some_argument_2')