Module#prepend

Module.prepend の意義を頻繁に見失って混乱するので以下の資料を読んで得た理解を纏める。間違っていたら指摘頂けると有り難い。

参照: https://speakerdeck.com/a_matsuda/ruby-2-dot-0-on-rails

元々 alias_method_chain は alias を活用した、メソッドそのものを後付けで拡張するためのメソッドだった。

class A でmodule B を include して、*module B が* class A のメソッドを拡張する形式で多用される。コアの部分のみをクラス側に書いて、module がそれを拡張していくという形式だ。

@waycats はalias_method_chain の複雑さを排除していくために、これを include を多用したスタイルで解決を図ろうとした。メソッドを後から拡張というスタイルは、例えばクラスの再オープンではメソッド自体が上書きされてしまうため、alias_method_chain を使うしか無かった。module 側がクラスのメソッドを拡張するにしても同じく alias_method_chain を使うしか無い。@waycats が行ったのは include で代用したことだが非常に判りづらい。結果として拡張される、というものであってコードを読むにあたり追いかけづらいという問題がある。このあたりは命名規則で解決できそうなものだかけれど、それは余りスマートなやり方には見えず、泥臭い(@waycats が悪いんじゃない)

メソッドの拡張は元々module やclass の継承関係によって行われていた。下位に属する class, module が上位の class, module のメソッドを拡張する形だ。問題は”上位の”という所であって、”同位の”メソッドを拡張できない事にある。

ここで prepend の登場になる。include が継承関係の上位に module を差し込んでいたのに対して prepend は下位に差し込む。こうすることによって対象のメソッドを呼んだ時に最初に prepend されたモジュールのメソッドが先ず呼ばれ、次に prepend を記述した class, module のメソッドが呼ばれる事になる。prepend を記述したクラスの同位にあるメソッドを拡張したことになるわけだ。