サーチ…


前書き

オブジェクト指向設計では 、オブジェクトメッセージを受信し、メッセージに応答します。 Rubyでは、メッセージの送信はメソッドの呼び出しであり、そのメソッドの結果は応答です。

Rubyでは、メッセージの受け渡しは動的です。メッセージがどのように返信するかを正確に知るのではなく、メッセージが到着したとき、Rubyは事前定義されたルールセットを使用して返信できるメソッドを見つけます。これらのルールを使用して、メッセージに割り込んだり応答したり、別のオブジェクトに送信したり、他のアクションの中で変更したりすることができます。

オブジェクトがメッセージを受け取るたびに、Rubyは以下をチェックします:

  1. このオブジェクトにシングルトンクラスがあり、このメッセージに返信できる場合。
  2. このオブジェクトのクラスを調べ、クラスの先祖のチェーンを探します。
  3. この祖先でメソッドが使用可能であるかどうかを1つずつチェックし、チェーンを上に移動します。

継承チェーンを通るメッセージ

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

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

SubExampleからSubExampleます。 subexample_methodメッセージを送信すると、Rubyは利用可能な1つのSubExampleを選択し、 Example#subexample_methodを無視します。

s.subexample_method # => :subexample

SubExampleそれはチェックExample 。私たちは送ればexample_method RubyがあればチェックしSubExampleそれに返信したりすることはできませんし、それが可能であるためではないRubyはチェーンを上がると覗くExample

s.example_method # => :example

Rubyが定義されたすべてのメソッドをチェックした後、それが応答できるかどうかをmethod_missingためにmethod_missingを実行します。私たちは送ればmissing_subexample_method Rubyは上で定義された方法を見つけることができませんSubExampleそれが上に移動してExampleExampleやチェーン上の他のクラスでも定義されたメソッドを見つけることはできません。 Rubyはやり直して、 method_missingを実行しmethod_missingmethod_missingSubExampleに返信できmissing_subexample_method

s.missing_subexample_method # => :subexample

しかし、メソッドが定義されている場合、たとえそれがチェーン内で上位であっても、Rubyは定義されたバージョンを使用します。私たちが送信した場合たとえば、 not_missed_methodにもかかわらず、 method_missingSubExampleそれに答えることができRubyが上に歩くSubExampleそれはその名前の定義されたメソッドを持っていないためとに見えるExample 1を有しています。

s.not_missed_method # => :example

モジュール構成を通過するメッセージ

Rubyはオブジェクトの祖先チェーン上に移動します。このチェーンは、モジュールとクラスの両方を含むことができます。チェーンを上に移動することについても同じ規則がモジュールに適用されます。

class Example
end

module Prepended
  def initialize *args
    return super :default if args.empty?
    super
  end
end

module FirstIncluded
  def foo
    :first
  end
end

module SecondIncluded
  def foo
    :second
  end
end

class SubExample < Example
  prepend Prepended
  include FirstIncluded
  include SecondIncluded

  def initialize data = :subexample
    puts data
  end
end

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

s = SubExample.new # => :default
s.foo # => :second

メッセージを中断する

メッセージを中断する方法は2つあります。

  • 定義されていないメッセージには、 method_missingを使用します。
  • チェーンの途中でメッセージを傍受するメソッドを定義する

メッセージを中断した後、次のことが可能です。

  • 彼らに返信してください。
  • それらを別の場所に送る。
  • メッセージまたはその結果を変更します。

method_missing経由で中断し、メッセージに返信する:

class Example
  def foo
    @foo
  end

  def method_missing name, data
    return super unless name.to_s =~ /=$/
    name = name.to_s.sub(/=$/, "")
    instance_variable_set "@#{name}", data
  end
end

e = Example.new

e.foo = :foo
e.foo # => :foo

メッセージを傍受して変更する:

class Example
  def initialize title, body
  end
end

class SubExample < Example
end

さて、私たちのデータが "title:body"であり、 Example呼び出す前にそれらのデータを分割しなければならないとしましょう。 SubExample initializeを定義することができます。

class SubExample < Example
  def initialize raw_data
    processed_data = raw_data.split ":"

    super processed_data[0], processed_data[1]
  end
end

メッセージをインターセプトして別のオブジェクトに送信する:

class ObscureLogicProcessor
  def process data
    :ok
  end
end

class NormalLogicProcessor
  def process data
    :not_ok
  end
end

class WrapperProcessor < NormalLogicProcessor
  def process data
    return ObscureLogicProcessor.new.process data if data.obscure?

    super
  end
end


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow