如何在尊重隐私的同时动态调用方法

时间:2009-11-26 14:33:22

标签: ruby reflection visibility

使用动态方法调用(#send#method)会忽略方法的可见性 有没有一种简单的方法可以动态调用一个调用私有方法失败的方法?

6 个答案:

答案 0 :(得分:12)

据我所知 - 你需要方法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

答案 1 :(得分:6)

使用public_send代替send

my_object.public_send :method, *args

这是Ruby 1.9的新功能,因此对于较旧的Ruby,您可以require 'backports/1.9.1/kernel/public_send'

答案 2 :(得分:3)

如果您使用的是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

答案 3 :(得分:0)

以为我不明白你为什么要这样做,你可以使用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

答案 4 :(得分:0)

确实如此,eval确实是我认为在1.9之前实际做到这一点的唯一方法。如果你想了解更多关于可见性的信息,Jamis Buck写了一篇awesome article关于可见性在Ruby中实际意味着什么的方法。

与Ruby中的其他内容非常相似,与其他语言略有不同。

答案 5 :(得分:0)

如果您想避开evalsendpublic_send,或者想要better performance,请使用public_method method

obj.public_method('my_method_name').call

您可以添加如下参数:

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