直接访问受保护方法和使用send之间的区别

时间:2012-09-19 12:57:40

标签: ruby class

为什么以下代码中的两种调用方法之间存在差异:

class Access
    def method_missing name
        print "Method is missing"
    end

    protected
    def protected_method
        print "Calling Protected Method"
    end
end

access = Access.new
access.protected_method #Method is missing
access.send(:protected_method) #Calling Protected Method

access.protected_method按预期工作。但是send选项尝试调用该方法,即使它受到保护。我想知道内部发生了什么。

我得到一个要调用的方法的字符串,所以我想使用send,但我不想调用受保护的方法。

4 个答案:

答案 0 :(得分:6)

这就是send的工作原理。如果您只想调用公共方法,请使用public_send

答案 1 :(得分:1)

使用send可以绕过某些规则,例如访问对象的受保护或私有方法。

另一件事是send允许您动态调用方法。使用send将决定在程序运行之前不知道调用哪些方法,即可以决定在运行时将哪些消息传递给它。

除此之外,据我所知,他们是一样的。

答案 2 :(得分:0)

嗯,这就是send的工作方式。它允许您调用方法,无论其可见性如何。 如果您发送的是不存在的名称,则method_missing会启动。请参阅:

class Access
    def method_missing name
        "Method is missing"
    end

    protected
    def protected_method
        "Calling Protected Method"
    end
end

access = Access.new
access.protected_method # => "Method is missing"
access.send(:protected_method) # => "Calling Protected Method"
access.send(:non_existing_method) # => "Method is missing"

如果您不希望以这种方式调用受保护的方法,那么,我想,对于可怕的eval来说,这是一个很好的用例。

eval "Access.new.protected_method" # => "Method is missing"
eval "Access.new.non_existing_method" # => "Method is missing"

答案 3 :(得分:-1)

send的一个用途是绕过可见性,所以这是一个功能,而不是一个bug,事实上,如果你不允许,你可能会打破使用你的类的其他程序员的期望这种行为。

也就是说,如果您真的需要它,可以覆盖类中的sendmethod_missing来实现您想要的行为:

class Access
  def foo; puts "foo"; end

  def method_missing(message, *args)
    puts "Method #{message} missing"
  end

  def send(message, *args)
    if self.class.protected_instance_methods.include?(message)
      method_missing(message, *args)
    else
      super
    end
  end

protected

  def bar; puts "bar"; end
end

a = Access.new
a.foo            #=> 'foo'
a.bar            #=> 'Method bar missing'
a.send('bar')    #=> 'Method bar missing'