Ruby 2.5 で Object#yield_self というメソッドが追加されます。
https://github.com/ruby/ruby/blob/v2_5_0_preview1/NEWS
https://bugs.ruby-lang.org/issues/6721

定義は簡単で、受け取ったブロックの引数に自身を渡して、そのブロックを評価した結果を返します。

class Object
  def yield_self
    yield(self)
  end
end

簡単な例

"foo".yield_self{|s| s + s}
# => "foofoo"

tap に似ていますが、tap は自身を返すのに対し、yield_self はブロックを評価した結果を返します。

"foo".tap{|s| puts s + s}
foofoo
# => "foo"

今まで yield_self と同じことをするには tap の中で break する必要がありました。

"foo".tap{|s| break s + s}
# => "foofoo"

もっと実際的なケース

https://mlomnicki.com/yield-self-in-ruby-25/ を参考にしました。

GitHub の API にアクセスして、Rails リポジトリのスターの数を調べます。

require 'uri'
require 'net/http'
require 'json'

今までだったら、メソッドを入れ子にして書いたり

JSON.parse(Net::HTTP.get(URI.parse("https://api.github.com/repos/rails/rails"))).fetch("stargazers_count")

中間変数に入れたりしていたケースを

url = URI.parse("https://api.github.com/repos/rails/rails")
res = Net::HTTP.get(url)
data = JSON.parse(res)
data.fetch("stargazers_count")

yield_self を使うとメソッドチェーンで繋いで書いていくことができます。

"https://api.github.com/repos/rails/rails"
  .yield_self { |s| URI.parse(s) }
  .yield_self { |url| Net::HTTP.get(url) }
  .yield_self { |res| JSON.parse(res) }
  .fetch("stargazers_count")

ブロックなら中間変数と違って名前空間を汚すこともありません。

&記法でも書くことができますが、これは反ってわかりにくいかなと思います。

"https://api.github.com/repos/rails/rails"
  .yield_self(&URI.method(:parse))
  .yield_self(&Net::HTTP.method(:get))
  .yield_self(&JSON.method(:parse))
  .fetch("stargazers_count")

名前について

yield_self は長いなと思いました...。
元のissue を見ると、

image.png

みたいに言われたりしていて、他にも

apply, transform, alter, mutate, map, morph, cast

などの名前が候補として挙がっていましたが、結局は最初に提案された yield_self になったみたいですね。issue の議論は途中で途切れていて、最終的に決まった経緯はわかりませんでした。

簡単ですが、以上です!

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.