読者です 読者をやめる 読者になる 読者になる

プログラミング 美徳の不幸

Ruby, Rails, JavaScriptなどのプログラミングまとめ、解説、備忘録。

rubyの真偽値の話

rubyではご存知の通りfalseとnil以外は真と評価される。

例えばこういうコードがあったとして

class Project < ActiveRecord::Base
  def completed?
  end
end

projectsというテーブルにはDATETIME型のcompleted_atというカラムがあったとします。
completed_atにはプロジェクトの完了日時が入り、完了日時が入っていれば完了したと判断できるとしてこのときのProject#completed?の実装はどうしますか?

だいたいこういう選択肢に別れると思います。

1. 実装しない

そもそも単純な話入っていれば終了したとみなせるのだから不要なメソッド

2. そのままcompleted_atを見る

つまり

def completed?
  completed_at
end

3. completed_atをtrue/falseに変換する

def completed?
  !!completed_at
end

人によって考え方は違うと思うんですが、僕はどう考えても3つ目のtrue/false変換がスジがいいと思うんですよね。

1は程度問題なんですが、ロジックではなくデータを参照しているのが気に入りません。まぁこの程度ならいいかもしれませんが、こういうコード見たことないですか?

- if @project.owner == current_user
  = link_to '編集'

僕も昔こういうコード書いててこう書いたほうがいいよって言われたことがあります。

- if @project.editable_by?(current_user)
  = link_to '編集'

2は際どいですが、厳密には真とみなされるオブジェクトとtrueにも違いがあって
true == trueはtrueですが
'anyobject' == trueはfalseです。

その結果、確かrspecのbe_trueとかのマッチャの結果が変わったと思います。

ただ、3に対しても批判があってそのやり方はrubyの仕様的にどうなのっていう意見があります。
そのあたりの議論はここを見ればいいんですがgithub.com

この場では明らかに2のほうがruby的だって言われてます。

うーん、そうなのかなぁ苦笑