RailsConf2015 - Nothing is Something by Sandi Metz　前半のメモ

[BathRuby 2015 - Nothing is Something by Sandi Metz　前半のメモ]
(http://qiita.com/TakaakiFuruse/items/59708a2c8b0a36f27c12)の二度目の講演｡

著者が別のところのインタビューで「ちょっとアップデートした」と言ってたので見てみた｡スライドがちょっと変わってた｡以前とは大きく内容が変わったわけではない｡二度目の鑑賞｡今回はビデオを見ながらRailsでやってみた｡

どうも内容の簡略化のために実際は動かないメソッドなども使われているようなので､ちょっと内容を変えてある｡

IF statements解説から始まった｡これを再定義をしてみるらしい｡
(構造を見るためにやってるわけでこうしろというわけではない)

```ruby:
class Object
  def if_true
    yield
    self
  end

  def if_false
    self
  end
end

class FalseClass
  def if_true
    self
  end

  def if_false
    yield
    self
  end
end

class Nilclass
  def if_true
    self
  end

  def if_false
    yield
    self
  end
end

"test".if_true{p "evaluated block"} # => "evaluated block"
"test".if_false{p "evaluated block"} # nothing

nil.if_true{p "evaluated block"} # => return block
nil.if_false{p "evaluated block"} # => return nothing
```

SmallTalkっぽく書いてみると以下のようなことができるらしい｡
これも｡「できるよ」､というだけでこうしろというわけではない

```ruby:
if (1==1)
  p "is true"
else
  p "is false"
end
# => true

(1==1).if_true{p "true"}.if_false{p "false"}
# => true

(2==1).if_true{p "true"}.if_false{p "false"}
# => false
```

#ここからRailsのコンソール上でやること
環境はハートルの[SampleApp](https://github.com/mhartl/sample_app_3rd_edition)を使った｡

↓こういう形式でユーザーが登録されてるとする

```ruby:
=> [#<User:0x007fc78089fbf8
    id: 1,
    name: "12345",
    email: "a@a.com",
    created_at: Sat, 11 Jul 2015 09:38:11 UTC +00:00,
    updated_at: Sat, 11 Jul 2015 09:38:11 UTC +00:00,
    password_digest: "$2a$10$/TywdUFH6kYf.....4ZT0x3GoOFVjrR0quBK",
    remember_digest: nil,
    admin: false>
```

ID 1 から　ID　3 まで呼び出してみる｡

```ruby:
    ids = ["1","","3"]
    # => [1, 2, 3, 4, 5]
    users = ids.map{|id| User.find_by(id: id)}
    # => ユーザーが3つ帰ってくる.ひとつはNil

    users.each{|user| p user.name}
    # => NoMethodError: undefined method...
    # NilがあるのでNilに当たるとうまく帰ってこない

    # じゃあ事前にNilを消しておこう
    users = ids.reject(&:empty?).map{|id| User.find_by(id: id)}
    #=> return users with id: 1 and id: 2
    
　　users.each{ |user| p user.name }
    #=> Nilが消えたのでユーザー名がちゃんとプリントできた.

   
    ids = ["1","","3"]
```

### "If you sending a message, nil is something."


このとき

```ruby:

    users = ids.map{|id| User.find_by(id: id)}
    #↑こうすることもできる

    users.each{|u| p u.nil? ? "no such user" : u.name}
    # 二番目の nil が "no such user"になった

    #小汚いので↓こうすることもできる､ただNilがそのまま出る
    users.each{|u| p u && u.name}

    #あんまりよろしくないがrailsだと↓こう､Nilはそのまま出る
    users.each{|u| p u.try(:name)}

    # each内はようするにみんな同じことをしている｡一番下がおおもとのやつ
    p u.try(:name)
    p u.nil? ? "no such user" : u.name
    p u == nil ? "no such user" : u.name
    p u.is_a(NilClass) ? "no such user" : u.name
```
 
一番下のやつは結局これ↓

```ruby:

    if u.is_a? (NilClass)
      p "no such user"
    else
      p u.name
    end
```

↑は
↓これと同じ

```ruby:
    class Nilclass
      def if_true
        self
      end

      def if_false
        yield
        self
      end
    end
```

これで動くけどConditionはどんどん増えていく｡
よくない､メッセージだけおくれたらいいじゃん

```ruby:
#まず rails generate heleper UserNotFound して以下を作る
    module UserNotFoundHelper
      class Notfound
        def name
          "no such user"
        end
      end
    end

#で､
    include UserFindHelper
    ids = ["1","","3"]
    users = ids.map{|id| User.find_by(id: id) || Notfound.new}

```

NilだとNilの代わりにオブジェクトがかえる｡まだConditionalがあるし､Dependencyが追加されたが､IfからBehaviorを取り除けた｡ p "｡｡｡｡" だけになった｡


```ruby:
users = ids.map{|id| User.find_by(id: id) || Notfound.new.name} 
```

↑をするとusersをIterateすればメッセージが帰ってくるようにできる｡

この一連のやり方をActive Nothing と呼ぶらしい
も少しリファクターしてみる

```ruby:
 # User と Notfound を GuaranteedUser にwrapしてしまう

    module UserNotFoundHelper
      class Notfound
        def name
          "no such user"
        end
      end
      class GuaranteedUser
        def self.find(idnum)
          User.find_by(id: idnum) || Notfound.new
        end
      end
    end
```

で↓こうやって呼ぶ｡スゴイスッキリ

```ruby:
    include UserNotFoundHelper
    ids = ["1","","3"]
    users = ids.map{|id| GuaranteedUser.find(id)}
    users.each{|u| p u.name}
    #=> "12345"
    #  "no such user"
    #  "Albin Robel"
```

おわり