Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to dynamically call a method while respecting privacy

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?

like image 853
Emirikol Avatar asked Nov 26 '09 14:11

Emirikol


3 Answers

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
like image 83
andrykonchin Avatar answered Sep 28 '22 06:09

andrykonchin


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'.

like image 32
Marc-André Lafortune Avatar answered Sep 28 '22 06:09

Marc-André Lafortune


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
like image 43
johannes Avatar answered Sep 28 '22 06:09

johannes