Module#includeとは

Module#includeとは
Module#includeとは、Rubyの組み込みライブラリに含まれるModuleクラスのインスタンスメソッド
引数で指定したモジュールの定義 (メソッド、定数) を引き継ぐことができる
多重継承の代わりに用いられておりmix-inとも呼ばれている
モジュールの機能追加は、クラスの継承関係の間にそのモジュールが挿入されることで実現されている
そのため、メソッド探索などはスーパークラスよりもインクルードされたモジュールのほうが先に行われる
module M
def hoge
puts "M#hoge"
end
end
class C1; end
class C2 < C1
include M
end
# 指定されたモジュールの定義 (メソッド、定数) を引き継ぐことができる
C2.new.hoge
# => M#hoge
# モジュールの機能追加は、クラスの継承関係の間にそのモジュールが挿入されることで実現されている
p C2.ancestors
# => [C2, M, C1, Object, Kernel, BasicObject]
module M
def hoge
puts "M#hoge"
end
end
class C1
def hoge
puts "C1#hoge"
end
end
class C2 < C1
include M
end
# メソッド探索などはスーパークラスよりもインクルードされたモジュールのほうが先に行われる
C2.new.hoge
# => M#hoge
引数について
引数は可変長引数なので配列として受け取られるため複数モジュール指定可能
include(*mod) -> self
引数に複数のモジュールを指定した場合、最後の引数から順にインクルードする
同じモジュールを二回以上includeした場合、二回目以降は無視される
class C2 < C1
include M1, M2
end
p C2.ancestors
# => [C2, M1, M2, C1, Object, Kernel, BasicObject]
Module#includeの実態
Module#includeの実態はModuleクラスのappend_featuresインスタンスメソッド
includeメソッドはRubyで書くと以下のように定義できる
Module#append_features → モジュール(またはクラス)に self の機能を追加する
Module#included → self が include されたときに対象のクラスまたはモジュールを引数にしてインタプリタがこのメソッドを呼び出す(フックメソッド)
def include(*modules)
modules.reverse_each do |mod|
# append_featuresやincluded はプライベートメソッドなので
# 直接 mod.append_features(self) とは書けない
mod.__send__(:append_features, self)
mod.__send__(:included, self)
end
end
参考:https://docs.ruby-lang.org/ja/latest/method/Module/i/append_features.html
Module#includedメソッドはフックメソッドのため通常はメソッドの中身はなく、オーバーライドして使うもの
一方で、Module#append_featuresはメソッドは、実際に継承チェーンにモジュールを追加する