以下は Pete Lacey 氏による Idiomatic Dynamic Ruby の抄訳(というか超訳・・・)です。誤りやタイポなど、お気づきの点はご教示ください。
Ruby の動的な特性を理解するには、Ruby のオブジェクト生成を実際にトレースしていくのが近道だ。これにより、
sing = class << self; self; end
のようなメタプログラミングのイディオムも「納得して」使えるようになる。次のコードを実行してみよう。
class Test
puts "1. 基底クラス内、全てのメソッドの外側。" +
"object ID は #{self.object_id}"
def meth
puts "9. 基底クラスのインスタンスメソッド内。" +
"object ID は #{self.object_id}"
end
class << self
puts "2. 基底クラスの特異クラス内。" +
"object ID は #{self.object_id}"
def meth2
puts "4. 基底クラスのクラスメソッド内。" +
"object ID は #{self.object_id}"
sing = class << self; self; end;
puts "5. sing は特異メソッドを参照。" +
"object ID は #{sing.object_id}"
end
end
end
class Atest < Test
puts "3. 基底クラスのサブクラス内。" +
"object ID は #{self.object_id}"
end
puts "-- 基底クラスのメソッドを直接コール。"
Atest.meth2
puts "6. 基底クラスのサブクラスの外。" +
"サブクラス Atest の Object ID は #{Atest.object_id}"
class << Atest
puts "7. サブクラスの特異クラス内。" +
Object ID は #{self.object_id}"
end
puts "-- サブクラスのインスタンスを作成。"
a = Atest.new
puts "8. インスタンスオブジェクトの Object ID は #{a.object_id}"
puts "-- インスタンスメソッドをコール"
a.meth
class << a
puts "10. インスタンスオブジェクトの特異クラス内。" +
"Object ID は #{self.object_id}"
end
Ruby の動的性質の要は特異クラス(singleton class)にある。人によってはこれを仮想
クラス(virtual class)、メタクラス(metaclass)、アイゲンクラス(eigenclass)などと呼んだりもする。Ruby ではあらゆるオブジェクトが特異クラスを持つことができる。オブジェクトにとって特異クラスはスーパークラスとして機能するが、同時にそのオブジェクトの基となったクラスのサブクラスとしても機能する。つまり、親子関係の間に割って入っていくような形になるわけだ。なお、Ruby ではクラスと言えどもオブジェクトであるので、特異クラスを持つことができる。
さて、上のコードを実行したところ次のような結果が得られた(object ID は環境により異なる)。
1. 基底クラス内、全てのメソッドの外側。object ID は 21625930
2. 基底クラスの特異クラス内。object ID は 21625920
3. 基底クラスのサブクラス内。object ID は 21625900
-- 基底クラスのメソッドを直接コール。
4. 基底クラスのクラスメソッド内。object ID は 21625900
5. sing は特異メソッドを参照。object ID は 21625840
6. 基底クラスのサブクラスの外。サブクラス Atest の Object ID は 21625900
7. サブクラスの特異クラス内。Object ID は 21625840
-- サブクラスのインスタンスを作成。
8. インスタンスオブジェクトの Object ID は 21625620
-- インスタンスメソッドをコール
9. 基底クラスのインスタンスメソッド内。object ID は 21625620
10. インスタンスオブジェクトの特異クラス内。Object ID は 21625580
では、1から10の各ステップについて見ていくことにしよう。

Ruby プロセッサがまず出会うのは Test クラスの定義である。ここでメモリ上にオブジェクトが1個確保される(ステップ1)。この基底クラス内でメソッド定義以外で次に出会うのは class << self というコードだが、まだクラスメソッドが一度も定義されていないため、新たに Test クラスの特異クラスが生成される。この特異メソッドの内部で、object IDを出力し(ステップ2)、クラスメソッド meth2 を定義する。
次にRubyプロセッサは class Atest < Test というコードに出会う。そうすると Test クラスのサブクラスである Atest のオブジェクトが生成される(ステップ3)。このオブジェクト内部では Atest.meth2 のようにして基底クラス内で定義されたクラスメソッドを呼び出すことができる(ステップ4)。ただし今いるのは あくまで Atest の中であり、そのため sing = class << self; self; end; の実行で生成されるのは Atest クラスの特異クラスである(ステップ5)。
特異クラスは、例の Active Record の設計においても非常に重要な役割を果たす。Active Record におけるクラスは ActiveRecord::Base のサブクラスであるにもかかわらず、例えば Person クラスには姓名を、 Car クラスには車種を、といったようにクラスの属性を自由に設定できる。これを可能にしているのが他ならぬ特異クラスであり、特異クラスにメソッドを定義することで、基底クラスのメソッドをオーバーライト(overwrite)することなく動的にオーバーライド(override)できる。
次に Atest オブジェクト自身にobject IDを問い合わせてみる(ステップ6)。また、 class << Atest によってその特異クラスを生成する(ステップ7)。さらに Atest の new メソッドを呼び出して実際のインスタンスを作成し、object IDを尋ねる(ステップ8)。オブジェクト a のインスタンスメソッド meth を呼び出すと、予想通りの出力が返ってくる(ステップ9)。最後にオブジェクトaの特異クラスを生成する class << a というコードを実行し、プロセスを終了する。
このように、基底クラスからそのサブクラスのインスタンスまでには6つのレベルが存在している。まず基底クラスがあり、その言わば「影」として特異クラスがある。いわゆるクラスメソッドは特異クラスにおいて定義されたメソッドである。上の例でも、サブクラスである Atest は Test クラスを継承しつつも独自のクラスメソッドを持っている。さらに Atest クラスのインスタンスにも特異クラスは設定可能で、これにより、そのインスタンスに固有のメソッドを定義できる。
Rubyの動的な特性について納得はいっただろうか?