search
LoginSignup
76

More than 5 years have passed since last update.

posted at

updated at

Organization

[Ruby] メタプログラミングの入り口、オープンクラスを理解する

概要

メタプログラミングRuby勉強録。

今回のトピックはメタプログラミングの代名詞の一つ、オープンクラスです。

オープンクラスとは

既存するクラスを好きな場所で再オープンし、
メソッド修正・追加など任意の変更を加えられる機能のこと。

例えば

以下のような文字列操作メソッドがあったとします。

def love_ruby(str)
  str + ' I love Ruby!' 
end

love_ruby('My name is kidachi.')
=> "My name is kidachi. I love Ruby!"

取りあえずトップレベルに定義しましたが、
オブジェクティブにするため、クラスに所属するようにしましょう。
そこで、オープンクラスを使ってStringクラス自体を改変します。

class String
  def love_ruby
    self + ' I love Ruby!'
  end
end

'My name is kidachi.'.love_ruby
=> "My name is kidachi. I love Ruby!"

これでStringクラスを改変できました。
以後、あらゆる文字列がlove_rubyメソッドを利用できます。

'Foo!'.love_ruby
=> "Foo! I love Ruby!"

'Bar!'.love_ruby
=> "Bar! I love Ruby!"

'I love Ruby!'.love_ruby
=> "I love Ruby! I love Ruby!"

これがオープンクラスの力です。

また、新規メソッドを定義するだけでなく、
既存のメソッドを書き換えてしまうことも可能です。

例えば、文字列操作でよく使うupcaseを書き換えてみましょう。

# 本来のupcase
'I love Ruby!'.upcase
=> "I LOVE RUBY!"

# オープンクラスによりupcase自体を書き換え
class String
  def upcase
    self + ' I love Ruby!'
  end
end

# 改変後のupcase
'I love Ruby!'.upcase
=> "I love Ruby! I love Ruby!"

いかがでしょうか。
ここまでで、その強力さと同時に危険さが伝わったかと思います。

いくらRubyのことが好きでも、大文字変換が期待されるメソッドを
まったく関係のない機能で上書いてしまうのは、ただのテロですよね。

つまり、オープンクラスは、
その気になればStringやArrayと言ったコアなクラスも
思いのままに破壊できてしまう危険性

を伴っているということ。

よってオープンクラスを使う際は以下のルールを守るべきです。

  • 全ての文字列が保持しても問題のない汎用的な機能か見極める
  • 充分にテストする

つまり上記例で言うと、upcaseの書き換えはもちろん、
汎用性に欠けるlove_rubyメソッドも本来オープンクラスで
追加するようなものではないということですね。

代替案

love_rubyメソッドのように、限定的な場面でのみ
使いたい/使われるべき機能の場合は、

  • 大人しく拡張Stringクラスを定義する
  • (Ruby2.0以上の場合は)refinmentsを用いる

という選択肢があります。

※refinments
オープンクラスの影響を特定範囲に限定出来る。
ただし、Ruby2.0で実験的実装、2.1で正式採用という
非常に新しい機能なので、利用の際は最新情報キャッチアップの上でどうぞ!

参考)Refinementsとは何だったのか
http://magazine.rubyist.net/?0041-200Special-refinement

モンキーパッチ

オープンクラスにより既存のメソッドを置き換えることモンキーパッチと言います。

また、特に、意図せずに既存メソッドを書き換えてしまった事象のことや、
それゆえにマイナスイメージを伴うものを意味する向きもあります。

もちろん普通に便利なものとして使うことも。
明確な定義はなく、細かいところはその場の文脈で変わる様です。

上記のString#upcaseの書き換えは(良くない)モンキーパッチですね。

結論

オープンクラス(に限らずメタプログラミング全般)は

  • 既存クラスをいつでも思いのままに修正出来る利便性
  • ルールを破壊してしまう危険性

を備えています。

メタプログラミングの入り口に立った私たちは、
今後常にMatzのことばを頭の片隅に置いておきたいですね。

「Rubyは君を信頼する。Rubyは君を分別のあるプログラマとして扱う。
Rubyはメタプログラミングのような強力な力を与える。
ただし、大いなる力には、大いなる責任が伴うことを忘れてはいけない」

-「メタプログラミングRuby」序文より。

以下に続く

[Ruby] method_missing()を実用レベルで理解する
http://qiita.com/kidachi_/items/75ae4a29c99a79816384

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
76