ジョギング
日課
- お休み
玉ねぎとそら豆が
- 実家から玉ねぎとそら豆が送られてきた
- 玉ねぎはベランダに干しておいた
奥さん
- 久しぶりに体調が悪いということで寝込んでいた
- 無理せず, 自分の体に正直に, 焦らずに
今日のるびぃ ~ REx - Ruby Examination にチャレンジ (9) ~
REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.
$ ruby --version ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux] $ irb --version irb 0.9.6(09/06/30)
refinements
以下のコードを実行するとどうなるか.
# file name: refinement_1.rb class Cls1 def method1(value) 100 + value end end module Mod1 refine Cls1 do def method1 super 50 end end end module Mod2 refine Cls1 do def method1 super 100 end end end using Mod1 using Mod2 puts Cls1.new.method1
以下, 実行例.
$ ruby refinement_1.rb
200
ということで, 200
が表示される.
なぜか, 以下, 解説より抜粋.
- 同一メソッドに対して, refinements を用いて, 2 つのモジュールで再定義している
- using を 2 行書いた場合, 1 つのメソッドで有効になる再定義は 1 つだけ, 最後に書いた using が優先される
- 設問で有効になるのは using Mod2 となる為, super + 100 = 100 + 100 = 200 となる
そもそも, refinements について.
- 再定義したメソッドの適用範囲を限定する機能
- 再定義したメソッドは using メソッドを利用して利用する
- using メソッドは, トップレベル, クラス構文, モジュール構文内で利用することが出来る
- トップレベルで using を呼び出した場合, using が呼び出された箇所からファイルの最後までとなる
以下, refinements の例. (プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで 「8.9 モジュールに関する高度な話題」より引用)
module StringShuffle refine String do def shuffle chars.shuffle.join end end end
- refinements を使う準備としてモジュールを作成する
- モジュール内で refine メソッドを使って, refinements を適用するクラス (上記の例では
String
クラス) を指定し, そのブロック内に shuffle メソッドを定義する
refinements を有効にする為に, 以下のように using メソッドを利用することで, Foo クラス内でのみ shuffle メソッドが利用可能となる.
irb(main):001:0> module StringShuffle irb(main):002:1> refine String do irb(main):003:2* def shuffle irb(main):004:3> chars.shuffle.join irb(main):005:3> end irb(main):006:2> end irb(main):007:1> end => #<refinement:String@StringShuffle> # 通常は String#shuffle は存在していない irb(main):008:0> 'kappa'.shuffle NoMethodError: undefined method 'shuffle' for "kappa":String irb(main):009:0> class Foo irb(main):010:1> using StringShuffle # using メソッドで StringShuffle を利用する (refinements を有効にする) irb(main):011:1> def initialize(name) irb(main):012:2> @name = name irb(main):013:2> end irb(main):014:1> def shuffle_name irb(main):015:2> @name.shuffle irb(main):016:2> end irb(main):017:1> end # Foo クラスを抜けると refinements は無効となる => :shuffle_name irb(main):019:0> user = Foo.new('kappa') => #<Foo:0x005563c35d7d80 @name="kappa"> irb(main):022:0> user.shuffle_name => "ppaak"
もう少し. サンプルコードをドキュメントより引用.
class C def foo puts "C#foo" end end module M refine C do def foo puts "C#foo in M" end end end
以下, irb にて確認.
# refinements 無し irb(main):014:0> x = C.new => #<C:0x0055b46a444cf0> irb(main):015:0> x.foo C#foo => nil # refinements 有り, だけど irb だと意図したような結果にならない irb(main):016:0> using M => main irb(main):017:0> x = C.new => #<C:0x0055b46a42bc28> irb(main):018:0> x.foo C#foo => nil # refinements 有り, 以下のように一行で書けば意図したような結果になる irb(main):019:0> using M; x = C.new; x.foo C#foo in M => nil
フムフム.