Object#yield_self
が導入されます。tap
と違ってyield
の戻り値がそのままyield_self
の戻り値となっています。
class Object
def yield_self(*args)
yield(self, *args)
end
end
引用:https://bugs.ruby-lang.org/issues/6721
class Kernel
def tap
yield self
self
end
end
引用:Rubinius
これを見たときになんとなくパイプライン演算子ぽいなと思いました。Elixirでやるとこんな感じです。
IO.puts "I love Elixir"
|> String.upcase
|> String.reverse
# RIXILE EVOL I と表示されます
もし、Ruby2.5になったらこんな感じにかけます。
class Object
def yield_self(*args)
yield(self, *args)
end
end
puts "I love Ruby"
.yield_self(&:upcase)
.yield_self(&:reverse)
# YBUR EVOL I と表示されます。
Elixirはファンクションの第一引数に次々に値をセットしている一方で、Rubyはyield
の戻り値をチェーンしています。~~プログラミングの幅が広がればよいですが、いまのところベストプラクティスは思いつきません~~と思っていたのですが、頂いたコメントからヒントを得ることができました
tap
ではbreak
を利用して戻り値に無理やりしていたことを自然に書くことが出来ます。文字列や整数の結果をチェーンするのを思いついたのですが、ステップごとに異なるクラスのインスタンスに変化していくときに活躍しそうです!(Elixirでの例とおんなじですね)
require 'net/http'
class Object
def yield_self(*args)
yield(self, *args)
end
end
uri = 'https://www.libertyfish.co.jp/'
puts uri.yield_self(&URI.method(:parse))
.yield_self(&Net::HTTP.method(:get_response))
.code
# ステータスの200が表示される
蛇足ですが、tap
と似たようなものだと思ってyield_self
に渡すブロックで破壊的メソッドを使った場合は思ってたのと違う!というのが起こりそうですね。
class Object
def yield_self(*args)
yield(self, *args)
end
end
puts "HELLO"
.yield_self{|greet| greet.upcase!}
# すでに大文字であれば、`upcase!`の戻り値は`nil`
puts "HELLO"
.yield_self{|greet| greet.upcase}
# すでに大文字であっても、"HELLO"
puts "HELLO"
.tap{|greet| greet.upcase!}
# すでに大文字であっても、"HELLO"
puts "HELLO"
.tap{|greet| greet.upcase}
# すでに大文字であっても、"HELLO"