[ruby-talk:444825] Pattern matching as String, passing patters to functions
Hi Rubyists, is this the place to ask beginner questions? I am confused about pattern matching. It only seems to work when the key is of type symbol. How would I apply pattern matching to string keys? Example require "yaml" yaml_data=" cards_on_hand: - suite: hearts value: '9' - suite: hearts value: 'king' - suite: diamonds value: 'king' " y=YAML.safe_load(yaml_data, symbolize_names: true) puts y.inspect y[:cards_on_hand].each do |a_card| case a_card in { suite: String => captured_suite, value: 'king' } puts "you have a king on your hand and its suite is #{captured_suite}" else puts "a card of no interest #{a_card.inspect}" end end {cards_on_hand: [{suit: "hearts", value: "9"}, {suit: "hearts", value: "king"}, {suit: "diamonds", value: "king"}]} a card of no interest {suite: "hearts", value: "9"} you have a king on your hand and its suite is hearts you have a king on your hand and its suite is diamonds Second question: Since everything in Ruby is an object, how do I pass patterns into a function? Even more specific, how do I handle capture when passing to a function? Cheers, Marcus
im lazy. straight from copilot :) 🔑 Pattern Matching with String Keys By default, Ruby’s hash pattern matching expects symbol keys. That’s why your example works when you load YAML with symbolize_names: true. If you keep string keys, you need to explicitly match them: ruby y = YAML.safe_load(yaml_data) # no symbolize_names y["cards_on_hand"].each do |a_card| case a_card in { "suite" => String => captured_suite, "value" => "king" } puts "you have a king on your hand and its suite is #{captured_suite}" else puts "a card of no interest #{a_card.inspect}" end end Notice the difference: suite: → matches a symbol key "suite" => → matches a string key So: Use symbolize_names: true if you want to work with symbols. Or match with "key" => if you want to keep string keys. 📦 Passing Patterns into Functions Patterns in Ruby are objects (they’re part of the language syntax). You can’t directly “store” a pattern as a variable, but you can wrap matching logic in a method and use case ... in inside it. Example: ruby def match_card(card, pattern) case card in pattern yield $~ if block_given? # or just return true else nil end end pattern = { suite: String => suite, value: "king" } y[:cards_on_hand].each do |card| match_card(card, pattern) do puts "Captured suite: #{suite}" end end Another approach is to use procs/lambdas for reusable matching logic: ruby king_pattern = ->(card) { case card in { suite: String => s, value: "king" } s else nil end } y[:cards_on_hand].each do |card| if (suite = king_pattern.call(card)) puts "You have a king of #{suite}" end end This way, you can pass around reusable matchers like any other object. 🚀 Key Takeaways Use symbol: for symbol keys, "string" => for string keys. Wrap patterns in methods or lambdas to pass them around. Captures (=> var) work fine inside those reusable matchers. On Tue, May 26, 2026 at 10:12 PM Marcus Poller via ruby-talk < ruby-talk@ml.ruby-lang.org> wrote:
Hi Rubyists,
is this the place to ask beginner questions?
I am confused about pattern matching. It only seems to work when the key is of type symbol. How would I apply pattern matching to string keys?
Example
require "yaml"
yaml_data=" cards_on_hand: - suite: hearts value: '9' - suite: hearts value: 'king' - suite: diamonds value: 'king' "
y=YAML.safe_load(yaml_data, symbolize_names: true) puts y.inspect
y[:cards_on_hand].each do |a_card| case a_card in { suite: String => captured_suite, value: 'king' } puts "you have a king on your hand and its suite is #{captured_suite}" else puts "a card of no interest #{a_card.inspect}" end end
{cards_on_hand: [{suit: "hearts", value: "9"}, {suit: "hearts", value: "king"}, {suit: "diamonds", value: "king"}]}
a card of no interest {suite: "hearts", value: "9"} you have a king on your hand and its suite is hearts you have a king on your hand and its suite is diamonds
Second question:
Since everything in Ruby is an object, how do I pass patterns into a function? Even more specific, how do I handle capture when passing to a function?
Cheers, Marcus ______________________________________________ ruby-talk mailing list -- ruby-talk@ml.ruby-lang.org To unsubscribe send an email to ruby-talk-leave@ml.ruby-lang.org ruby-talk info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-talk.ml.ruby-lang.org...
String keys do not work with pattern matching, or more specifically pattern expressions in this case. The only way to get around that is to use something to symbolize the keys. That said, I have argued before that we should treat pattern expression keys as irrelevant, whether they are Strings or Symbols. https://baweaver.com/writing/2022/06/11/the-case-for-pattern-matching-key-ir... The other option is to use something like Dio to make it irreverent for you: https://github.com/baweaver/dio The general direction of my argument in this regard is that pattern expressions are exactly that: patterns. They are not Symbols, nor are they Strings, just as keyword arguments are keyword arguments and not Symbols either. Regarding your second point? Patterns are not first-class objects, unlike a regular expression, for example. However, you can cheat this one a bit more elegantly: captured_pattern = -> value { value in pattern: /match/ } You use a function / proc / lambda / block to do it. That's also something I want, in addition to composable patterns (e.g., capturing a pattern and reusing it inside another one as a branch or a part of it.) On Sun, May 31, 2026 at 10:14 PM botp via ruby-talk < ruby-talk@ml.ruby-lang.org> wrote:
im lazy. straight from copilot :)
🔑 Pattern Matching with String Keys By default, Ruby’s hash pattern matching expects symbol keys. That’s why your example works when you load YAML with symbolize_names: true. If you keep string keys, you need to explicitly match them:
ruby y = YAML.safe_load(yaml_data) # no symbolize_names
y["cards_on_hand"].each do |a_card| case a_card in { "suite" => String => captured_suite, "value" => "king" } puts "you have a king on your hand and its suite is #{captured_suite}" else puts "a card of no interest #{a_card.inspect}" end end Notice the difference:
suite: → matches a symbol key
"suite" => → matches a string key
So:
Use symbolize_names: true if you want to work with symbols.
Or match with "key" => if you want to keep string keys.
📦 Passing Patterns into Functions Patterns in Ruby are objects (they’re part of the language syntax). You can’t directly “store” a pattern as a variable, but you can wrap matching logic in a method and use case ... in inside it.
Example:
ruby def match_card(card, pattern) case card in pattern yield $~ if block_given? # or just return true else nil end end
pattern = { suite: String => suite, value: "king" }
y[:cards_on_hand].each do |card| match_card(card, pattern) do puts "Captured suite: #{suite}" end end Another approach is to use procs/lambdas for reusable matching logic:
ruby king_pattern = ->(card) { case card in { suite: String => s, value: "king" } s else nil end }
y[:cards_on_hand].each do |card| if (suite = king_pattern.call(card)) puts "You have a king of #{suite}" end end This way, you can pass around reusable matchers like any other object.
🚀 Key Takeaways Use symbol: for symbol keys, "string" => for string keys.
Wrap patterns in methods or lambdas to pass them around.
Captures (=> var) work fine inside those reusable matchers.
On Tue, May 26, 2026 at 10:12 PM Marcus Poller via ruby-talk < ruby-talk@ml.ruby-lang.org> wrote:
Hi Rubyists,
is this the place to ask beginner questions?
I am confused about pattern matching. It only seems to work when the key is of type symbol. How would I apply pattern matching to string keys?
Example
require "yaml"
yaml_data=" cards_on_hand: - suite: hearts value: '9' - suite: hearts value: 'king' - suite: diamonds value: 'king' "
y=YAML.safe_load(yaml_data, symbolize_names: true) puts y.inspect
y[:cards_on_hand].each do |a_card| case a_card in { suite: String => captured_suite, value: 'king' } puts "you have a king on your hand and its suite is #{captured_suite}" else puts "a card of no interest #{a_card.inspect}" end end
{cards_on_hand: [{suit: "hearts", value: "9"}, {suit: "hearts", value: "king"}, {suit: "diamonds", value: "king"}]}
a card of no interest {suite: "hearts", value: "9"} you have a king on your hand and its suite is hearts you have a king on your hand and its suite is diamonds
Second question:
Since everything in Ruby is an object, how do I pass patterns into a function? Even more specific, how do I handle capture when passing to a function?
Cheers, Marcus ______________________________________________ ruby-talk mailing list -- ruby-talk@ml.ruby-lang.org To unsubscribe send an email to ruby-talk-leave@ml.ruby-lang.org ruby-talk info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-talk.ml.ruby-lang.org...
______________________________________________ ruby-talk mailing list -- ruby-talk@ml.ruby-lang.org To unsubscribe send an email to ruby-talk-leave@ml.ruby-lang.org ruby-talk info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-talk.ml.ruby-lang.org...
participants (3)
-
botp -
Brandon Weaver -
Marcus Poller