成らぬは人の為さぬなりけり

エンジニアライフをエンジョイする為のブログ

Ruby2.0の新機能を勉強してみる その3 Refinements

前回に引き続き、
Ruby2.0の新機能のお勉強です。

今回は、実験的に追加された機能である「Refinemens」をやってみようと思います。

今回のテーマ

「Refinements」

環境

Refinementsって何?

Rubyはオープンクラスなので、クラスをいたるところで自由に拡張できます。
しかし、一回拡張すると、同じクラスを使用している所すべてに影響が出ます。
例えば、

Hashを拡張して、「xxx.key」でvalueが取得できるようにしてみました。

このファイルが一回requireされると、
アプリケーション全体で使えるようになります。
これは、非常に大きなメリットではあるのですが、
どこでもなんでも出来てしまうのは、デメリットな場面もあります。

そこで、このような拡張をスコープを絞って使用可能にする機能がrefinementです。
(と、理解している、、、)

どうやって使うのか

実際にコードを書いてみます。

このように「Module#refine」を使って定義します。
今回は、先の例をrefineを使って定義してみました。

refinement/refinement01.rb:3: warning: Refinements are experimental, and the behavior may change in future versions of Ruby!
"hoge"
"foo"

と、いうように、現在は警告が出ます。
「Refinementsは実験的な機能なので、今後のバージョンで振る舞いが変わる可能性があるよ!」
と言ってるようです。なるほど。

ちなみに、「using」メソッドは、匿名モジュール(main)でしか呼び出せないようです。
ModuleやClassには定義されていないので、

module Hoge
  using XX
....
end

class Foo
  using XX
...
end

とか、できません。

ホントにスコープは限定的になるのか?

やってみます。
先の例のHashをオープンクラスで拡張する方法をまず試してみます。

これの「hash_extention03.rb」を実行してみます。

"hoge"
"hash_extention2"
"hash_extention3"

すべて02と03でも最初に定義したメソッドが使えたようです。

では、次にrefinementsを試してみます。

「refinement02.rb」を実行してみます。

refinement/refinement01.rb:3: warning: Refinements are experimental, and the behavior may change in future versions of Ruby!
"hoge"
"foo"
refinement/refinement02.rb:4:in `<main>': undefined method `a' for {:a=>"refiment02"}:Hash (NoMethodError)

はい、「aなんてメソッド無いですけど?」と怒られました。

というわけで、スコープはusingしたファイル内に限られるようです。

まとめ

このRefinement機能すごく興味があって、
実用化されれば、かなり使い所あると思うんですよね。
今後に期待!!

今回のリリースから外れた機能や、
refinementsの詳しい仕様に関しては、以下をご参照下さい。
RefinementsSpec - ruby-trunk - Ruby Issue Tracking SystemRubyist Magazine - Refinementsとは何だったのか
Class: Module (Ruby 2.0)