Ruby 2.0.0リリース! – prependを使ってみよう

Ruby20周年おめでとうございます。そして、待望の2.0.0がリリースされましたね! 1.8から1.9になったときと違い、互換性がなくなる変更は少ないので、比較的移行は楽そうです。 有名かつ大きな新機能は キーワード引数 Module#prepend Enumerable#lazy Refinements ですが、ここではprependについて見てみます。 prependはメソッド探索チェーンの手前にmoduleを差し込む機能であって、何がうれしいかといえばalias_method_chainと同じことがシンプル・高速に実現できるということです。 たとえば以下のようなクラスがあったとします。 class Person def hello puts “Hello! I am a person.” end end class Student < Person def hello puts “Hello! I am a student.” end end ここで、挨拶の前後に処理を入れたい場合、Module#prependを使えばこのように簡単に実現できます。 module Polite def hello puts “これから挨拶します” super puts “よろしくお願いします” end end class Student < Person prepend Polite end Student.new.hello 実行結果 これから挨拶します Hello, I am a student. よろしくお願いいたします 同じことをRuby 1.9で実現したい場合、以下のようなアプローチが必要になります。 StudentのサブクラスPoliteStudentを用意して、helloを定義し、その中でsuperを呼び出す この方法では、Studentを利用しているすべての箇所をPoliteStudentに書き直す必要があります。 Student#polite_helloを定義し、その中でhelloを呼び出す この方法では、Student#helloを利用しているすべての箇所をStudent#polite_helloに書き直す必要があります。 Student#helloをStudent#original_helloとして別名定義する(alias_method)。Student#helloを上書きし、その中でoriginal_helloを呼び出す alias_method_chainの仕組みです。呼び出し側に影響なく実現できますが、original_helloのようなつまらないメソッドが増えてしまいます。 すぐに思いつく使い方としては、 特定メソッドの前後で時刻を測定し、簡易的なプロファイリングを実施 例外が発生するメソッドがあるけどそれを握りつぶしたい・独自処理したい 特定メソッドの実行のみ、I18n.localeやシステム環境変数をいじりたい などに使えそうですね。 このようなちょっとしたパッチを、少ないコード量で気軽に実現できるのが重要なポイントだと思います。 なお、メソッドの探索順を図で表すと、こんな感じです。 prependの場合、superでStudentクラスのメソッドが呼び出せることがわかると思います。   ここまで書いて、Personクラス意味ないことに気がついたorz