動機
この記事はもともとLegalForceさんで行われたイベントのために調べ物をしていたのでそれを再利用したものです。
私はRubyの最大の強みの一つはブロックの表現力だと思うのですが、この記事ではそんなブロックを(実は)引数に受け取るメソッド群を紹介したいと思います。
本編
但し書き
今回はコアクラス(String
, Array
, Hash
)のみに絞って紹介しています。
明らかにブロックを受け取ると思われるもの(例:each系のメソッド)などは除外されています。
その他、明らかに使い途がないと個人的に思われたものも除外しています。
String
String#gsub
個人的に意外だったものの筆頭は、gsub
とgsub!
がブロックを受け取ることです。以下のように使います。
'hoge'.gsub(/[aiueo]/) {|match| match * 2 } # => hoogee
これはかなり便利そう。
String#match, Regexp#match
match
は正規表現に対して呼ぶのが王道な気はしますが、どちらもブロックを受けることができます。
str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
str.match(/^(.+) (.+)/) {|match| puts match[2] }
# "elit."が出力される
String#scan
存在自体を知らない人も多いであろうscan
メソッド。match
の同じようなブロックの使い方ができます。
str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
str.scan(/\w+/) {|word| print "*#{word}*"}
# "*Lorem**ipsum**dolor**sit**amet**consectetur**adipiscing**elit*"が出力される。
Array
Array.new
今知ったのですが、Array.new
はブロックを受けることができるようです。
Array.new(3) {|index| index ** 2} # => [0, 1, 4]
いつ使うんだろ…
Array#count
メジャーなメソッドであるcount
も実はブロックを受け取ります。
ary = (0..10).to_a
ary.count {|e| e.even? } # => 6
これはとてもRuby的で綺麗だと思います。
Array#fetch
Hash#fetch
と比べると使う機会は少ないですが、配列にもfetch
メソッドがあります。
ary = (0..10).to_a
ary.fetch(100) {|i| puts "#{i} is out of range" }
# "100 is out of range"が出力される。
Array#index
ブロックがtrueを返す最初のインデックスを返します。こんなものあるんだ…
ary = (0..10).to_a
ary.index {|i| i.odd? } # => 1
Array#to_h
to_h
ってブロック受け取れるんだ…!
ary = (0..10).to_a
ary.to_h # => TypeError
ary.to_h {|e| [e.to_s, e ** e]} # => {"0"=>1, "1"=>1, "2"=>4, "3"=>27, "4"=>256, "5"=>3125, "6"=>46656, "7"=>823543, "8"=>16777216, "9"=>387420489, "10"=>10000000000}
何かに使えそう。
Hash
Hash#merge
これもすごく便利だと思ったやつで、ハッシュ同士を合体させるときにキーがコンフリクトしたものの処理をブロックで行うことができます。
h1 = {a: 1, b: 2}
h2 = {b: 3, c: 4}
h1.merge(h2) {|key, old, new| old + new} # => {:a=>1, :b=>5, :c=>4}
Hash#to_h
最初はよく意味がわからなかったのですが、Hash#to_h
はブロックを受け取るとキーバリューペアをブロック引数として返り値の配列を新しいハッシュとすることができるようです。
{foo: 42}.to_h {|k, v| [k.upcase, v * 2]} # => {:FOO=>84}
これは実質map
しているということなのでしょうか…
まとめ
今回はコアクラスに絞ってブロックを受け取るメソッドを紹介しました。他にももちろんまだまだあるので、ぜひご自身で調べてみてください。