LoginSignup
3
2

More than 5 years have passed since last update.

rubyで条件付きメソッドチェーン(tap, try, inject)

Last updated at Posted at 2019-01-29

頭が回転しだして眠れなくなった。

メソッドチェーンしたいけど条件によってはしてほしくないときあるよね。
そういうときになぜだかあまり気が進まないやりかた:

condition = true
n = 0

n = n.next if condition
n = n.next if !condition
n

理由はわからないが気が進まないものは気が進まないので、他の方法を調べてみた。

.tap { break } を使う

https://qiita.com/takeru@github/items/29f9cad9e2318b7e5b82
↑参考

condition = true
n = 0

n.tap { |x| break x.next if condition }.tap { |x| break x.next if condition }
# => 2

n.tap { |x| break x.next if condition }.tap { |x| break x.next if !condition }
# => 1

n.tap { |x| break x.next if !condition }.tap { |x| break x.next if condition }
# => 1

n.tap { |x| break x.next if !condition }.tap { |x| break x.next if condition }
# => 0

ハックっぽさが仕事では使いにくそう。
break しなければレシーバが引き継がれるのが良いところ。

try を使ってみる (rails)

https://stackoverflow.com/questions/33744368/conditionally-call-chained-method
↑の一番下の例。
try にブロックを渡せるのは知らなかった

condition = true
n = 0

n.try { |x| condition ? x.next : x }.try { |x| condition ? x.next : x }
# => 2

n.try { |x| condition ? x.next : x }.try { |x| !condition ? x.next : x }
# => 1

n.try { |x| !condition ? x.next : x }.try { |x| condition ? x.next : x }
# => 1

n.try { |x| !condition ? x.next : x }.try { |x| !condition ? x.next : x }
# => 0

この try が何をしてるかというと引数がブロックのみだったら yield してるだけ。
レシーバは引き継がれないので返してやる必要がある。

配列に入れて inject (reduce)

https://stackoverflow.com/questions/1797189/conditional-chaining-in-ruby
↑の最初の例。

condition = ture
n = 0

l = []
l << :next if condition
l << :next if !condition
l << :next if condition

# l => [:next, :next]

l.inject(n) { |obj, method| obj.send(method) }
# => 2

引数を渡したければ配列で包んで渡してブロックの中でも使ってやれば良い。

l = []
l << [:method, arg1, arg2] if condition

ところで私は確信しておりますが、rubyist が好むのはこれじゃないでしょうか。

3
2
1

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
3
2