Rubyには、既に定義されたクラスを修正できるオープンクラスという機能があります。
オープンクラスとは
オープンクラスは文字通り「クラスをオープンする」ということですが、例えば以下のような使い方ができます。
class Hoge
def foo
p "foo"
end
def baz
p "baz"
end
end
Hoge.new.foo #=> foo
class Hoge
def foo
p "foo2回目"
end
def bar
p "bar"
end
end
Hoge.new.foo #=> foo2回め
Hoge.new.bar #=> bar
Hoge.new.baz #=> baz
1回目のHogeクラスを定義して、"foo"を出力するところまではなんということもありませんが、そのあとまたHogeクラスを定義することができるのですね。
「クラスをこじあける」という表現をすることがありますが、オープンクラスによってクラスの内容を修正することができます。
オープンクラスしたコードを見ていきましょう。
先程のコードでは、オープンクラスした際にfooメソッドをもう一度定義しています。
def foo
p "foo2回目"
end
こうすることによって、メソッドを上書きすることができます。結果、"foo"と出力していたメソッドが上書きされ、"foo2回目"が出力されたのです。
また、barメソッドも定義しました。
def bar
p "bar"
end
Hogeクラスのインスタンスメソッドとして、barメソッドが追加されたことを意味します。
さらに、「こじ開ける」という表現だと想像しやすいかもしれませんが、元のクラスに定義されていたメソッドはそのまま使用することができます。
例えば、先程のコードでbazメソッドは1回目の定義では記述されていたものの、オープンクラスでクラスを修正した際には記述していません。
def baz
p "baz"
end
しかし、オープンクラス後に生成したHogeクラスのインスタンスでbazメソッドを実行すると、"baz"が出力されています。このように、オープンクラスでは必要な分だけクラスを修正したり、機能を追加することができるのです。
そこで、こんな無駄なこともできるわけです。
無駄で邪魔なメソッドをつくってみる
Rubyには、組み込みライブラリとしてStringクラスが組み込まれています。
例えば、こんなコードがあります。
puts "aaa".size #=> 3
"aaa"というのは文字列。つまりStringクラスのインスタンスです。また、Stringクラスのインスタンスメソッドとしてsizeが最初から定義されています。Stringが組み込みライブラリのため、特にクラスの定義をしなくても文字列を扱うことができるようになっているのです。
さて本題ですが、オープンクラスの性質を利用して遊んでみます。以下のような形でStringのオープンクラスを定義します。
class String
def inspect
"無駄ァ!"
end
def muda
"無駄無駄無駄無駄ァ!"
end
end
inspectというのは、Objectクラスのインスタンスメソッドです。StringはObjectを継承したサブクラスであるため、Stringでもinspectメソッドが使用できます。
そして、出力に利用される組み込み関数の「p」は、オブジェクトのinspectメソッドの結果を返すのです。
通常、「Hello!World!」を出力しようとすると、以下のように書けば出力されます。
p "Hello!World" #=> Hello!World!
しかし、上記のオープンクラスを使用すると、結果はこうなります。
class String
def inspect
"無駄ァ!"
end
def muda
"無駄無駄無駄無駄ァ!"
end
end
p "Hello!World" #=> 無駄ァ!
inspectメソッドがStringクラスで書き換えられているため、pメソッドの結果も無駄になってしまったわけです。
また、オープンクラスでmudaというメソッドを再定義しました。こんな使い方もできます。
class String
def inspect
"無駄ァ!"
end
def muda
"無駄無駄無駄無駄ァ!"
end
end
p "Hello!World".muda #=> 無駄無駄無駄無駄ァ!
これでどんな文字列でも無駄で邪魔な出力ができるようになりました。
まとめ
無駄な使い方をご紹介しましたが、オープンクラスはRubyならではの本来とっても役に立つ機能です。
実はオープンクラスはRuby技術者認定試験Goldでも重要な試験範囲の一つです。また、pメソッドでinspectの結果が出力される点も聞かれることがあるので、Rubyの試験を受ける方は覚えておくとよいでしょう。