Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

⾃⼰紹介 ⾃⼰紹介 名前: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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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]) # => " わからない"

Slide 6

Slide 6 text

任意のクラスでパターンマッチできる 任意のクラスでパターンマッチできる #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"

Slide 7

Slide 7 text

応⽤するとこんな事ができる 応⽤するとこんな事ができる 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"

Slide 8

Slide 8 text

いろいろと便利に使える 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]

Slide 9

Slide 9 text

これを gem 化した これを gem 化した

Slide 10

Slide 10 text

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"

Slide 11

Slide 11 text

オープンクラスに直越 include したく オープンクラスに直越 include したく ないですよね? ないですよね?

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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]

Slide 14

Slide 14 text

特定のクラスのみ拡張もできる 特定のクラスのみ拡張もできる 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"]

Slide 15

Slide 15 text

in { first:, last:, size: } end

Slide 16

Slide 16 text

Refinements は最⾼だな!! Refinements は最⾼だな!!

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

右代⼊ 右代⼊ 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]

Slide 19

Slide 19 text

ちなみにパターンマッチなので以下のように書くこともできる 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]

Slide 20

Slide 20 text

まとめ まとめ

Slide 21

Slide 21 text

まとめ まとめ Ruby 2.7 / 3.0 でパターンマッチという機能が実装された パターンマッチ便利 パターンマッチは #deconstruct_keys を定義することで任意のクラス をパターンマッチすることができる を使うと簡単に既存のクラスを拡張できるよ Refinements は最⾼だな!! 右代⼊も最⾼だな!! pattern_matchable

Slide 22

Slide 22 text

宣伝 宣伝 今週の⾦曜⽇だよ! yukicoder の問題をみんなで解いてみるよ! 今年もやるよ!!! みんな参加してね! Ruby 3.0 についての Advent Calendar だよ!!! 寂しいのでみんな参加してね!! 参加して!!! Machida.rb #07 - Machida.rb | Doorkeeper Ruby Advent Calendar 2020 Ruby 3.0 Advent Calendar 2020 令和時代の基礎⽂法最速マスター

Slide 23

Slide 23 text

ご清聴 ご清聴 ありがとうございました ありがとうございました