Rubyっぽく書きたい!!


rubyっぽくないコードをみるとリファクタリングしたくなるわけです。
ちょいちょい、追記していきたい。

case01

before01.rb
def can_use?
  # open_atから一週間以内 || deleted_atから一週間以内
  today = Date.today
  if open_at.present? and deleted_at.present?
    open_at + 7.days > today && deleted_at + 7.days > today
  elsif created_at.present?
    open_at + 7.days > today
  elsif deleted_at.present?
    deleted_at + 7.days > today
  else
    true
  end
end
after01.rb
def can_use?
  return true unless target_date = [open_at, deleted_at].compact.min
  target_date > 1.week.ago
end

考察

  • 日付を引いたり、足したりしてる処理はちゃんとActiveSupport使おう
  • 条件分岐で条件に当てはまらなかったら、早めにreturnすると可読性が上がる
    • 比べるものが存在しない時
  • 同じ条件判定がorで続く場合当てはまるりうるものを、選んでから判定すればDRYになる
    • 日付で以内だったら、minをとってからの判定
  • rubyは条件判定で代入して使うイディオムがあるため、短く書ける
    • 代入文が値を返し、nilfalse以外trueになる性質を利用
  • 基本的にテスト書いてないのにリファクタリングはしちゃダメ

case02

before02.rb
#loop内
next if user.blank?
next if user.is_a?(Admin)
next if user.disabled?
after02.rb
next if user.instance_eval { blank? || is_a?(Admin) || disabled? }

考察
- instance_evalを使えば、レシーバーのスコープ内でいろいろできる
  - instance_evalの使い方として正しいのかはわからないけど、レシーバーを省略してシンプルに書ける
- 条件分岐はorでつなげた方が計算コストも減るし、シンプルになると思う

case03

before03.rb
if article.save
  flash[:notice] = "投稿成功"
else
  flash[:notice] = "入力に間違いがあります"
end
after03.rb
flash[:notice] = if article.save
                   "投稿成功"
                 else
                   "入力に間違いがあります"
                 end

考察
- rubyのif文やcase文は値を返してくれる、インデントなど揃えれば上記のような書き方をした方が個人的に見やすいと思う