как динамически вызывать метод при соблюдении конфиденциальности - PullRequest
6 голосов
/ 26 ноября 2009

При использовании динамических вызовов методов (#send или #method) видимость методов игнорируется.
Есть ли простой способ динамического вызова метода, который не сможет вызвать закрытый метод?

Ответы [ 6 ]

12 голосов
/ 26 ноября 2009

Как я знаю - вам нужен метод 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
6 голосов
/ 28 ноября 2009

Используйте public_send вместо send:

my_object.public_send :method, *args

Это новинка для Ruby 1.9, поэтому для более старых Ruby вы можете require 'backports/1.9.1/kernel/public_send'.

3 голосов
/ 26 ноября 2009

Если вы используете 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
0 голосов
/ 09 октября 2014

Если вы хотите избежать eval, send или public_send или хотите лучшую производительность , используйте метод public_method :

obj.public_method('my_method_name').call

Вы можете добавить следующие аргументы:

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

0 голосов
/ 27 ноября 2009

Правда, eval на самом деле, я думаю, единственный способ сделать это до 1.9. Если вы хотите узнать больше о видимости, Джамис Бак написал потрясающую статью о том, что на самом деле означает видимость в Ruby.

Так же, как и другие вещи в Ruby, видимость немного отличается от других языков.

0 голосов
/ 26 ноября 2009

Хотя я не понимаю, почему вы хотите это сделать, вы можете использовать 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...