昨日は時間を捻出できなくてブログを書けなかった!継続日数は13日でストップ!まぁ継続日数を目標にしてるわけではないし,引き続き学びがあったら少しでもアウトプットできるように頑張ろうと思う.
Module#prepend
引き続き Ruby Gold の対策をしていて,前回同様に Ruby 2.1 で追加された機能がテーマ.今回は Module#prepend
を調べた.
Ruby Association の資料に載ってるコードをベースに少しずつ紐解いていく.
module M def foo puts "M#foo" end end class C prepend M def foo puts "C#foo" end end C.new.foo # >> M#foo
include の場合
include
でモジュールを Min-in する場合で,さらにメソッド名が同じ場合,継承チェーン的にクラスが優先されるので,クラス C のメソッドが呼び出される.
module M def foo puts "M#foo" end end class C include M def foo puts "C#foo" end end C.new.foo p C.ancestors # >> C#foo # >> [C, M, Object, Kernel, BasicObject]
参考として,クラス S を継承してから継承チェーンを見てみる.特に変わらず,クラス C のメソッドが呼び出される.継承したクラスよりモジュールの方が優先度が高いことがわかる.
module M def foo puts "M#foo" end end class S def foo puts "S#foo" end end class C < S include M def foo puts "C#foo" end end C.new.foo p C.ancestors # >> C#foo # >> [C, M, S, Object, Kernel, BasicObject]
prepend
そこで今回の prepend
を使って Mix-in するとどうなるかと言うと,その言葉通り,クラスより先に読み込まれるようになって,継承チェーンが変わってくる.
結果として,モジュール M のメソッドが呼び出される.
module M def foo puts "M#foo" end end class C prepend M def foo puts "C#foo" end end C.new.foo p C.ancestors # >> M#foo # >> [M, C, Object, Kernel, BasicObject]
クラス S を継承した場合の優先度は変わらずで,あくまでクラス C とモジュール M の順序が変わるのが prepend
の影響と言える.
module M def foo puts "M#foo" end end class S def foo puts "S#foo" end end class C < S prepend M def foo puts "C#foo" end end C.new.foo p C.ancestors # >> M#foo # >> [M, C, S, Object, Kernel, BasicObject]
alias_method_chain と prepend
prepend
の挙動を理解したところで,実際にどういう活用事例があるんだろうと考えてみたときに,まさに今読んでる Metaprogramming Ruby 2 に Rails の例が載っててビビった!タイミング良くて勉強になった.
Chapter 11. The Rise and Fall of alias_method_chain
ActiveRecord の Validations で alias_method_chain
が使われていて,その実装は alias_method
を機能の有無で付け替えて事前処理を追加するようなパターンで Around Aliases と呼ばれている.
抜粋しただけだと意味ないけど,例えばこんな感じ.この実装をよりスッキリさせるために prepend
が提案されて,実際に追加された感じ.
alias_method without_method, target alias_method target, with_method
やっぱり,メタプロ本を買うなら Ruby 2.1 に対応した洋書の方を買うべき!
Metaprogramming Ruby 2: Program Like the Ruby Pros (Facets of Ruby)
- 作者: Paolo Perrotta
- 出版社/メーカー: Pragmatic Bookshelf
- 発売日: 2014/08/18
- メディア: ペーパーバック
- この商品を含むブログを見る
関連エントリー
- Matzにっき(2010-11-13)
- Module#prepend - alias_method_chainが滅ぶ日 - I am Cruby!
- » Ruby2.0のModule#prependは如何にしてalias_method_chainを撲滅するのか!? TECHSCORE BLOG