Ruby 2.0 series




                  refinements

                            弘野/それぃゆ
                              @hilohiro
ご注意!
    今回の内容は
Ruby 2.0.0 Preview 2で
  確認した内容です。


正式リリースでは変更される
  可能性があります。
黒魔術をより安全に(?)
Rubyの特徴 - オープンクラス
●   定義されたクラスを実行中に改変できる
    –   メソッドを追加したり変更したり削除したり
    –   システムが定義しているクラスでも可能
refinements
●
    クラスの変更の影響範囲を限定する
    –   モンキーパッチはアプリケーション全体に影響する
●   既存のクラスの改変を行う
    –   メソッドの追加、上書き
    –   モジュールのインクルード


●   モジュール/クラス内でrefineする
    –   Module#refine(clazz) として定義されている
●   refinementsを利用したいところでusingを呼び出す
書き方
module MyScope
  refine String do
    def double_string
      self + self
    end
  end
end

class ScopeUser
  using MyScope

  def run_refined
    'sample string'.double_string
  end
end

p ScopeUser.new.run_refined # => "sample stringsample string"
p 'outer string'.double_string
NoMethodError: undefined method `double_string' for "outer
string":String
        from (irb):3
        from /usr/local/bin/irb:12:in `<main>'
もう少し細かく
Module#refine(clazz, &definitions)
●   refinementsの内容を定義する
●   refinements対象のクラスをパラメータで指定する
    –   参考資料にはモジュールはrefine出来ないと書かれて
        いたけど成功した…バグ?
●   1つのモジュールに複数のrefineを書くことが出来
    る
    –   全てのrefineがまとめて利用される
Module#using(mod)
●   モジュールで定義されたrefinementsの内容を利用可
    能にする
●   モジュールのincludeは行われない
    –   モジュールをネームスペースとして利用するだけ
●   メソッド内でもusingを呼び出せる
    –   そのメソッドだけで有効
●   グローバルにもusingを呼び出せる
    –   普通にモンキーパッチ? それともソースファイルスコープ?
Module#used(mod)
●   usingでrefinementsが利用されたときに呼び出さ
    れる
    –   Module#included(mod)のusing版
    –   mod.send(:include, self)でincludeを強制できる
refinementsの優先順位
    refineのブロックで定義されたメソッドは…
●   includeしたモジュールで定義されたものよりも優
    先される
●   クラスで定義されたものよりも優先される
    –   オープンクラスで改変したものよりも優先される
●   派生クラスでオーバーライドしたものよりは優先度
    が低い
    –   デモします
refinementsの優先順位(その2)
    refineのブロックでincludeしたモジュールのメソッド
    は…
●   includeしたモジュールで定義されたものよりも優先
    される
●
    クラスで定義されたものよりも優先される
●   派生クラスでオーバーライドしたものよりは優先度
    が低い
●   refineのブロックでdefされたメソッドよりは優先度が
    低い
Ruby 2.0 rcのrefinements
●   Ruby 2.0 Preview 2までと違ってrcでは
    require 'refinement.so'
    が必要
    –   using が定義されていない
    –   refinements.soじゃないようです…


●   のですが今のところ refinement.so のビルドが上
    手くいっていません…
    –   はまりました
あとは適当に議論しましょう。
組み合わせ
refinementsと特異メソッド
●   refinementsのブロックで特異メソッドを定義しよう
    としても上手くいかない
    –   def self.foo で定義したときは呼び出せない特異メソッ
        ドになる
    –   def Refined.foo で定義したときは、refinementsとは
        無関係に特異メソッドが書き換わる(通常のオープンク
        ラスで定義した場合と同様)
●   refine Refined.singleton_classでクラスを指定す
    る
refinementsとundef
●   refineしたクラスがもつメソッドをundefして
    も、refineで定義された同名のメソッドはundefさ
    れない
●   refine内でundefすると無限ループに…
usingと継承
●   親クラスでusingを呼び出したrefinementsは派生
    クラスでも利用可能
●   子クラスでusingを呼び出しても親クラスのメソッド
    には効果を現さない
    –   ただし、子クラスでオーバーライドしたメソッドを親クラ
        スが呼び出した場合は別
refineされるクラスのメソッド
●   refinementsはSelectorNamespace
●   refineされるクラスのメソッドは、通常refineで書き換えられたメソッドを呼び出すこと
    が出来ない
      class A
        def foo
          bar
        end
        def bar
          'A#bar'
        end
      end
      module RefineA
        refine A do
          def bar
            'RefineA#bar'
          end
        end
      end
      def test
        using RefineA
        A.new.foo
      end
      p test # => 'A#bar'
モジュールでのusing
●   モジュールAでモジュールRefinerをusingしても、
    モジュールAをincludeしたクラスBではRefinerで
    定義されたrefinementsは利用できない
    –   モジュールAで定義されたコードでのみ利用可能
参考資料
●   http://qiita.com/items/77fd309178dcdd13b5cd
●   http://timelessrepo.com/refinements-in-ruby
●   http://www.infoq.com/jp/news/2012/11/ruby-20-
    preview1

More Related Content

PDF
UnrealEngineが5日間でasm.js化できたと聞いた俺たちは…
ODP
Rubyのコードを読んでみよう(オブジェクト編)
PDF
Javaクラスファイルの読み方
PDF
ebisu.rb #19 超実践 super
PDF
表参道.Rb #27 pattern-match の一部を読む
PDF
RubyとActive Support for expert 2
PDF
Module での名前解決について
PPT
クラスのインスタンス変数について
UnrealEngineが5日間でasm.js化できたと聞いた俺たちは…
Rubyのコードを読んでみよう(オブジェクト編)
Javaクラスファイルの読み方
ebisu.rb #19 超実践 super
表参道.Rb #27 pattern-match の一部を読む
RubyとActive Support for expert 2
Module での名前解決について
クラスのインスタンス変数について
Ad

Ruby2.0 - refinements - 鳥取Ruby会 第11回

  • 1. Ruby 2.0 series refinements 弘野/それぃゆ @hilohiro
  • 2. ご注意! 今回の内容は Ruby 2.0.0 Preview 2で 確認した内容です。 正式リリースでは変更される 可能性があります。
  • 4. Rubyの特徴 - オープンクラス ● 定義されたクラスを実行中に改変できる – メソッドを追加したり変更したり削除したり – システムが定義しているクラスでも可能
  • 5. refinements ● クラスの変更の影響範囲を限定する – モンキーパッチはアプリケーション全体に影響する ● 既存のクラスの改変を行う – メソッドの追加、上書き – モジュールのインクルード ● モジュール/クラス内でrefineする – Module#refine(clazz) として定義されている ● refinementsを利用したいところでusingを呼び出す
  • 6. 書き方 module MyScope refine String do def double_string self + self end end end class ScopeUser using MyScope def run_refined 'sample string'.double_string end end p ScopeUser.new.run_refined # => "sample stringsample string" p 'outer string'.double_string NoMethodError: undefined method `double_string' for "outer string":String from (irb):3 from /usr/local/bin/irb:12:in `<main>'
  • 8. Module#refine(clazz, &definitions) ● refinementsの内容を定義する ● refinements対象のクラスをパラメータで指定する – 参考資料にはモジュールはrefine出来ないと書かれて いたけど成功した…バグ? ● 1つのモジュールに複数のrefineを書くことが出来 る – 全てのrefineがまとめて利用される
  • 9. Module#using(mod) ● モジュールで定義されたrefinementsの内容を利用可 能にする ● モジュールのincludeは行われない – モジュールをネームスペースとして利用するだけ ● メソッド内でもusingを呼び出せる – そのメソッドだけで有効 ● グローバルにもusingを呼び出せる – 普通にモンキーパッチ? それともソースファイルスコープ?
  • 10. Module#used(mod) ● usingでrefinementsが利用されたときに呼び出さ れる – Module#included(mod)のusing版 – mod.send(:include, self)でincludeを強制できる
  • 11. refinementsの優先順位 refineのブロックで定義されたメソッドは… ● includeしたモジュールで定義されたものよりも優 先される ● クラスで定義されたものよりも優先される – オープンクラスで改変したものよりも優先される ● 派生クラスでオーバーライドしたものよりは優先度 が低い – デモします
  • 12. refinementsの優先順位(その2) refineのブロックでincludeしたモジュールのメソッド は… ● includeしたモジュールで定義されたものよりも優先 される ● クラスで定義されたものよりも優先される ● 派生クラスでオーバーライドしたものよりは優先度 が低い ● refineのブロックでdefされたメソッドよりは優先度が 低い
  • 13. Ruby 2.0 rcのrefinements ● Ruby 2.0 Preview 2までと違ってrcでは require 'refinement.so' が必要 – using が定義されていない – refinements.soじゃないようです… ● のですが今のところ refinement.so のビルドが上 手くいっていません… – はまりました
  • 16. refinementsと特異メソッド ● refinementsのブロックで特異メソッドを定義しよう としても上手くいかない – def self.foo で定義したときは呼び出せない特異メソッ ドになる – def Refined.foo で定義したときは、refinementsとは 無関係に特異メソッドが書き換わる(通常のオープンク ラスで定義した場合と同様) ● refine Refined.singleton_classでクラスを指定す る
  • 17. refinementsとundef ● refineしたクラスがもつメソッドをundefして も、refineで定義された同名のメソッドはundefさ れない ● refine内でundefすると無限ループに…
  • 18. usingと継承 ● 親クラスでusingを呼び出したrefinementsは派生 クラスでも利用可能 ● 子クラスでusingを呼び出しても親クラスのメソッド には効果を現さない – ただし、子クラスでオーバーライドしたメソッドを親クラ スが呼び出した場合は別
  • 19. refineされるクラスのメソッド ● refinementsはSelectorNamespace ● refineされるクラスのメソッドは、通常refineで書き換えられたメソッドを呼び出すこと が出来ない class A def foo bar end def bar 'A#bar' end end module RefineA refine A do def bar 'RefineA#bar' end end end def test using RefineA A.new.foo end p test # => 'A#bar'
  • 20. モジュールでのusing ● モジュールAでモジュールRefinerをusingしても、 モジュールAをincludeしたクラスBではRefinerで 定義されたrefinementsは利用できない – モジュールAで定義されたコードでのみ利用可能
  • 21. 参考資料 ● http://qiita.com/items/77fd309178dcdd13b5cd ● http://timelessrepo.com/refinements-in-ruby ● http://www.infoq.com/jp/news/2012/11/ruby-20- preview1