訊息傳遞繼承鏈

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