Rubyのinclude,prepend,extend
#ruby
概要
Rubyのオブジェクト指向は「クラス継承」ではなく「メソッド探索チェーン(ancestors)」を中心に理解するのが本質。prepend / include / extend はいずれも、このチェーンに対してモジュールをどこに差し込むかを制御する仕組みであり、それ以上でも以下でもない
table:まとめ
操作 対象チェーン 差し込む位置
include インスタンスのチェーン クラスの直上に差し込む
prepend インスタンスのチェーン クラスの直下に差し込む
extend 特異クラスのチェーン レシーバの特異クラスの直上に差し込む
使い分け
機能を付与するならinclude
既存メソッドを侵襲せずラップするならprepend
特定オブジェクトやクラス自身に機能を生やすならextend
code:ruby
module M
def hello = "M#hello"
end
class A
include M
def hello = "A#hello"
end
class B
prepend M
def hello = "B#hello"
end
A.ancestors # => A, M, Object, Kernel, BasicObject
B.ancestors # => M, B, Object, Kernel, BasicObject
A.new.hello # => "A#hello" # AがMより先にヒット
B.new.hello # => "M#hello" # MがBより先にヒット
include / prepend
code:ruby
module M
def hello = "M#hello"
end
obj = Object.new
obj.extend(M)
obj.hello # => "M#hello"
# ↑ これは下と等価
class << obj
include M
end
extend