注意:refinement は2013/02/27 時点でexperimentalですので、この記事が三日後ゴミになっている可能性はありますので注意してくださいね。
refinementとは?
まず簡単に refinement について説明します。refinement とは、モジュールの適用範囲を特定のファイル内のみに制限するための仕組みです。おっともうこの時点でなんか使えそうな気がしてきました。
http://jp.rubyist.net/magazine/?0041-200Special-refinement
からのサンプルコードを拝借すると、
という感じで定義します。通常の module と違うのは refine というブロックの存在です。ここで指定されたクラスにそのブロック内のメソッドをまとめて追加するぞ、という意味になります。もちろん複数のクラスを指定して、一気に refine することができます。
で、これをどう使うかというと、
使う側はこのような感じ。ファイルでこのように using で refinement を指定すると、そのファイルの中でのみ、refine 対象のクラスにメソッドが追加される、という動きになります。
http://jp.rubyist.net/magazine/?0041-200Special-refinement
からのサンプルコードを拝借すると、
# rationalize.rb module Rationalize refine Fixnum do def /(other) quo(other) end end end
という感じで定義します。通常の module と違うのは refine というブロックの存在です。ここで指定されたクラスにそのブロック内のメソッドをまとめて追加するぞ、という意味になります。もちろん複数のクラスを指定して、一気に refine することができます。
で、これをどう使うかというと、
using Rationalize p 1 / 2 #=> (1/2)
使う側はこのような感じ。ファイルでこのように using で refinement を指定すると、そのファイルの中でのみ、refine 対象のクラスにメソッドが追加される、という動きになります。
DCI的に解釈
これをDCIに使えるのか?DCIではコンテキストを定め、そのコンテキスト以下においてはモデルに対して自動でroleが付与され、そのコンテキスト下でのみ実装の追加や差し替えが行われます。そしてそのコンテキストを抜け出たらそのroleは自動的に消滅します。
すると、そのコンテキスト下で各modelに付与すべきroleを refinement として定義しておき、そのコンテキストを表すファイルの先頭で using refinement する。すると refinement が role として各modelに付与される。その refinement はそのファイル内でのみ有効なので、コンテキストを抜けると自動的に role が消えます。
仕組みとしては良さそうです。また、特定コンテキスト下の role をひとまとめに書いておいて、それを一括で漏れ無くガツンと追加できる、というのもワタシ好みな感じです。今までのナイーブな rails での問題として、特定のコンテキスト下でのみ必要なメソッドが各モデルに分散してよくわからなくなる、という問題がありました。それがコンテキストという単位で一箇所にまとめることができるのは良いと思います(もちろん、モデルに置くべきか、コンテキスト単位でまとめるべきか、というのはケースバイケースだと思いますが)。また、このコンテキストで、いったいどのmoduleがextendされているのか?というのも一目瞭然なのが良いです。最もビジネスロジックレイヤーに近い、サービスなどの実装ではこの refinement が活躍しそうな予感で一杯です。
以上