クラスからメソッドを呼び出すことと、インスタンスからメソッドを呼び出すことの違いについて

プログラミングを学び始めて1日目でも書けそうなコードで躓いてしまったのですが、やっぱり基本は大事だなと改めて思ったので、書き留めることにします。
皆さんは以下のコードを実行するとどのような結果になるかわかりますか。

```ruby
class Human 

  puts "今から喋ります！"
  say
 
  def say
    puts "こんにちは"
  end
end
```

結果は以下のようにエラーとなります。

```shell
$ ruby human.rb
今から喋ります！
human.rb:4:in `<class:Human>': undefined local variable or method `say' for Human:Class (NameError)
from human.rb:1:in `<main>'

```

エラーコードを読んでエラー原因がわかった方も多いと思います。
なるほど、メソッドを先に定義していないからエラーになったんだ。と。
では、さっそく以下のように書き直しましょう！

```ruby
class Human 
  
  def say
    puts "こんにちは"
  end

  puts "今から喋ります！"
  say
end
```

以下が結果です。

```shell 
$ ruby human.rb
今から喋ります！
human.rb:8:in `<class:Human>': undefined local variable or method `say' for Human:Class (NameError)
from human.rb:1:in `<main>'
```

**<del>もうやだ！プログラミングやめる！！</del>**
このエラーを理解するためには、クラスから呼び出すメソッドと、インスタンスから呼び出すメソッドは勝手が違うということを理解する必要がありました。

###１．クラスからメソッドを呼び出すときは、メソッドをクラスメソッドに定義する
以下のようにメソッド名に**"self."**を追加してメソッドをクラスメソッドにして実行してみます。

```ruby
class Human 

  #before
#  def say
#    puts "こんにちは"
#  end
#
#  puts "今から喋ります！"
#  say
#end

  #after
  def self.say
    puts "こんにちは"
  end

  puts "今から喋ります！"
  say
end
```

実行結果：

```shell
$ ruby human.rb
今から喋ります！
こんにちは
```
無事にエラーが消えて、処理が実行されました！
この理由は**self.**をメソッド名の左側に明示的に記述することで、このメソッドのレシーバーにクラスを定義します。
（言い換えればインスタンスメソッドからクラスメソッドになります。）
<del>レシーバーとは、メソッドの戻り値をレシーブ（受け取る）ところを指します。</del>
【修正】レシーバーとは、メソッドの呼び出し元を指します。


```ruby
class Class 

  def self.say
    p "#{self}がレシーバーです。"
  end

  say
end
```

以下の実行結果のように**self.**にあたるレシーバーはクラスオブジェクトです。

```shell
$ ruby class.rb
"Classがレシーバーです。"
```



一方で、普段何気なく書いてる以下のようなメソッドはインスタンスメソッドです。
しかし、どこにもレシーバーを定義する**self.**の記述はありません。

```ruby
def say
  puts "こんにちは"
end
```

インスタンスメソッドはself.が暗黙的に省略されてるだけで、実際には以下のような形が正確です。

```ruby
def say
  self.puts "こんにちは"
end
```

では以下のようにインスタンス化して、インスタンスメソッドを呼び出してみます。

```ruby
class Class
  def call
    p "#{self}がレシーバーです。"
    self.p "#{self}がレシーバーです。"
  end
end

class Main
  p instance = Class.new
  instance.call
end
```

実行結果を確認すると、selfがインスタンスIDになっていることが確認できました！

```shell
$ ruby instance.rb
#<Class:0x0000564fd89e0498>
"#<Class:0x0000564fd89e0498>がレシーバーです。"
"#<Class:0x0000564fd89e0498>がレシーバーです。"
```

###２．プログラムは原則記述されたコードを上から順番に処理されていく
大前提ではあるのですが、気がついたらこの感覚がなくなってました。
最近はRailsを触ることが多く、プログラムのエントリーポイントとなるようなクラスを触ることがないので、記述する処理はメソッドとして書くことが多く、クラス内の実行順序を意識しなくなっていたようです。

###３．インスタンスメソッドはメソッドを記述したクラス内の各メソッドの記述順序を気にしない。
上記２の話に繋がりますが、今回の学びで一番の気づきは３の部分です。

以下のように改修します。
1. 先程のsayメソッドを呼び出す処理をメソッド化(call)
2. 別クラスからHumanクラスをインスタンス化
3. callメソッドを呼び出す

```ruby
class Human 

# before
#  puts "今から喋ります！"
#  say
#
#  def say
#    puts "こんにちは"
#  end

# after
  def call #1
    puts "今から喋ります！"
    say
  end
  
  def say 
    puts "こんにちは"
  end
end

class Main
  human = Human.new #2
  human.call #3
end
```

以下実行結果：

```
$ ruby human.rb
今から喋ります！
こんにちは
```
メソッド化する前は、sayメソッドを定義する前に同クラス内でsayメソッドを呼び出すとエラーになりました。
しかし、sayメソッドを定義する前にsayメソッドを呼び出すcallメソッドを定義した場合、別クラスでインスタンス化し、callメソッドを実行してもsayメソッドを呼び出すことが出来ます。


###所感
この問題に行き当たった理由は、エントリーポイントとなるプログラムを書いていた際、よく使うメソッドを一連の実行処理のブロックの下にまとめていたのですが、実行してみるとエラーが発生したためです。
これまでなんとなく手続き型言語は１つのファイルを上から下に処理していくもので、オブジェクト指向言語は指定した変数やメソッドを探しだして実行するイメージを持っていましたが、プログラムというのは上から下に流れてくものだってことを改めて認識させられました。

あまりに初歩的で少し恥ずかしい失敗ではありましたが、大怪我する前に学ぶことが出来てよかったです…！