消息传递继承链

class Example
  def example_method
    :example
  end

  def subexample_method
    :example
  end

  def not_missed_method
    :example
  end

  def method_missing name
    return :example if name == :missing_example_method
    return :example if name == :missing_subexample_method
    return :subexample if name == :not_missed_method
    super
  end
end

class SubExample < Example
  def subexample_method
    :subexample
  end

  def method_missing name
    return :subexample if name == :missing_subexample_method
    return :subexample if name == :not_missed_method
    super
  end
end

s = Subexample.new

要找到适合 SubExample#subexample_method Ruby 的方法,首先要看一下 SubExample 的祖先链

SubExample.ancestors # => [SubExample, Example, Object, Kernel, BasicObject]

它从 SubExample 开始。如果我们发送 subexample_method 消息,Ruby 选择一个可用的 SubExample 并忽略 Example#subexample_method

s.subexample_method # => :subexample

SubExample 之后它会检查 Example。如果我们发送 example_method Ruby 检查 SubExample 是否可以回复它,因为它不能 Ruby 上链并查看 Example

s.example_method # => :example

在 Ruby 检查所有定义的方法之后,它运行 method_missing 以查看它是否可以回复。如果我们发送 missing_subexample_method Ruby 将无法在 SubExample 上找到一个已定义的方法,所以它会移动到 Example。它无法在 Example 或任何其他类别的链上找到定义的方法。Ruby 重新启动并运行 method_missingSubExamplemethod_missing 可以回复 missing_subexample_method

s.missing_subexample_method # => :subexample

但是,如果定义了一个方法,Ruby 就会使用已定义的版本,即使它在链中更高。例如,如果我们发送 not_missed_method,即使 SubExamplemethod_missing 可以回复它,Ruby 也会在 SubExample 上走路,因为它没有一个带有该名称的已定义方法,并且会查看有一个的 Example

s.not_missed_method # => :example