パターンマッチと右代入が便利になる gem をつくった

3931098ae486b6df619050c63e24f6cc?s=47 osyo
November 05, 2020

パターンマッチと右代入が便利になる gem をつくった

3931098ae486b6df619050c63e24f6cc?s=128

osyo

November 05, 2020
Tweet

Transcript

  1. Omotesando.rb #56 Omotesando.rb #56 パターンマッチと右代⼊が パターンマッチと右代⼊が 便利になる gem をつくった 便利になる

    gem をつくった
  2. ⾃⼰紹介 ⾃⼰紹介 名前:osyo Twitter : github : ブログ : 趣味で

    Ruby にパッチを投げたり bugs.ruby で気になったチケットを ブログにまとめたりしてる Ruby 2.5 〜 2.7 までオレオレ機能を追加した Ruby 3.0 では機能追加できなかった… Ruby で⼀番好きな機能は Refinements オンラインなのであちこちの地域.rb に参加してる @pink_bangbi osyo-manga Secret Garden(Instrumental) Fukuoka.rb Hamada.rb kawasaki.rb nikotama.rb Sendai.rb Shibuya.rb Shinjuku.rb Tama.rb Toyama.rb Gotanda.rb Entaku.rb Grow.rb Hamamatsu.rb kanazawa.rb Kobe.rb Machida.rb mitaka.rb Ruby Tuesday toruby ⻄⽇暮⾥.rb
  3. パターンマッチと右代⼊ パターンマッチと右代⼊ 便利になる gem をつくった 便利になる gem をつくった

  4. 注意! 注意! この記事は開発版の Ruby 3.0 で検証しています Ruby 3.0 がリリースがされているときには挙動が変わっている可能 性があるので注意してください

  5. Ruby 2.7 / 3.0 でパターンマッチが⼊った Ruby 2.7 / 3.0 でパターンマッチが⼊った

    Ruby 2.7 / 3.0 でパターンマッチが⼊りました これは以下のような感じで使うことができる def check(user) case user in { name:, age: (..20) } "#{name} は魔法少⼥です" in { name:, age: (20..) } "#{name} は魔法少⼥ではありません" else " わからない" end end p check({ name: " ほむ", age: 14 }) # => " ほむは魔法少⼥です" p check({ name: " マミ", age: 30 }) # => " マミは魔法少⼥ではありません" p check([" まどか", 14]) # => " わからない"
  6. 任意のクラスでパターンマッチできる 任意のクラスでパターンマッチできる #deconstruct_keys を定義することで拡張できる class Time # in に書いた Hash

    のキーを受け取る # 返した Hash でパターンマッチを⾏う def deconstruct_keys(keys) { year: year, month: month, day: day } end def to_four_seasons case self in { month: (3..5) } then "spring" in { month: (6..8) } then "summer" in { month: (9..11) } then "autumn" in { month: (1..2) } | { month: 12 } then "winter" end end end p Time.now.to_four_seasons # => "autumn"
  7. 応⽤するとこんな事ができる 応⽤するとこんな事ができる module PatternMatchWithMethod # メソッドを呼び出すような拡張を⾏う def deconstruct_keys(keys) keys.to_h {

    |name| [name, public_send(name)] } end end class Time include PatternMatchWithMethod def to_four_seasons case self in { month: (3..5) } then "spring" in { month: (6..8) } then "summer" in { month: (9..11) } then "autumn" in { month: (1..2) } | { month: 12 } then "winter" end end end p Time.now.to_four_seasons # => "autumn"
  8. いろいろと便利に使える class Array include PatternMatchWithMethod end # 配列のメソッドの結果を取得する case ["homu",

    "mami", "mado"] in { first:, last:, size: } end p first # => "homu" p last # => "mado" p size # => 3 # インスタンスに extend して⽣やすこともできる case { name: "homu", age: 14 }.extend PatternMatchWithMethod in { keys:, values: } end p keys # => [:name, :age] p values # => ["homu", 14]
  9. これを gem 化した これを gem 化した

  10. pattern_matchable pattern_matchable require "pattern_matchable" class Time # PatternMatchable を include

    するとすぐに使える include PatternMatchable def to_four_seasons case self in { month: (3..5) } then "spring" in { month: (6..8) } then "summer" in { month: (9..11) } then "autumn" in { month: (1..2) } | { month: 12 } then "winter" end end end p Time.now.to_four_seasons # => "autumn"
  11. オープンクラスに直越 include したく オープンクラスに直越 include したく ないですよね? ないですよね?

  12. Refinements の時間だオラァ!! Refinements の時間だオラァ!!

  13. using PatternMatchable するだけで拡張できる using PatternMatchable するだけで拡張できる require "pattern_matchable" # このファイル内でのみ反映される

    using PatternMatchable class Time def to_four_seasons case self in { month: (3..5) } then "spring" in { month: (6..8) } then "summer" in { month: (9..11) } then "autumn" in { month: (1..2) } | { month: 12 } then "winter" end end end p Time.now.to_four_seasons # => "autumn" case ["homu", "mami", "mado"] in { first:, last:, size: } end p [first, last, size] # => ["homu", "mado", 3]
  14. 特定のクラスのみ拡張もできる 特定のクラスのみ拡張もできる require "pattern_matchable" class Time # Time クラスのみ拡張する using

    PatternMatchable Time def to_four_seasons case self in { month: (3..5) } then "spring" in { month: (6..8) } then "summer" in { month: (9..11) } then "autumn" in { month: (1..2) } | { month: 12 } then "winter" end end end p Time.now.to_four_seasons # => "autumn" # Array は拡張されない # error: ["homu", "mami", "mado"] (NoMatchingPatternError) case ["homu", "mami", "mado"]
  15. in { first:, last:, size: } end

  16. Refinements は最⾼だな!! Refinements は最⾼だな!!

  17. おまけ:右代⼊の話 おまけ:右代⼊の話

  18. 右代⼊ 右代⼊ Ruby 3.0 で右代⼊が⼊る予定 これは左辺の値を右辺の変数に代⼊する構⽂ また以下のような機能も⼊る予定 これって分割代⼊じゃね? これって分割代⼊じゃね? result

    = 42 # を 42 => result user = { name: "homu", age: 14 } case user in { name:, age: } end # を user => { name:, age: } p [name, age] # => ["homu", 14]
  19. ちなみにパターンマッチなので以下のように書くこともできる homu = { name: "homu", age: 14 } #

    特定のクラスのみ代⼊できる homu => { name: String => name, age: Integer => age } p [name, age] # => ["homu", 14] mami = { name: :mami, age: 14 } # これはエラー # error: {:name=>:mami, :age=>14} (NoMatchingPatternError) mami => { name: String => name, age: Integer => age } p [name, age] # => ["homu", 14]
  20. まとめ まとめ

  21. まとめ まとめ Ruby 2.7 / 3.0 でパターンマッチという機能が実装された パターンマッチ便利 パターンマッチは #deconstruct_keys

    を定義することで任意のクラス をパターンマッチすることができる を使うと簡単に既存のクラスを拡張できるよ Refinements は最⾼だな!! 右代⼊も最⾼だな!! pattern_matchable
  22. 宣伝 宣伝 今週の⾦曜⽇だよ! yukicoder の問題をみんなで解いてみるよ! 今年もやるよ!!! みんな参加してね! Ruby 3.0 についての

    Advent Calendar だよ!!! 寂しいのでみんな参加してね!! 参加して!!! Machida.rb #07 - Machida.rb | Doorkeeper Ruby Advent Calendar 2020 Ruby 3.0 Advent Calendar 2020 令和時代の基礎⽂法最速マスター
  23. ご清聴 ご清聴 ありがとうございました ありがとうございました