ようへいの日々精進XP

よかろうもん

2018 年 02 月 17 日(土)

ジョギング

  • 香椎浜 x 3 周
  • 天気も良くて走りやすかった

日課

  • (腕立て x 50 + 腹筋 x 30) x 3

フィギュアスケート

  • 見ているだけで膝が痛くなりそうなんだけど...
  • 羽生選手と宇野選手で金銀, 本当に素晴らしいと思う
  • 田中選手もよく頑張ったと思うので, 上の二人に負けないようにこれからも精進して欲しい
  • 俺も負けじと精進しよう

藤井五段

  • 羽生選手と宇野選手の金銀で湧いているが, 将棋の藤井五段が羽生善治に勝ったらしい
  • これも凄いよなあ

夕飯

  • 奥さんの手料理
  • おいしゅうございました

今日のるびぃ 2018/02/17 ~ Refinement ~

これは メタプログラミング Ruby 第 2 版 の読書メモです.

オープンクラスの懸念点

  • オープンクラスしてクラスを修正する際の課題して, 変更がグローバルに及んでしまうこと
  • 変更がグローバルに及ぶことにより, 別の箇所のコードを破壊してしまう懸念がある
[1] pry(main)> String.methods.grep(/disp/)
=> [:display]
[2] pry(main)> "aaa".display
aaa=> nil
[3] pry(main)> class String
[3] pry(main)*   def display
[3] pry(main)*     'foo'
[3] pry(main)*   end
[3] pry(main)* end
=> :display
[4] pry(main)> "aaa".display
=> "foo"

上記は, String.display をオープンクラスして挙動を変更した際の実行例.

Refinement

上記のような懸念点を解消する為に Refinement を利用する.

module StringRefine
  refine String do
    def display
      'foo'
    end
  end
end

puts 'aaa'.display

using StringRefine
puts 'aaa'.display

上記のコードを実行すると, どのような結果になるだろうか.

$ ruby refinements_sample.rb
aaa
foo

using StringRefine を実行した以降, String.display の挙動が変わっていることが解る.

Refinements の適用範囲

Ruby 2.1 から module 内でも Refinement を呼び出せるようになっているので, 以下のように SubString モジュール定義の中だけで String.display の挙動を変えることが出来る.

module StringRefine
  refine String do
    def display
      'foo'
    end
  end
end

puts 'aaa'.display   #=> aaa

module SubString
  using StringRefine
  puts 'aaa'.display #=> foo
end

puts 'aaa'.display   #=> aaa

Refinement が有効になるのは, 以下の 2 箇所となる.

  • refine ブロックそのもの
  • using を呼び出した場所からモジュールの終わり, もしくはトップレベルにいる場合にはファイルの終わりまで

参考

ふむふむ.