0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ぼっち演算子とnil?、blank?を組み合わせるとnilのときに結果が逆になる罠

Posted at

考えてみればそのとおりだけども、ちょっとハマったのでメモがてら。

ぼっち演算子についてはsafe navigation operator (ぼっち演算子)を参照。

rubyのぼっち演算子が便利なのでよく使うのですが、
条件分岐させるときに注意が必要です。

# hogeはnameというインスタンス変数を持つオブジェクトとします
hoge.name.blank? ? '空です' : '空じゃないです'

みたいな判定のときに

hoge.name = '値あり'
hoge.name&.blank?  ? '空です' : '空じゃないです'
#=> '空じゃないです'

hoge.name = ''
hoge.name&.blank?  ? '空です' : '空じゃないです'
#=> '空です'

hoge.name = nil
hoge.name&.blank?  ? '空です' : '空じゃないです'
#=> '空じゃないです' # 思ってたのと違う!!

のようにnameがnilのときに期待と逆の結果になります。
ぼっち演算子は「オブジェクトがnilじゃないときにメソッドを呼び出す」という動きなので、
nilのときはblank?を呼び出さないためnilが返り、nilはfalsyなのでfalseのときの結果を返します。

そもそもnil?blank?もnilが使えるメソッドなので素直に

hoge.name.blank? ? '空です' : '空じゃないです'

と書けばOKです。

empty?はnilが持ってないので、ぼっち演算子が必須ですが、

hoge.name&.empty? ? '空です' : '空じゃないです'

だと、hoge.nameがnilのときは「空じゃないです」が返って、ブランクのときは「空です」が返るという直感的じゃない動きをします。
empty?使うときってnilチェックしているかと思うのでこの罠には引っかからないかと思いますが。

ちなみにpresent?だと、結果オーライな感じになります。

hoge.name = '値あり'
hoge.name&.present? ? '空じゃないです' : '空です'
#=> '空じゃないです'

hoge.name = ''
hoge.name&.present? ? '空じゃないです' : '空です'
#=> '空です'

hoge.name = nil
hoge.name&.present? ? '空じゃないです' : '空です'
#=> '空です'

&ひとつだけの違いだし、パッと見で気づきにくいのでレビューで見落としがちだったりします。
あらためてrspecとか大事だなと思いました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?