Pattern Matching
Prerequisites: case expressions, Hashes
Pattern matching (Ruby 3.0+) checks a value's shape and pulls
out the pieces you need in one step. It uses case with in instead
of when.
Matching hashes
def describe(event)
case event
in { type: "signup", user: { name: String => name } }
"New user: #{name}"
in { type: "purchase", amount: Integer | Float => amount } if amount > 100
"Big purchase: #{amount}"
in { type: "purchase" }
"Small purchase"
else
"Unknown event"
end
end
puts describe({ type: "signup", user: { name: "Ada" } })
puts describe({ type: "purchase", amount: 250 })
puts describe({ type: "purchase", amount: 20 })
puts describe({ type: "refund" })
New user: Ada
Big purchase: 250
Small purchase
Unknown event
Reading the first pattern: "a hash whose :type is "signup", whose
:user is a hash with a :name that is a String — and bind that
string to the variable name."
String => namechecks the type and binds the value to a variable.Integer | Floatmeans either.if amount > 100is a guard — an extra condition.- Hash patterns ignore extra keys, so
{ type: "purchase" }matches any purchase.
Matching arrays
def parse(command)
case command.split
in ["add", item] then "Adding #{item}"
in ["remove", item] then "Removing #{item}"
in ["move", from, to] then "Moving #{from} to #{to}"
in [] then "Empty command"
in [cmd, *] then "Unknown command: #{cmd}"
end
end
puts parse("add milk")
puts parse("move a b")
puts parse("jump high")
Adding milk
Moving a to b
Unknown command: jump
Unlike hash patterns, array patterns must match the length exactly;
* matches "any remaining elements".
Destructuring shortcut
=> on its own unpacks a value or raises
NoMatchingPatternKeyError if the shape is wrong — handy for reading
JSON you expect to have certain keys:
config = { db: { host: "localhost", port: 5432 } }
config => { db: { host:, port: } }
puts "#{host}:#{port}"
localhost:5432
host: with no value binds the key's value to a variable of the same
name.
Common mistakes
- Forgetting the
elsebranch: if nothing matches,case ... inraisesNoMatchingPatternError(unlikecase ... when, which returnsnil). - Pattern-matching string keys with symbol syntax.
{ name: }matches:name, not"name". Parse JSON withsymbolize_names: true(see the JSON lesson).