Effective Rubyを読んで勉強になったこと

## はじめに

Effective Rubyを私が読んで勉強になったことを書いてます。

本書を読んだのは2回目ですが、1回目は何がどう役立つのか全くわかりませんでした。
2回目の今回もいまだに「これって一体どういった場面で効果的なの？」、「そもそも何いってんのこれ？」って部分は多数というかそっちの方が多い気もしますが、以前より「なるほど！」と思った部分があったので、「なんかコーディング力上がってない気がする」って悶々としている人は読んでみると発見があるかもしれません。

本全体の内容を紹介するものではなく
RoRを書いていて、「あ〜こう書けば良かったんだ！」と自分のアンテナに引っかかったところだけを書いていくので、本全体の内容を知りたい方は以下の記事など参照すると良いと思います。
https://qiita.com/fujigaki/items/9d64fa49efcbe7017d8c


## 勉強になったこと

### 項目2 オブジェクトを扱うときにはnilかもしれないことを忘れないようにしよう

```ruby
undefined method 'XXXX' for nil:NilClass(NoMethodError)
```

以前は、RoRしか経験がなく特に気になってませんでしたが、Typescriptではじめて静的型付き言語を触ってから嫌いになったエラーの1つです。
上記のエラーが意図せず発生しないように、nilになる可能性をできる限り排除しましょうってことが大事で、すぐにできることとして

```ruby
[4] pry(main)> nil.to_a
=> []
[5] pry(main)> nil.to_s
=> ""
[6] pry(main)> nil.to_i
=> 0
```
があげられます。
このように型付けがないのをカバーするためにto_aやto_sに代表される変換メソッドを入れておくことでnilが排除されるので、よりエラーが発生しにくいコードになるってことですね。

### 項目8 サブクラスを初期化するときはsuperを呼び出そう

```ruby
[7] pry(main)> class Parent
[7] pry(main)*   attr_accessor(:name)  
[7] pry(main)*   def initialize  
[7] pry(main)*     @name = "サンプル太郎"    
[7] pry(main)*   end    
[7] pry(main)* end  
=> :initialize
[8] pry(main)> 
[9] pry(main)> class Child < Parent
[9] pry(main)*   attr_accessor(:age)   
[9] pry(main)*   def initialize  
[9] pry(main)*     @age = 14    
[9] pry(main)*   end    
[9] pry(main)* end  
=> :initialize
[10] pry(main)> 
[11] pry(main)> child  = Child.new
=> #<Child:0x00007fcf69ed6a08 @age=14>
[12] pry(main)> child.name
=> nil
```

上記のようにChildクラスにParentを継承していた時にChildをnewしてもParentのnameにはアクセスできないんですよね。
最近、これと全く同じことをしてなんでアクセスできない？って思って調べた結果superが必要だったと思い出しました。
「あーこれこの間ハマったやつや！」って思ったので改めて。



```ruby
[13] pry(main)> class Child < Parent
[13] pry(main)*   attr_accessor(:age)   
[13] pry(main)*   def initialize  
[13] pry(main)*     super()    
[13] pry(main)*     @age = 14    
[13] pry(main)*   end    
[13] pry(main)* end  
=> :initialize
[14] pry(main)> Child.new
=> #<Child:0x00007fcf5cfda718 @age=14, @name="サンプル太郎">
```

### 項目11 構造化データの表現にはHashではなくStructを使おう

Typescriptを触っていて例えばUserの配列を作ろうとしたとき

```typescript
type User = {
  id: string
  name: string
  address: string
}
const users: User[] = []
```

Userって型を作ってその配列だよ！って型宣言してたんですが、これと似たようなことだと認識してます。

```ruby
[2] pry(main)> sample_users = [
[2] pry(main)*   { id: "1", name: "太郎", age: 8, nickname: "とっとこ太郎" }, 
[2] pry(main)*   {id: "2", name: "花子", age: 11, nickname: "トイレの花子"} 
[2] pry(main)* ]  
=> [{:id=>"1", :name=>"太郎", :age=>8, :nickname=>"とっとこ太郎"}, {:id=>"2", :name=>"花子", :age=>11, :nickname=>"トイレの花子"}]
[3] pry(main)> 
[4] pry(main)> array = []
=> []
[5] pry(main)> 
[6] pry(main)> sample_users.each do |user|
[6] pry(main)*   array << { name: user[:name], nickname: user[:nickname] } 
[6] pry(main)* end  
=> [{:id=>"1", :name=>"太郎", :age=>8, :nickname=>"とっとこ太郎"}, {:id=>"2", :name=>"花子", :age=>11, :nickname=>"トイレの花子"}]
[7] pry(main)> 
[8] pry(main)> array[0][:missing]
=> nil

```
見て分かる通り、missingなんてkeyがないので、本来ならエラー発生してほしいんですが、nilが返ってきてしまいます。
これだと仮にタイポしてたとしても気づかないってことが。
それを防ぐために、Structで型を定義してそれをarrayに詰めようって話ですね。

```ruby
[19] pry(main)> SampleUser = Struct.new(:name, :nickname)
=> SampleUser
[23] pry(main)> array = []
=> []
[24] pry(main)> sample_users.each do |user|
[24] pry(main)*   array << SampleUser.new(user[:name], user[:nickname])
[24] pry(main)* end  
=> [{:id=>"1", :name=>"太郎", :age=>8, :nickname=>"とっとこ太郎"}, {:id=>"2", :name=>"花子", :age=>11, :nickname=>"トイレの花子"}]

[26] pry(main)> array
=> [#<struct Sample name="太郎", nickname="とっとこ太郎">, #<struct Sample name="花子", nickname="トイレの花子">]
[28] pry(main)> array[0]
=> #<struct Sample name="太郎", nickname="とっとこ太郎">
[29] pry(main)> array[0][:missing]
NameError: no member 'missing' in struct
[30] pry(main)> array[0][:name]
=> "太郎"
[31] pry(main)> array[0].name
=> "太郎"
[32] pry(main)> array[0].missing
NoMethodError: undefined method `missing' for #<struct Sample name="太郎", nickname="とっとこ太郎">
from (pry):36:in `<main>'
```
なるほど、nilが返ってこなくなりエラーが発生！これはいいですね！


### 項目19 reduceを使ってコレクションを畳み込む方法を身に付けよう

```ruby
users = [{ name: "太郎", age: 22 }, { name: "花子", age: 11 }, { name: "大吉", age: 55 }]
```

ここから21才以上ののname取り出したい時って

```ruby
[45] pry(main)> users.select { |u| u[:age] >= 21}.map{|u| u[:name]}
=> ["太郎", "大吉"]
```
って書くと思うのですが、これってselectで21才以上の新しい配列を作ってさらにそこにnameだけを抽出した新しい配列をつくるという無駄な処理があります。

ここでreduce使うと

```ruby
[48] pry(main)> users.reduce([]) do |names, user|
[48] pry(main)*   names << user[:name] if user[:age] >= 21  
[48] pry(main)*   names
[48] pry(main)* end  
=> ["太郎", "大吉"]
[49] pry(main)> 
```

うん。シンプル。注意としてはアキュムレーターををしっかりとブロックの中で返してあげることですね。


## 感想

2回目読んでみましたが、リファクタリングに使えそうなTipsがあって読んで良かったと思います。
正直、第５章メタプログラミングと第8章メモリ管理とパフォーマンスは、どこで使うのか？、そもそも何いってるかようわからんって部分が大半だったので次本書を手にするときは「なるほど！」って思いたいところです