プログラミング漫遊記

思ったことや、勉強したことをつらつらと。

学びながら遊ぶ、Rubyの楽しみ方(オープンクラスで遊ぶ)

現在12月24日です。明日はRubyにとってすごくおめでたい日ということと、アドベントカレンダー part2が空いていたのでこっそり記事を書いてみたいと思います。

travel_to Time.zone.local(2022, 12 05, 00, 00, 00)

この記事は Rubyのカレンダー Advent Calendar 2022 - Qiitaのpart2 5日目の記事です。

qiita.com

テーマ

初学者なりにこんな風にRubyで(を)楽しんでいるぜ!という一例をお伝えできたらと思っています。

フィヨルドブートキャンプ*1在学中、下記の構文を見てどういう仕組みで動いているのか非常に不思議に思いました。

['a', 'b', 'c'].map(&:upcase)
=> ["A", "B", "C"]

そこでこの構文の仕組みを学習してみようと思って、いろいろ遊んだので紹介したいと思います。 こういうふうに遊びながら学ぶのが私なりのRubyの楽しみ方です!という記事です。

仕組み

ざっくりとした説明は以下の通りです

  1. メソッド呼び出しにおいて、引数の先頭に&がついている場合は、暗黙的にto_procメソッドが呼び出される。
  2. 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!!

*1:Rubyなどを学べるプログラミングスクール