extendとincludeの違いについて

ruby2.0

moduleを取り込むのにinculudeとextendがあって
あ・れ・はなんなんじゃ なんじゃ なんじゃにん(ry となったので調べてみた。

違いは継承ツリーのどこに差し込まれるかという話っぽい。
includeは(includeした)元のクラスの上に差し込まれる。
extendは(extendした)元のオブジェクトの特異クラスの上に差し込まれる。

それとincludeとextendは並べがちだけど定義されてる場所が違う。

[1] pry(main)> String.method(:extend)
=> #<Method: Class(Kernel)#extend>
[2] pry(main)> String.method(:include)
=> #<Method: Class(Module)#include>

include

module IncludeModule
  def unko
    :unko
  end
end

class Foo
  include IncludeModule
end

Foo.ancestors   # [Foo, IncludeModule, Object, Kernel, BasicObject]

Fooクラスの上にIncludeModuleで現れていて親クラスっぽい感じで使えるようになる。

extend

extendでmoduleを取り込むと特異クラスの継承ツリーに現れる。
また、取り込み先の上に差し込まれる。

module ExtendModule
  def hello
    :hello_hoge
  end
end

class Foo
  extend ExtendModule
end

p Foo.singleton_class.ancestors   #  [ExtendModule, Class, Module, Object, Kernel, BasicObject]
p Foo.hello   #  :hello_hoge
# ancestorsメソッドで特異クラス自身が見えないのはruby2.0以前の仕様らしく、2.1から表示されるようになるとのこと。

特異クラスの上に挿されるのでクラスメソッドととして呼べている。
また、extendは特異クラスに取り込まれるということでインスタンスに対しても使える。

p foo = Foo.new
foo.extend(ExtendModule)
foo.hello   #  :hello_hoge

まとめ

全然違う