アペフチ

Sendagaya.rb #135

Sendagaya.rb #135に行って来た。今日も前半は『メタプログラミングRuby 第2版』を読んで、後半はRails 5のチェンジログからActive Record 5.0.0.beta1のチェンジログを眺めていた。

メタプログラミングRuby Refinements

今日は「2.4.2 メソッドの実行」から「2.4.3 Refinements」まで。

メソッドの実行では他の言語から来るとprivateとかに戸惑うよねとか、protectedって何に使うんだろうねという話をした。

お次はいよいよRefinements

class MyClass
  def my_method
    "original my_method"
  end

  def anothor_method
    my_method
  end
end

module MyClassRefinements
  refine MyClass do
    def my_method
      "refined my_method"
    end
  end
end

using MyClassRefinements
MyClass.new.my_method      # => "refined my_method"
MyClass.new.another_method # => "original my_method"

この最後の行は驚かないだろうか。僕は驚いた。

この挙動を本では

Refinementsが有効になっているコードは、(略)インクルードやプリペンドしたモジュールのコードよりも優先される。

と説明している。しかしこれだけで、メソッド探索の順番を覚えられるだろうか。@tkawaさんの説明が素晴らしかった。

  1. クラスやインクルードやプリペンドを考慮するより先に、まずRefinementsを探す
  2. 次に通常のメソッド探索手順に従って、プリペンドされた物、インクルードした物、特異クラス、クラス……とメソッドを探す

ということだ。上の例で言うと、まずmy_methodを呼ぶ場合

  1. Refinementsを探す
  2. MyClassRefinementsが見付かる
  3. my_methodが定義されている
  4. MyClassRefinements#my_methodを呼ぶ

で、結果は"refined my_method"になる。一方another_method

  1. Refinementsを探す
  2. MyClassRefinementsが見付かる
  3. another_methodは定義されていない
  4. Refinementsの探索は終わり、今後二度と探索されない
  5. プリペンドされたモジュールやインクルードされたモジュールを探すが、ない
  6. クラスを見る
  7. MyClassである
  8. another_methodが定義されている
  9. another_methodを実行する
  10. my_methodが呼ばれている
  11. Refinementsの探索は終わっているので、クラスのmy_methodが見付かる
  12. MyClass#my_methodを実行する

ということで、結果が"original my_method"になる、というわけだ。

子の説明を聞いて僕は「あ。」と声が漏れるくらい腹に落ちた。

Active Record 5.0.0.beta1チェンジログ

その後もちょいちょいRefinementsと遊んでからはActive Record 5.0.0.beta1のチェンジログをざっと流しながら気になった所で止めて、あーだこーだ言っていた。結構RDBMSの個別機能に対応していたり、細かなユースケースを拾ったりしていて、「Active Recordは基本は既に成熟しているんだろうなあ」という感想を持った。

次回は『メタプログラミングRuby』読むほか、fukajunさんがElectronについての発表をしたいということなのでそれは聞けるはずだ。あとはその場で決まるんだろう。その場で決まるので、聞きたいことを持って行けば、聞けると思う。

次回分もすぐさまイベントが作られて、申し込める。
https://sendagayarb.doorkeeper.jp/events/38655