how to dynamically call a method while respecting privacy
Using d开发者_如何学Goynamic method calls (#send
or #method
) the methods' visibility is ignored.
As I know - you need method 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
Use public_send
instead of send
:
my_object.public_send :method, *args
It's new to Ruby 1.9, so for older Ruby, you can require 'backports/1.9.1/kernel/public_send'
.
If you are using ruby-1.9, you can use Object#public_send
which does what you want.
If you use ruby-1.8.7 or earlier you have to write your own 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
Or you could write your own Object#public_method
which behaves like Object#method
but only for public methods
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
Thought I don't understand why you want to do so, you can use 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
It's true though, eval really is I think the only way to actually do it pre-1.9. If you want to read more about visibility Jamis Buck wrote an awesome article about what method visibility actually means in Ruby.
Much like other things in Ruby visibility is ever so slightly different than other languages.
If you want to avoid eval
, send
or public_send
, or you want better performance, use the public_method
method:
obj.public_method('my_method_name').call
You can add arguments like this:
obj.public_method('my_method_name').call('some_argument_1', 'some_argument_2')
精彩评论