Ruby
簡潔に書くシリーズ

Ruby で、とある変な if 文を綺麗に書けるか考えた

言語の機能をなるべく使うという条件で、シンプルに書くことを目指す1


  • 人に読みやすいかということはこだわらない

  • 文字数にこだわるわけでもない


課題



  • fetch_a でオブジェクトが取れればそれの x, y で作れる Hash を、

  • 取れなければ fetch_b を試して取れればそれの x, y で作れる Hash を、

  • どちらもダメなら nil を返す

(空想ではなく、実際に見たコードを一部省略したものです)

if a = fetch_a

{ x: a.x, y: a.y }
elsif b = fetch_b
{ x: b.x, y: b.y }
else
nil
end

if の中で代入するのは rubocop style 的に NG だそうなので、なんとかできないかなと思った。

この課題については、やりたいこと自体がかなり複雑すぎるなので、書き方を改善すればいいという問題ではない気がしたが、気にしない 2


思いついた案


instance_eval使う

(fetch_a || fetch_b)&.instance_eval { { x: x, y: y } }


instance_eval は長いのが嫌いなので tap にしてみる。


instance_evalの代わりにtap

(fetch_a || fetch_b)&.tap { |v| break { x: v.x, y: v.y } }


v の名前づけに悩む(3回書くので、丁寧にすれば長くなるし)が、変わらない文字数でできそう

Ruby 2.7 なら Numbered parameters を使うこともできそう


tap+NumberedParameters

(fetch_a || fetch_b)&.tap { break { x: @1.x, y: @1.y } }






  1. 判定基準はまだうまく言語化できていないです... 



  2. たとえば、 「{ x: x, y: y } を返すメソッドを、 a, b それぞれのクラスに実装する」とか?