RubyのObject
クラスにある割にはそこまで注目されないメソッドの1つに、#tap
があります。使ってみたところ、個人的にはメリットがあるなと思いました。
返り値にするオブジェクトを組み上げる
よく、
def some_method
a = []
a << hoge
a.concat piyo(:fuga)
a[0] = false
a
end
のような、返り値オブジェクトを組み立てるようなメソッドを書く場面がありますが、ときおり最後のa
を書き忘れてでたらめなオブジェクトを返してしまうことがあります(Ruby以外では明示的なreturn
が必要なので、忘れることはふつう起きませんが)。ここにObject#tap
を使うと、
def some_method
[].tap do |a|
a << hoge
a.concat piyo(:fuga)
a[0] = false
end
end
のように、変数の生成部が1つのブロックとなります。これなら返り値を書き忘れるということになりませんし、どこでこの変数を変更しているかもはっきりします。
参考リンク:Object#tapでローカル変数を減らす。
定数の生成
文字列1つとかシンプルな配列なら手間なく生成できるのですが、時にはメソッドを呼んだり、ローカル変数を使ったりして巨大な配列やハッシュの定数を作る必要があるかもしれません。とはいえ、定数を破壊的に変更し続けるのは見栄えが悪いですし、定数定義時に使ったローカル変数が散らばってしまうのもすっきりしないものです。
そこで、tap
を使えばスコープもローカルにできますし、直接定数を変更するということにもならずに済みます。
SOME_CONSTANT = {}.tap do |h|
h.merge! a: 1, b: 3
i = some_method(5)
h[i] = 100
h[i + 80] = 7
h.freeze
end
注意点
性質上、tap
内部ではオブジェクトを破壊的変更で変えていく必要があります(Sring#<<
、Hash#merge!
など)。ブロックパラメータに別なオブジェクトを代入しても、うまく動きません。