/ ,' 3

https://twitter.com/gorlemkun

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