現在12月24日です。明日はRubyにとってすごくおめでたい日ということと、アドベントカレンダー part2が空いていたのでこっそり記事を書いてみたいと思います。
travel_to Time.zone.local(2022, 12 05, 00, 00, 00)
この記事は Rubyのカレンダー Advent Calendar 2022 - Qiitaのpart2 5日目の記事です。
テーマ
初学者なりにこんな風にRubyで(を)楽しんでいるぜ!という一例をお伝えできたらと思っています。
フィヨルドブートキャンプ*1在学中、下記の構文を見てどういう仕組みで動いているのか非常に不思議に思いました。
['a', 'b', 'c'].map(&:upcase) => ["A", "B", "C"]
そこでこの構文の仕組みを学習してみようと思って、いろいろ遊んだので紹介したいと思います。 こういうふうに遊びながら学ぶのが私なりのRubyの楽しみ方です!という記事です。
仕組み
ざっくりとした説明は以下の通りです
- メソッド呼び出しにおいて、引数の先頭に&がついている場合は、暗黙的に
to_proc
メソッドが呼び出される。 - symbolにはto_procメソッドがあり、メソッド内部でproc化され任意のタイミングで呼び出される
オレオレmapメソッドをArrayクラスに定義するとわかりやすいと思って、オープンクラスを使って車輪の再発明をしてみました。
using (Module.new do refine Array do def oreore_map(&block) return to_enum(:map) unless block_given? result = [] each do |obj| result << yield(obj) end result end end end) ['a', 'b', 'c'].oreore_map(&:upcase) => ["A", "B", "C"]
メソッド定義の中にデバッガを入れてblock.class
としてみたり、いろいろ試すことで挙動を理解することができました。
遊ぶ
to_proc
が呼び出されることによってprocオブジェクトに変換されているのであれば、to_proc
が定義されているものであれば何でも渡すことができるのかな?という疑問が湧いてきたので、いろいろ実験してみました。こういう実験が面白いです。
hashにはto_proc
というメソッドが定義されているようでした。
https://docs.ruby-lang.org/ja/latest/method/Hash/i/to_proc.html
なるほどkeyからvalueへの変換が簡単にできるんですね。
hash = { a: 100, b: 200, c: 300 } %i(a b c).map(&hash) => [100, 200, 300]
Methodクラスにもto_proc
メソッドが定義されているようです。
https://docs.ruby-lang.org/ja/latest/class/Method.html
method = 123.method(:*) [1, 2, 3].map(&method) => [123, 246, 369]
さらに遊ぶ
いろいろ実験してto_proc
に応じることができるオブジェクトを&と一緒に渡すことができる。ということがわかりました。
さらにこんな衝動に駆られます。
「シンボルじゃなくて、文字列を渡したい!!!!」
ここまでの実験でto_proc
メソッドさえ定義したらうまくいけるのではないか?という自信がついていたので(&文字列)
を渡せるようにしてみました。
注意: Error処理はしてません
using(Module.new do refine String def to_proc Proc.new do |*args, $block| args.shift.send(self, *args, &block) end end end end) 'upcase'.to_proc.call('aaa') => "AAA" ['a', 'b', 'c'].map(&'upcase') => ["A", "B", "C"]
文字列を渡してもうまく動くようになりました!!!
まとめ
このように遊びながら学ぶことでRubyと仲良くなっていく感覚があり、自分なりの楽しみ方になっているので同じ初学者の方などの参考になれば嬉しいです。
travel_back
Ruby.3.2のリリースが楽しみです。(関係者の方ありがとうございます:bow:) Happy Holidays!!