Using dynamic method calls (#send or #method) the methods visibility is ignored.
is there a simple way to dynamically call a method that will fail calling a private method?
views:
103answers:
5Thought 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
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
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
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.
require 'backports' # Needed for Ruby < 1.9
my_object.public_send :method, *args
My backports gem defines all of Ruby 1.8.7 and many Ruby 1.9 methods, including public_send, which is what you want to use here.