Module#prependで何が出来るようになったのか
私事ですが先日実家の香川県に帰ったところ、うどん屋と田んぼしかない不毛地帯であったのに、いつの間にかセブンイレブンが出店していることに感動しました。具体的な例を使うと記憶しやすいのではないかと考え、これを今回の題材に使ってみることにします。
まずはincludeを使った場合の例です。
SevenElevenモジュールとKagawaクラスにそれぞれ同名のメソッドdrink
が定義されています。Kagawa内でSevenElevenをincludeしたのちKagawa#drink
を呼び出してみると、includeしたSevenElevenのものではなく、Kagawaクラスのdrinkが呼び出されます。
この理由は、Kagawa.ancestors
メソッドを実行することで理解できます。
Object, Kernel, BasicObjectはどんなRubyのクラスにも入ってくる基礎的なクラスです。左が子孫、右が先祖という方向で順に並んでいます。Kagawa#drink
が呼び出されたとき、Rubyは左(子孫)から順にさかのぼってメソッドを探します。先の例ではKagawaクラスのdrinkメソッドがヒットしたのでそこでメソッド探索を打ち切ったのでした。
ここでprependを使うと、メソッド探索においてモジュールのメソッドを先にヒットさせることができます。includeをprependに書き換えると次のようになります。
SevenElevenが先にメソッド探索チェインに現れ、Kagawa2#drink
の結果はSevenElevenモジュールで定義したdrinkとなります。
もちろん、子孫側のメソッド中でsuperを使えば、先祖側の同名メソッドを呼び出せます。
superを呼び出す場所に注意してください。
- include
- superを使うのは子孫側 = include「する」側(例ではKagawa3)
- prepend
- superを使うのは子孫側 = prepend「される」側(例ではSevenEleven2)
次のページでは実例として、Railsでよく使われるalias_method_chain
をprependで書き換えてみます。