Module#include
クラスAがモジュールMをincludeすると、メソッドの探索順は A → M → …
のようになる。
つまり、モジュールMはクラスAの親クラス側に差し込まれる。
module M def hello puts "M hello" end end class A include M def hello super puts "A hello" end end A.new.hello # => M hello # => A hello p A.ancestors # 自身と親クラスの配列を返す # => [A, M, Object, Kernel, BasicObject]
Module#prepend
Module#prependはクラスの子側(?)にモジュールを差し込む。
したがって、モジュールのメソッドで、インスタンスのメソッドをラッピングできる。
module M def hello puts "before" super puts "after" end end class A prepend M def hello puts "hello" end end A.new.hello # => before # => hello # => after p A.ancestors # 自身と親クラスの配列を返す # => [M, A, Object, Kernel, BasicObject]
差し込まれる順番は自然。
Module#include
はクラスのすぐ後ろ(親側)に追加していく。
Module#prepend
は先頭(子側)に追加していく。
module M1; end module M2; end class A include M1 # A -> M1 include M2 # A -> M2 -> M1 (Aのすぐ後ろに追加していく) end class B prepend M1 # M1 -> B prepend M2 # M2 -> M1 -> B (先頭に追加していく) end p A.ancestors # 自身と親クラスの配列を返す # => [A, M2, M1, Object, Kernel, BasicObject] p B.ancestors # 自身と親クラスの配列を返す # => [M2, M1, B, Object, Kernel, BasicObject]
Module#include
はメソッドの前に何かを実行するってことができなかったけど、Module#prepend
ではそれができる。
メソッドの前後に処理を(自然に?)追加できるので便利ですね!