特異メソッド、特異クラスとクラスメソッドの関係について

## はじめに
昨晩、rubyの特異メソッドや特異クラスについて調べたところ深みにはまってしまい、気付いたらAM2:00になっていました。。
せっかくなので、調べた結果をまとめてみました。

## 特異メソッドとは何か？
一言でいうと、**あるオブジェクト固有のメソッド**です。
特異メソッドは`def オブジェクト名.メソッド名`という記法で定義します。

```rb
class People
  def hello
    puts "hello!"
  end
end
tanaka = People.new

# tanakaに特異メソッドbyeを定義
def tanaka.bye
  puts "goodbye!"
end

tanaka.bye
# => goodbye!

# 別のオブジェクトからはbyeメソッドは呼び出せない
suzuki = People.new
suzuki.bye
# => NoMethodError: undefined method `bye' for #<People:0x007fc328da83b8>
```
特異メソッドは**クラスではなくオブジェクトに直接定義されるメソッド**になります。そのため、特異メソッドbyeはオブジェクトtanakaからのみ呼び出すことができ、同じPeopleクラスに属するsuzukiからは呼び出すことができません。

## クラスメソッドとは何か？
クラスメソッドは、クラスに属するメソッドであり、クラスから直接呼び出すことができるメソッドであるというのが、通常の理解かと思います。
では、なぜ**クラスから直接呼び出すことができる**のでしょうか？
その答えは、クラスメソッドが**クラス自身(Classクラスのオブジェクト)の特異メソッド**だからです。
Classクラスとは、簡単にいうと**全てのクラスの元となるクラス**です。例えば、クラスの基本的なメソッドである`new`メソッドはClassクラスのインスタンスメソッドとして定義されています。
分かりにくいので、詳しく見ていきます。

```rb
class People
  # インスタンスメソッド定義
  def hello
    puts "hello!"
  end
  # 特異メソッド(クラスメソッド)定義
  def self.bye
    puts "goodbye!"
  end
end

# クラスメソッドは'クラス名.メソッド名'で呼び出すことができる
People.bye
# => goodbye!

# インスタンスメソッドhelloは、インスタンスからしか呼び出せない
People.hello
# => NoMethodError: undefined method `hello' for People:Class
tanaka = People.new
tanaka.hello
# => hello!
```
クラスメソッドは、クラス定義の中で`def self.メソッド名`と定義します。この`def self.メソッド名`の`self`とは、**ClassクラスのオブジェクトであるPeople**です。
実際に確認してみます。

```rb
class People
  # selfの中身を確認
  p self
  # selfのクラスを確認
  p self.class
end
# => People
# => Class
```

よく言われているように、rubyでは全てがオブジェクトです。そのため、Peopleクラスも**クラスであると同時にオブジェクト**でもあります。
前述のクラスメソッドの定義で使用されていた`def self.メソッド名`という記法ですが、`self`はオブジェクトPeopleですので、`def People.メソッド名`と同じ意味になります。
これは、特異メソッドの定義方法である`def オブジェクト名.メソッド名`と同一です。特異メソッドはオブジェクトに直接定義されるメソッドですので、オブジェクト(ここではPeopleクラス)から呼び出すことができます。
その結果、`People.メソッド名`という記法で呼び出すため、クラスから直接呼び出しているように見えるということです。

- Classクラス
- Peopleクラス
- Peopleクラスのオブジェクトtanaka

の関係性は下記図になります。

<img width="496" alt="スクリーンショット 2017-03-07 12.45.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/161201/0634d268-d3fe-642c-d664-a76403930b7d.png">


## 特異クラスとは何か？
さて、特異メソッドとクラスメソッドの関係は上記の通りですが、実は特異メソッドの説明の中で、正確ではない表現になっていた箇所があります。
それは、**特異メソッドはクラスではなくオブジェクトに直接定義されるメソッド**という箇所です。
実は、メソッドは全てクラスに定義されており、特異メソッドも例外ではありません。そのため、**オブジェクトに直接定義される**という表現は正確ではありません。
では、特異メソッドはどこに定義されているのかというと、**オブジェクトの特異クラスのインスタンスメソッド**として定義されています。
特異クラスとは、**ある特定のオブジェクト固有のクラス**です。特異クラスは、オブジェクト一つに対して1対1の関係で存在するクラスです。例えば、オブジェクトPeopleの特異クラスは、オブジェクトPeopleのためだけのクラスであり、他のオブジェクトのクラスにはなり得ません。
オブジェクトPeopleの特異クラスのインスタンスメソッドは、そのインスタンスであるオブジェクトPeopleから呼び出すことができます。
これが、オブジェクトPeopleのクラスメソッドの正体です。

- Classクラス
- Peopleクラスの特異クラス
- Peopleクラス
- Peopleクラスのオブジェクトtanaka

上記の関係性を下記の図で示します。
<img width="663" alt="スクリーンショット 2017-03-07 12.45.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/161201/e765f944-02a6-f672-7202-29efafd7bbdc.png">

次に実際にコードで確認してみます。
特異クラスはユーザーには意識されないようになっているらしく、`class`メソッドでは表示することができないため、`singleton_class`メソッドを使って表示します。

```rb
# Peopleの特異クラスを確認
People.singleton_class
# => #<Class:People>

# 特異クラスのクラスを確認
People.singleton_class.class
# => Class
```

また、オブジェクトPeopleの特異メソッドであるbyeが、実際には特異クラスのインスタンスメソッドとして定義されていることを確認します。

```rb
# 特異クラスのインスタンスメソッドにbyeが存在することを確認
People.singleton_class.instance_methods(false)
# => [:bye]
```

## まとめ
- 特異メソッドは、あるオブジェクト固有のメソッド
- クラスメソッドは、クラス自身(Classクラスのオブジェクト)の特異メソッド
- 特異クラスは、ある特定のオブジェクト固有のクラス
- 特異メソッドの真の姿は、オブジェクトの特異クラスのインスタンスメソッド