読者です 読者をやめる 読者になる 読者になる

Rubyのclass << selfとクラスメソッド、ならびに特異メソッドと特異クラス

Rubyライブラリのソースコードを読んでいると、よく class << self という構文が出てきます。
↓こんなの

class C
  class << self
    def foo
      puts 'foo'
    end
  end
end

C.foo #foo


最初見た時は?と思いましたが、ようはこれ(クラスメソッド定義)と同じでした。

class C
  def self.foo
    puts 'foo'
  end
end

C.foo #foo


肝は

・クラスメソッドとは、クラスの特異クラスのインスタンスメソッドである
・class << obj; endは、objの特異クラスを開く

という2点

なので、さきほどのコードに解説をつけるとこうなります

class C
  class << self # クラスCの特異クラスをオープン(このselfはクラスCなので)
    def foo # クラスCの特異クラスのインスタンスメソッド(=クラスCのクラスメソッド)を定義
      puts 'foo'
    end
  end
end

C.foo #foo


さらに

・特異クラスのインスタンスメソッドのことを、特異メソッドと呼ぶ
・特異メソッドは、def obj.メソッド名; endで定義する

なので、以下は全て同義です

class C
end

# foo1
def C.foo1
  puts "foo1"
end

# foo2
class << C
  def foo2
    puts "foo2"
  end
end

# foo3
class C
  def self.foo3
    puts "foo3"
  end
end

# foo4
class C
  class << self
    def foo4
      puts "foo4"
    end
  end 
end

# foo5
(class << C; self; end).send(:define_method, :foo5) {puts "foo5"}

# foo6
# Ruby 1.9.2 以上
C.singleton_class.send(:define_method, :foo6) {puts "foo6"}

C.foo1 #foo1
C.foo2 #foo2
C.foo3 #foo3
C.foo4 #foo4
C.foo5 #foo5
C.foo6 #foo6


class << self は、複数のクラスメソッドを定義する時に便利ですね

class C
  class << self
    attr_accessor :v
    
    def foo
      puts @v
    end
  end
end
                                                                                                                                                                                                            
C.v = 'foo'
C.foo #foo