RubyにおけるクラスメソッドがClassクラスのインスタンスの特異メソッドだった話
Rubyでは、特異メソッドとしてインスタンスに直接所属するメソッドを作成出来る。
HOGE = Object.new def HOGE.fuga p "fugafuga" end HOGE.fuga # "fugafuga" HOGEEE = Object.new HOGEEE.fuga # NoMethodError
この場合、ObjectクラスのインスタンスであるHOGEに対して直接特異メソッドを生やしているため、#fugaメソッドはHOGEからしか呼べず、同じObjectクラスのインスタンスであるHOGEEEから呼ぶことは出来ない。 上記はこのように書き換え可能。
HOGE = Object.new class << HOGE def fuga p "fugafuga" end end HOGE.fuga # "fugafuga" HOGEEE = Object.new HOGEEE.fuga # NoMethodError
class式に<<を使って直接オブジェクトを指定することで特異クラスを定義して、その特異クラスであるHOGEクラスに対して、fugaインスタンスメソッドを生やしている。
ところで、
class Hoge
するとき、Ruby内ではまずClassクラスのインスタンスが作成される。そして、そのインスタンスが参照する先がHogeという定数になる。すなわち、HogeというClassクラスのインスタンスが定義され、RubyにおいてはHogeクラスとして扱われる。(※Ruby内では大文字から始まる変数は定数となる)
書き方を変えるとこうなる。
Hoge = Class.new
そして、
class Hoge class << Hoge def fuga p "fugafuga" end end end Hoge.fuga # "fugafuga"
こうした場合、、、 ClassクラスのインスタンスであるHogeというオブジェクトから特異クラスを定義して、そのHoge特異クラスに対して、fugaインスタンスメソッドを生やしている。 Hogeクラス内のHogeはselfに書き換え可能なので
class Hoge class << self def fuga p "fugafuga" end end end Hoge.fuga # "fugafuga"
こう出来る。 Hoge.fugaのようなものはクラスメソッドと呼ばれ、クラスメソッドはClassオブジェクトの特異メソッド(特異クラスのメソッド)である。
そのため、クラスメソッドというのはインスタンスメソッドとは違い、もう既に生成されたインスタンス(Classクラスのオブジェクト)から呼ばれる。Hoge.newから新たに生み出されたインスタンスから呼ばれるインスタンスメソッドとは根本的に呼ばれる元が違うので注意(注意してもなんにもならないんだけどね)。
参考: http://magazine.rubyist.net/?0046-SingletonClassForBeginners