LoginSignup
3
3

More than 5 years have passed since last update.

includeとextendのおさらい

Last updated at Posted at 2015-10-13

どう違うのかいまいち分からなかったので、触りながら確認していきます。

サンプル
module Piyo
  def piyo_piyo
  end
end

class Foo
end

class Bar <Foo
end

class Hoge < Bar
end

↓を見ながらいじっていきます。

hoge = Hoge.new

p "Hoge.ancestors => #{Hoge.ancestors}"

p "Foo.respond_to?(:piyo_piyo) => #{Foo.respond_to?(:piyo_piyo)}"

p "Bar.respond_to?(:piyo_piyo) => #{Bar.respond_to?(:piyo_piyo)}"

p "Hoge.respond_to?(:piyo_piyo) => #{Hoge.respond_to?(:piyo_piyo)}"

p "hoge.respond_to? => #{hoge.respond_to?(:piyo_piyo)}"
実行結果
"Hoge.ancestors => [Hoge, Bar, Foo, Object, Kernel, BasicObject]"
"Foo.respond_to?(:piyo_piyo) => false"
"Bar.respond_to?(:piyo_piyo) => false"
"Hoge.respond_to?(:piyo_piyo) => false"
"hoge.respond_to?(:piyo_piyo) => false"

各クラスと一番継承先のHogeクラスのインスタンスhogeにincludeとextendでどう変化するのか見ていきます。

FooにPiyoをinclude
module Piyo
  def piyo_piyo
  end
end

class Foo
  include(Piyo)
end

class Bar <Foo
end

class Hoge < Bar
end

hoge = Hoge.new

p "Hoge.ancestors => #{Hoge.ancestors}"

p "Foo.respond_to?(:piyo_piyo) => #{Foo.respond_to?(:piyo_piyo)}"

p "Bar.respond_to?(:piyo_piyo) => #{Bar.respond_to?(:piyo_piyo)}"

p "Hoge.respond_to?(:piyo_piyo) => #{Hoge.respond_to?(:piyo_piyo)}"

p "hoge.respond_to? => #{hoge.respond_to?(:piyo_piyo)}"
実行結果
"Hoge.ancestors => [Hoge, Bar, Foo, Piyo, Object, Kernel, BasicObject]"
"Foo.respond_to?(:piyo_piyo) => false"
"Bar.respond_to?(:piyo_piyo) => false"
"Hoge.respond_to?(:piyo_piyo) => false"
"hoge.respond_to?(:piyo_piyo) => true"

ancestorsにPiyoが追加されて、Hogeクラスのインスタンスhogeでmoduleのメソッドが使えるようになりました。
includeを差し込んだクラスの一つ上にmoduleが階層に追加されるようです。
extendを見てみます。

FooにPiyoをextend
module Piyo
  def piyo_piyo
  end
end

class Foo
  extend(Piyo)
end

class Bar <Foo
end

class Hoge < Bar
end

hoge = Hoge.new

p "Hoge.ancestors => #{Hoge.ancestors}"

p "Foo.respond_to?(:piyo_piyo) => #{Foo.respond_to?(:piyo_piyo)}"

p "Bar.respond_to?(:piyo_piyo) => #{Bar.respond_to?(:piyo_piyo)}"

p "Hoge.respond_to?(:piyo_piyo) => #{Hoge.respond_to?(:piyo_piyo)}"

p "hoge.respond_to?(:piyo_piyo) => #{hoge.respond_to?(:piyo_piyo)}"
実行結果
"Hoge.ancestors => [Hoge, Bar, Foo, Object, Kernel, BasicObject]"
"Foo.respond_to?(:piyo_piyo) => true"
"Bar.respond_to?(:piyo_piyo) => true"
"Hoge.respond_to?(:piyo_piyo) => true"
"hoge.respond_to?(:piyo_piyo) => false"

ancestorsにPiyoが表示されなくなりました。Hogeクラスのインスタンスhogeもmoduleのメソッドを使えなくなったようです。
ここがよくわからなかったのですが、「extendはあるオブジェクトに特異メソッドを付与する」ものみたいです。
特異クラスはクラスメソッドの様なもので継承はする。クラスメソッドの様なものなので、インスタンスには影響しない。(クラスの中でextendするとクラスメソッドの様に振る舞う?)
という理解で大丈夫なら表示結果と矛盾もないので納得できます。
extend (Object)
特異メソッド定義
instance method Module#include

インスタンスhogeにextend
module Piyo
  def piyo_piyo
  end
end

class Foo
end

class Bar <Foo
end

class Hoge < Bar
end

hoge = Hoge.new

p "Hoge.ancestors => #{Hoge.ancestors}"

p "Foo.respond_to?(:piyo_piyo) => #{Foo.respond_to?(:piyo_piyo)}"

p "Bar.respond_to?(:piyo_piyo) => #{Bar.respond_to?(:piyo_piyo)}"

p "Hoge.respond_to?(:piyo_piyo) => #{Hoge.respond_to?(:piyo_piyo)}"

p "hoge.respond_to?(:piyo_piyo) => #{hoge.respond_to?(:piyo_piyo)}"

hoge.extend(Piyo)

p "hoge.respond_to?(:piyo_piyo) => #{hoge.respond_to?(:piyo_piyo)}"
実行結果
"Hoge.ancestors => [Hoge, Bar, Foo, Object, Kernel, BasicObject]"
"Foo.respond_to?(:piyo_piyo) => false"
"Bar.respond_to?(:piyo_piyo) => false"
"Hoge.respond_to?(:piyo_piyo) => false"
"hoge.respond_to?(:piyo_piyo) => false"
↓extendしたインスタンスだけ使える
"hoge.respond_to?(:piyo_piyo) => true"

extendは対象がオブジェクトなので、インスタンスに直接使える様です。
extendする場所によって、クラスメソッドの様にもインスタンスメソッドの様にもなるところがややこしいです。
includeでも以下で同様にできるようです。

インスタンスhogeにinclude
class << hoge
  include(Piyo)
end
3
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3