動かして学ぶrubyのアクセサメソッドの使い分け＆エラー解決の近道のお話

# はじめに
どうもこんにちは～
クラスを書く時に必要なフィールド変数
最初は```attr_accessor```メソッドで良いだろうと高を括っていました。
調べていくうちにオブジェクト指向のカプセル化にも関わってくる重要な項目だと分かったので
自分への備考禄＆知らない方へのヒントになればいいなと思い記事を書きました。
物凄く記事が長いです。お時間があるときに読むことをおすすめします。

# この記事の対象読者
・Ruby初学者の方
・取り合えずインスタンス化までは出来るぞって方
・アクセサメソッド知ってるけど使い道が分からない方

# 動かして学んでみよう
動かしながら学んでいってみましょう。この後提示するクラスの内容はどうでもいいので
コピペしてもらって結構です。しかしアクセサの理解があやふやな方はターミナルでの実行は必ずしておいてください。動かして「どういった動きをするのか」を見ておくのと見ておかないとでは大違いです。この機会に「動かす習慣」を付けてみてください。一緒に頑張りましょう。

# 目次
[アクセサメソッドとは](#アクセサメソッドとは)
・実験してみよう
[アクセサメソッドなし](#アクセサメソッドなし)
[attr_reader](#attr_reader)
[attr_writer](#attr_writer)
[attr_accessor](#attr_accessor)
・考察してみよう

### アクセサメソッドとは
アクセサメソッドとは
3種類あります
```
attr_reader （読み取りできるぞ）
attr_writer （書き込みできるぞ）
attr_accessor (どっちもできるぞ)
```
ざっくりできることはこんな感じだって頭の片隅に入れといてください。


### アクセサメソッドなし
例えば「1～n番目まで順番に入る配列を作れる」クラスを作ったとします。
アクセサメソッドを一旦全部書いてみましょう。
  ```attr_reader :array```
  ```attr_writer :array```
  ```attr_accessor :array```
そして全部コメント化してください。
実験していきます。

```rb
class NumberArrayMaker
  #attr_reader :array
  #attr_writer :array
  #attr_accessor :array
  
  def initialize(number)
    @array = make_number_array(number)
    #[1,2,3,4...,number]の配列が入る
  end

  def make_number_array(number)
    number_array = []
    
    (1..number).to_a.each do |n|
      number_array << n
      #[1,2,3,4...,number]までの配列をメソッド内変数に格納
    end
    number_array
    #できた配列返すよ～
  end
end
```

クラス自体はどうでもいいです。取り合えずインスタンス化して
インスタンスの中身を参照見てみましょう。
インスタンスの中身の変数やメソッドの参照は
```インスタンス.インスタンス変数名 or インスタンスメソッド名```で見れます。
前にpやputなどで出力することをお忘れなく。ではやってみましょう。
```rb
create_array = NumberArrayMaker.new(12)

p create_array.array
#=> `<main>': undefined method `array' for #<NumberArrayMaker:0x000001afe08edb90 @array=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]> (NoMethodError)
```
見れませんね。エラーが出ます。エラー文も読んでみましょう。
エラー内容は
「arrayなんて名前のメソッドないぞ」と怒ってますね。
今のところ分かったことは「アクセサメソッド無しだと参照はできない」ということが分かりました。一歩前進です。それでは
「代入」の方はどうでしょうか。
インスタンス変数に代入するには
```インスタンス.インスタンス変数名 = "値"```
で代入出来ます。やってみましょう。
```rb
p create_array.array = ["すし", "いなりずし", "ふなずし"]
#=><main>': undefined method `array=' for #<NumberArrayMaker:0x000001d1434d4ea8 @array=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]> (NoMethodError)
```
やっぱり見れませんね。エラーが出ます。エラー文も読んでみましょう。
エラー内容は
「arrayなんて名前のメソッドないぞ」と怒ってますね。同じですね。
これで「アクセサメソッド無しだと代入はできない」ということが分かりました。

:::note info
アクセサメソッドなし
「参照や代入しようとしても、『メソッドがないぞ』と怒られる。」
:::

### attr_reader
はい。では```attr_reader```のコメント化を解除してください
```rb
class NumberArrayMaker
  attr_reader :array
  #attr_writer :array
  #attr_accessor :array
  
  def initialize(number)
    @array = make_number_array(number)
    #[1,2,3,4...,number]の配列が入る
  end

  def make_number_array(number)
    number_array = []
    
    (1..number).to_a.each do |n|
      number_array << n
      #[1,2,3,4...,number]までの配列をメソッド内変数に格納
    end
    number_array
    #できた配列返すよ～
  end
end
```

やることはさっきと同じです
まずは```create_array.array```の「参照」からチェックしていきます
```rb
p create_array.array
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
```
お、出ましたね！
どうやら今回は参照出来たようです。
これで「attr_reader」を付けると「参照することができる」
事が分かりました。
次は「代入」です。
```rb
p create_array.array = ["すし", "いなりずし", "ふなずし"]
#=> undefined method `array=' for #<NumberArrayMaker:0x00000207871d70c8 @array=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]> (NoMethodError)
```
はい。親の顔より見たエラーです。めんどくさいと思うかもしれませんが絶対にエラーは読むようにしましょう。```undefined method `array=` (NoMethodError)```つまりこれも
「arrayって名前のメソッドが何処にもないぞ」と怒っているわけですね。
ではまとめていきます

:::note info
attr_reader
「参照は出来た。代入しようとすると『メソットがないぞ』と怒られる」
:::

### attr_writer
はい。では```attr_reader```をコメント化し
はい。では```attr_writter```のコメント化を解除してください
```rb
class NumberArrayMaker
  # attr_reader :array
  attr_writer :array
  #attr_accessor :array
  
  def initialize(number)
    @array = make_number_array(number)
    #[1,2,3,4...,number]の配列が入る
  end

  def make_number_array(number)
    number_array = []
    
    (1..number).to_a.each do |n|
      number_array << n
      #[1,2,3,4...,number]までの配列をメソッド内変数に格納
    end
    number_array
    #できた配列返すよ～
  end
end
```
同じことを繰り返していきます。先ずは「参照」から
地道に、地道にやっていきます。
```rb
p create_array.array
#=> `<main>': undefined method `array' for #<NumberArrayMaker:0x0000018279c8d078 @array=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]> (NoMethodError)
```
エラーを見ていきます。```undefined method `array'(NoMethodError)```
これもarrayメソッドがない為呼び出せずエラーが出ていますね。
それでは「代入」はどうでしょうか
これで「参照」はできないことが分かりました。
```rb
p create_array.array = ["すし", "いなりずし", "ふなずし"]
#=> ["すし", "いなりずし", "ふなずし"]
```
出来ましたね！代入が出来ることが分かりました。
それではまとめましょう

:::note info
attr_writer
「代入することは出来た。参照しようとすると『メソットがないぞ』と怒られる」
:::
どうですかね。長かったですが「何が問題」かわかってきたんじゃないですかね。
さあ、次で最後ですよ。

### attr_accessor
それでは```attr_writer :array```をコメント化してください
 ```attr_accessor :array```のコメント化を解除してください
```rb
class NumberArrayMaker
  # attr_reader :array
  # attr_writer :array
  attr_accessor :array
  #[1,2,3,4...,number]の配列が入る
  
  def initialize(number)
    @array = make_number_array(number)
  end

  def make_number_array(number)
    number_array = []
    
    (1..number).to_a.each do |n|
      number_array << n
    end
    number_array
  end
end
```
では「参照」から…
```rb
p create_array.array
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
```
実行できますね。
それでは「代入」はどうかな…
```rb
p create_array.array = ["すし", "いなりずし", "ふなずし"]
#=> ["すし", "いなりずし", "ふなずし"]
```
両方とも出来ましたね！
ではまとめていきます

:::note info
attr_accessor
「参照は実行できた。代入も実行できた」
:::

# 考察してみよう
皆さんお疲れ様でした！これでアクセサメソッドの「実験」は終わりです。
長かったですよね。でも大事なことです。なぜなら実験結果から「仮説」「考察」をつけ
「何が問題だったのか」の「あたり」を付けることができるからです。
実際に考察してみましょう！
実験結果は以下の通りです

:::note info
アクセサメソッドなし
「参照や代入しようとしても、『メソッドがないぞ』と怒られる。」
:::

:::note info
attr_reader
「参照は出来た。代入しようとすると『メソットがないぞ』と怒られる」
:::

:::note info
attr_writer
「代入することは出来た。参照しようとすると『メソットがないぞ』と怒られる」
:::
:::note info
attr_accessor
「参照は実行できた。代入も実行できた」
:::

それではエラーが起きたときの共通項から考えていきましょう
エラーが起きたときには必ず「メソッドがない」とエラーが出ますね。
つまりここで考えられるのは「アクセサメソッドはメソッドと関連しているんだろう」と「あたり」がつけられます。
もっと言うと「メソッドを作ってるんじゃね？」ってところまで考察できるはずです



# ネタばらし
クラスに以下のメソッドを追加してください
アクセサメソッドはもういりません。コメント化するか削除してください
```rb
  def array
    @array
  end

  def array=(value)
    @array = value
  end
```

これで以下を実行してください
```rb
p create_array.array
p create_array.array = ["すし", "いなりずし", "ふなずし"]
```
どうですか。分かりましたか？
つまり本当にただメソッドが無かったということが分かったと思います。
```rb
  def array
    @array
  end
```
これは「attr_reader」が自動で作ってくれていました
```rb
  def array=(value)
    @array = value
  end
```
これは「attr_writter」が自動で作ってくれていました
そして「attr_accessor」はどちらも同時に作ってくれていたんですね。

# エラー解決の近道のお話
お疲れ様でした。大変だったと思います。途中から「言いたい事分かったよ。同じ事何度も何度もくどいよ」と思った方もいるかもしれません。
しかし僕がここで皆さんにお伝えしたかったのは
分からないことを何となくではなく「なぜそうなのか」をテストし、考察する過程を踏むことで
「それが何なのか」が分かるようになるということです。
確かにchatGPTに頼れば簡単に答えを教えてくれるかもしれませんし、「これってどういう意味？」と聞けば調べずともそれが何か教えてくれます。
でもchatGPTが使えなくなったらどうでしょう、自力で書けますか？自分で調べたこともテストしたこともないのに問題解決できますか？と僕は考えています。
実験し、問題点を洗い出し、考察し、あたりを付けて直してみる
この繰り返しがプログラミング学習の近道なのではないかと僕は思っています。
泥臭く、地味で地道な作業です。でもその先に「作ってくれてありがとう」そう言ってくれる人が
いると思うと「今日も頑張ろう」と勉強に熱が入ります。
僕はプログラミングし始めてまだ3か月程度の初心者ですが同じ境遇の方、これから始めようとしている方。頑張っていきましょう。