有没有办法判断 `method_missing` 是否被显式调用?

Is there a way to tell if `method_missing` was explicitly called?

从方法定义中,有没有办法判断方法 method_missing 是被显式调用还是作为挂钩方法被调用?

使用方法 initialize,可以通过执行以下操作来判断它是被显式调用还是作为钩子调用:

class A
  def initialize
    puts caller
  end
end

当作为钩子调用时,方法 initialize 有一行 new:

a = A.new
# => ...:in `new'
# => ...
# => ...:in `<main>'

显式调用时,没有这样一行(除非从new显式调用):

a.send(:initialize)
# => ...
# => ...:in `<main>'

但是当我用method_missing做类似的事情时,我无法区分这两种情况:

class A
  def method_missing *;
    puts caller
  end
end

a.foo
# => ...
# => ...:in `<main>'

a.method_missing
# => ...
# => ...:in `<main>'

initialize 不同,is invoked explicitly via the Class#new, the BasicObject#method_missing 由 Ruby 解释器调用:

Invoked by Ruby when obj is sent a message it cannot handle. symbol is the symbol for the method called, and args are any arguments that were passed to it. By default, the interpreter raises an error when this method is called. However, it is possible to override the method to provide more dynamic behavior.

Kernel#caller 将不包括执行堆栈跟踪中的那些位置,从那里 Ruby 解释器调用 method_missing 如果那是你正在寻找的。

您可以检查第一个参数:

class A
  def method_missing(name = nil, *)
    if name
      puts "called via `#{name}'"
    else
      puts "called directly"
    end
  end
end

A.new.foo
#=> called via `foo'

A.new.method_missing
#=> called directly