今回はパーフェクト Ruby で「Ruby のメソッド探索」について学んだのでそのメモです。
オブジェクトに対してメソッド呼び出しが行われる際、どのようにメソッドが呼び出されているのか、書いてみたいと思います。
自身のメソッドを呼び出した時
class BaseClass def hello :hello end end base_object = BaseClass.new base_object.hello #=> :hello
これは最も単純なケース。
自身のクラスのhello
メソッドを探しにいって、あれば実行します。
親クラスのメソッドを呼び出した時
class InheritClass < BaseClass end inherit_object = InheritClass.new inherit_object.hello #=> :hello
この場合、まず Ruby のインタプリタはinherit_object
のクラスInheritClass
を参照しますが、ここにhello
メソッドはありません。なので、次にその親クラスであるBaseClass
を探しにいってそこで見つかったhello
メソッドを呼び出します。
特異メソッドを呼び出した時
def base_object.hello :singleton_method_hello end base_object.hello #=> :singleton_method_hello
base_object
の特異メソッドにhello
を定義した場合。これはbase_object
の特異クラスのメソッドなので上図のような関係になります。
特異クラスはオブジェクトのクラスよりも先にメソッド探索されるようになっています。よって今回の場合、インタプリタはまずbase_object
の特異クラスを参照し、そこにあるhello
メソッドを呼び出します。
ちなみにbase_object
の特異クラスにはbase_object.singleton_class
でアクセス可能(特異クラスはそれを定義したり、確認しようとしたタイミングで作成される)です。
クラスに include したモジュールのメソッドを呼び出した時
module HelloModule def hello_from_module :hello_from_module end end class InheritClass include HelloModule end inherit_object = InheritClass.new inherit_object.hello_from_module #=> :hello_from_module
モジュールをクラスにinclude
した場合、そのモジュールの機能を取り込んだクラスが自身と親クラスの間に挿入されます。そして自分、モジュールの機能を取り込んだクラス、親クラスの順に探索します。
今回の場合はモジュールの機能を取り込んだクラス内でhello_from_module
を発見し、それを呼び出しています。
ちなみに複数のモジュールをinclude
した場合は後からinclude
したモジュールが前に挿し込まれる感じになります。
クラスに extend したモジュールのメソッドを呼び出した時
module HelloModule def hello_from_module :hello_from_module end end class InheritClass extend HelloModule end inherit_object = InheritClass.new inherit_object.hello_from_module #=> NoMethodError: undefined method ... InheritClass.hello_from_module #=> :hello_from_module
モジュールをクラスにextend
した場合、レシーバ(今回はInheritClass
)の特異クラスに対してextend
したモジュールがinclude
されます。
よって上図のような関係になり、モジュールで定義しているメソッドがInheritClass
のクラスメソッドとして使えるようになります。inherit_object
のメソッド探索は直線部なので、破線部にあるhello_from_module
は見つかりません。
存在しないメソッドを呼び出した時
method_missing
メソッドが定義されているクラスを探し続けます。
それが見つからない場合は最終的にBaseObject#method_missing
を呼び出し、NoMethodError
が発生します。
まとめ
特異メソッド、特異クラス、mixin など何気なく使っているものの動作を図で整理できてよかったです。 なにか間違えていたらご指摘いただけると幸いです。
今回も参考にしたのはこちら。