पाठ 12 / 25
Pattern Matching with case/in
Destructure hashes and arrays and validate data shapes with pattern matching.
Matching structure, not just values
Ruby 3 added pattern matching with case ... in. Unlike case/when, which compares values, in patterns match structure and bind variables: array patterns (in [first, *rest]), hash patterns (in { status: "paid", total: Integer => total }), alternative patterns (in :paid | :shipped), value patterns using === (ranges, classes, regexes), guards (in { total: } if total > 1000), and the pin operator ^ to compare with an existing variable. Hash patterns match if the listed keys are present, ignoring extra keys (use **nil to require no others). If no pattern matches and there is no else, Ruby raises NoMatchingPatternError, which helps catch unexpected data. The one-line forms data => { name: } (destructure or raise) and data in { name: String } (returns true or false) are handy for parsing JSON. Your own classes can participate by defining deconstruct (for array patterns) and deconstruct_keys (for hash patterns); Data and Struct objects support both automatically.
Parsing API responses with patterns
Structure checks and variable binding in one step.
require "json"
def describe(response)
case response
in { status: "ok", data: { orders: [] } }
"No orders yet"
in { status: "ok", data: { orders: [{ id:, total: }, *rest] } }
"First order #{id} (Rs #{total}) and #{rest.size} more"
in { status: "error", code: 400..499 => code, message: }
"Client error #{code}: #{message}"
in { status: "error", code: }
"Server error #{code}"
end
end
json = '{"status":"ok","data":{"orders":[{"id":"o-1","total":1200},{"id":"o-2","total":300}]}}'
puts describe(JSON.parse(json, symbolize_names: true)) # First order o-1 (Rs 1200) and 1 more
config = { db: { host: "localhost", port: 5432 } }
config => { db: { host:, port: } } # destructure or raise
puts "#{host}:#{port}"
Point = Data.define(:lat, :lng)
case Point.new(lat: 18.5, lng: 73.9)
in { lat: 8..37 => lat } # Data supports deconstruct_keys
puts "Within India's latitude range: #{lat}"
endUnmatched patterns raise
A case/in without else raises NoMatchingPatternError when nothing matches. That is usually what you want for unexpected API data, but add an else branch where unknown shapes are normal.
त्वरित जाँच: How does `case ... in` differ from `case ... when`?
- in matches structure and binds variables, while when compares values with ===
- They are identical
- in only works with integers
- when supports guards but in does not
Answer
in matches structure and binds variables, while when compares values with === — Pattern matching destructures arrays, hashes and objects and can bind parts to variables.