Module#prependとは
- Module#prependとは、Rubyの組み込みライブラリに含まれるModuleクラスのインスタンスメソッド
- 引数で指定したモジュールを self の継承チェーンの先頭に追加することで self の定義 (メソッド、定数) を上書きする
- prependの引数として渡したモジュールのインスタンスメソッドでsuperを呼ぶことで self のモジュール/クラスのメソッドを呼び出すことができる
- 引数で指定したモジュールは後ろから順に処理されるため、 modules の先頭が最も優先される
module M1 def foo puts "M1#foo(1)" super puts "M1#foo(2)" end end class C1 prepend M1 def foo puts "C1#foo" end end # prependの引数として渡したモジュールのインスタンスメソッドでsuperを呼ぶことで self のモジュール/クラスのメソッドを呼び出すことができる C1.new.foo # => M1#foo(1) # C1#foo # M1#foo(2)
module M2 def foo puts "M2#foo(1)" super puts "M2#foo(2)" end end class C2 prepend M1, M2 def foo puts "C2#foo" end end # 引数で指定したモジュールは後ろから順に処理されるため、 modules の先頭が最も優先される C2.new.foo # => M1#foo(1) # M2#foo(1) # C2#foo # M1#foo(2) # M2#foo(2)
引数について
- 引数は可変長引数なので配列として受け取られるため複数モジュール指定可能
prepend(*modules) -> self
- 引数に複数のモジュールを指定した場合、最後の引数から順に prepend する
Module#prependの実態
- Module#prependの実態はModuleクラスのprepend_featuresインスタンスメソッド
- prependメソッドはRubyで書くと以下のように定義できる
- Module#prepend_features → 引数で指定したモジュール(またはクラス)の継承チェーンの先頭に self を追加する
- Module#prepend → self が prepend されたときに対象のクラスまたはモジュールを引数にしてインタプリタがこのメソッドを呼び出す(フックメソッド)
def include(*modules) modules.reverse_each do |mod| # prepend_featuresやprepend はプライベートメソッドなので # 直接 mod.prepend_features(self) とは書けない mod.__send__(:prepend_features, self) mod.__send__(:prepended, self) end end
参考:https://docs.ruby-lang.org/ja/latest/method/Module/i/prepend_features.html
- Module#prependedメソッドはフックメソッドのため通常はメソッドの中身はなく、オーバーライドして使うもの
- 一方で、Module#prepend_featuresはメソッドは、実際に継承チェーンの先頭にモジュールを追加する