How to dynamically invoke a method while maintaining confidentiality

Using calls to dynamic methods ( #send or #method ), the visibility of methods is ignored.
Is there a simple way to dynamically invoke a method that won't invoke a private method call?

+6
visibility reflection ruby
source share
6 answers

As I know - you need a public_send method:

 ----------------------------------------------------- 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 
+12
source share

Use public_send instead of send :

 my_object.public_send :method, *args 

This is new for Ruby 1.9, so for older Ruby you can require 'backports/1.9.1/kernel/public_send' .

+6
source share

If you are using ruby-1.9, you can use Object#public_send , which does what you want.

If you are using ruby-1.8.7 or earlier, you need 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 can write your own Object#public_method , which behaves like an 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 
+3
source share

I think I do not understand why you want to do this, 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 
0
source share

This is true, although, in fact, I believe that the only way to do this is before 1.9. If you want to know more about visibility, Jamis Buck has written an amazing article on what method visibility actually means in Ruby.

Like other things in Ruby's visibility, it is slightly different from other languages.

0
source share

If you want to avoid eval , send or public_send or want to improve performance , use the public_method method :

obj.public_method('my_method_name').call

You can add the following arguments:

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

0
source share

All Articles