バナー画像

普段は使うことはないけど、「tap」というメソッド名は耳にしたことがある人は少なくないでしょう。

元々はメソッドチェーンの途中経過を見るためのデバッグ目的で作られたAPIですが、それ以外の用途で活用もできる、おもしろいメソッドです。この記事では Rubyの「tap」メソッドの使い方について掘り下げていきたいと思います。

tapメソッドとは?

冒頭でも述べましたが、「tap」はメソッドチェーンの中に入り込んでデバッグ等をするためのメソッドとして主に使用します。

Rubyの「tap」メソッドは、公式ドキュメントでは「self を引数としてブロックを評価し、self を返します。」と概要で紹介されています。

【公式リファレンス】instance method Object#tap

これだけ読んだだけでは、なかなか理解が難しいメソッドですね。実際にサンプルコードを見ながら「tap」メソッドの使い方を確認しましょう。

tapの基本

次のサンプルコードは、配列を降順で並び替えるコードです。(注:まだtapは使っていません)

p [40, 30, 10, 30, 50]
   .sort
   .reverse
#=> [50, 40, 30, 30, 10]
ポテパンダの一言メモ

Rubyには、配列を降順で並び替える直接的なメソッドはないため、sortで配列を昇順で並び替えた後、reverseメソッドで配列を反転させて降順でのソートを実現します。

次に「sort」と「reverse」メソッドの後に「tap」メソッド挟んで、配列が昇順でソートされたタイミングと、配列を反転して降順でソートしたタイミングで内容を画面に出力します。

[40, 30, 10, 30, 50]
   .sort
   .tap{|array| p array}
   .reverse
   .tap{|array| p array}
実行結果
-------------------
[10, 30, 30, 40, 50]
[50, 40, 30, 30, 10]

上のコードの呼び出し階層をイメージにすると、次のようになります。

「tap」メソッドのブロックには、「tap」メソッドを呼び出したレシーバー自身が引数に渡されるため、ここでは昇順でソートされた配列がブロックの引数に渡されます。
そして「tap」メソッドは、レシーバーをそのままメソッドの結果として返すため、昇順でソートされた配列が、そのまま次の「reverse」メソッドに受け渡され、それ以降の「tap」メソッドも同様の動きになります。

このように「tap」メソッドは、指定したブロックを実行し、処理結果に関係なくレシーバ自身を返すため、メソッド全体の結果に影響を及ぼすことなく、メソッドチェーンの途中で変数の値の確認するなどのデバッグで利用されます。

これで Rubyの「tab」メソッドの処理内容が少し分かって頂けたのではないでしょうか。

tapとbreak使ったテクニック

「tap」メソッドは、元々はメソッドチェーンの途中の過程をデバッグするために作られたAPIですが、「tap」と「break」を組み合わせて使うことで、ブロックの評価結果を「tap」の戻り値と返すことができ、おもしろい処理を組むことができます。

まずは簡単な例で「break」を使ってブロックの処理を抜けると、どんな結果になるのか確認してみます。

value = 10
p value.tap{|x| break x * 2 }
実行結果
-------------------
20

このように、通常「tap」はレシーバー(呼び出し元のオブジェクト)を戻り値に返しますが、「break」でブロックを抜けると、ブロックの評価結果が「tap」メソッドの戻り値として返されます。

これを利用して、次のような処理を書けます。

変数に値を代入しつつ値を取得

ハッシュへの値の代入と、代入した値の取得を同時に行います。

次の例では、ハッシュ型の変数「hash」をレシーバーに「tap」メソッドのブロックで値を代入します。そして、ブロックの評価結果にはハッシュに格納した値が評価結果として返されます。

hash = {}
value = hash.tap{ |h| break h[:key] = 55 }
p value
実行結果
-------------------
55

HTTPのアクセスをパイプラインで実装

パイプラインで次々と「tap」メソッドの処理結果を、次の「tap」メソッドに渡していくことで、RubyでREST APIなどからJSONデータを取得する処理を、次のようにシンプルに記述することが可能です。

require 'open-uri'
require 'json'

url = "https://exsample.com/getaddress?zipcode=7830060"

json = url.
  tap {|url| break URI(url).read }.
  tap {|response| break  JSON.parse(response) }

nil以外の時に処理を実行

次のサンプルコードのように、変数の値がnil以外の時だけメソッドを実行するのは、よくある実装パターンです。

strA = "Ruby"
strB = nil

if !strA.nil?
  p strA.upcase
end 

if !strB.nil?
  p strB.upcase
end
実行結果
-------------------
"RUBY"

上のサンプルコードは「tap」メソッドを使うことで、次のコードのように、もっとシンプルに書き換えることができます。

strA = "Ruby"
strB = nil

strA = strA&.tap{|x| p x.upcase}
strB = strB&.tap{|x| p x.upcase}
実行結果
-------------------
"RUBY"

このよう感じに&.演算子を使用すると、レシーバーがnilの場合、それ以降のメソッドを評価しないため、変数の値がnil以外の時だけ、指定した処理を実行したいといったケースで利用できます。

thenでもっとスッキリと

Ruby 2.6では「then」メソッドが追加されました。このメソッドは、レシーバを引数としてブロック実行し、その評価結果をメソッドの戻り値として返します。

つまり「tap」と「break」を組み合わせて実現していた処理が、「then」メソッドでbreakキーワードなしに普通に書けるようになり、さらにスッキリとしたコードになります。

value = 10
p value.then{|x| x * 2 }
実行結果
-------------------
20

先ほど紹介した、RubyでREST APIなどからJSONデータを取得するような処理も「then」を使うともっとスッキリします。

require 'open-uri'
require 'json'

url = "https://exsample.com/getaddress?zipcode=7830060"

json = url.
  tap {|url| URI(url).read }.
  tap {|response| JSON.parse(response) }

さいごに

普段はあまり使わないけど、知っていれば以外と便利な「tap」メソッドと、Ruby 2.6で追加された「then」メソッドの使い方を解説してきました。

特に「then」メソッドは、メソッドチェーンでさまざまな処理を繋げることができ、これまで煩雑な書かれていたプログラムコードが、「then」を使うことでスッキリとしたコードにできる可能性を秘めています。

【関連記事】
【Ruby入門】mapメソッドの使い方と応用例

エンジニアになりたい人に選ばれるプログラミングスクール「ポテパンキャンプ 」

ポテパンキャンプは卒業生の多くがWebエンジニアとして活躍している実践型プログラミングスクールです。 1000名以上が受講しており、その多くが上場企業、ベンチャー企業のWebエンジニアとして活躍しています。

基礎的な学習だけで満足せず、実際にプログラミングを覚えて実践で使えるレベルまで学習したいという方に人気です。 プログラミングを学習し実践で使うには様々な要素が必要です。

それがマルっと詰まっているポテパンキャンプでプログラミングを学習してみませんか?

卒業生の多くがWebエンジニアとして活躍

卒業生の多くがWeb企業で活躍しております。
実践的なカリキュラムをこなしているからこそ現場でも戦力となっております。
活躍する卒業生のインタビューもございますので是非御覧ください。

経験豊富なエンジニア陣が直接指導

実践的なカリキュラムと経験豊富なエンジニアが直接指導にあたります。
有名企業のエンジニアも多数在籍し品質高いWebアプリケーションを作れるようサポートします。

満足度高くコスパの高いプログラミングスクール「ポテパンキャンプ」

運営する株式会社ポテパンは10,000人以上のエンジニアのキャリアサポートを行ってきております。
そのノウハウを活かして実践的なカリキュラムを随時アップデートしております。

代表の宮崎もプログラミングを覚えサイトを作りポテパンを創業しました。
本気でプログラミングを身につけたいという方にコスパ良く受講していただきたいと思っておりますので、気になる方はぜひスクール詳細をのぞいてくださいませ。