Pattern matching¶ ↑
Pattern matching is a feature allowing deep matching of structured values: checking the structure and binding the matched parts to local variables.
Pattern matching in Ruby is implemented with the case/in expression:
case <expression> in <pattern1> ... in <pattern2> ... in <pattern3> ... else ... end
(Note that in and when branches can NOT be mixed in one case expression.)
Or with the => operator and the in operator, which can be used in a standalone expression:
<expression> => <pattern> <expression> in <pattern>
The case/in expression is exhaustive: if the value of the expression does not match any branch of the case expression (and the else branch is absent), NoMatchingPatternError is raised.
Therefore, the case expression might be used for conditional matching and unpacking:
config = {db: {user: 'admin', password: 'abc123'}} case config in db: {user:} # matches subhash and puts matched value in variable user puts "Connect with user '#{user}'" in connection: {username: } puts "Connect with user '#{username}'" else puts "Unrecognized structure of config" end # Prints: "Connect with user 'admin'"
whilst the => operator is most useful when the expected data structure is known beforehand, to just unpack parts of it:
config = {db: {user: 'admin', password: 'abc123'}} config => {db: {user:}} # will raise if the config's structure is unexpected puts "Connect with user '#{user}'" # Prints: "Connect with user 'admin'"
<expression> in <pattern> is the same as case <expression>; in <pattern>; true; else false; end. You can use it when you only want to know if a pattern has been matched or not:
users = [{name: "Alice", age: 12}, {name: "Bob", age: 23}] users.any? {|user| user in {name: /B/, age: 20..} } #=> true
See below for more examples and explanations of the syntax.
Patterns¶ ↑
Patterns can be:
-
any Ruby object (matched by the
===operator, like inwhen); (Value pattern) -
array pattern:
[<subpattern>, <subpattern>, <subpattern>, ...]; (Array pattern) -
find pattern:
[*variable, <subpattern>, <subpattern>, <subpattern>, ..., *variable]; (Find pattern) -
hash pattern:
{key: <subpattern>, key: <subpattern>, ...}; (Hash pattern) -
combination of patterns with
|; (Alternative pattern) -
variable capture:
<pattern> => variableorvariable; (As pattern, Variable pattern)
Any pattern can be nested inside array/find/hash patterns where <subpattern> is specified.
Array patterns and find patterns match arrays, or objects that respond to deconstruct (see below about the latter). Hash patterns match hashes, or objects that respond to deconstruct_keys (see below about the latter). Note that only symbol keys are supported for hash patterns.
An important difference between array and hash pattern behavior is that arrays match only a whole array:
case [1, 2, 3] in [Integer, Integer] "matched" else "not matched" end #=> "not matched"
while the hash matches even if there are other keys besides the specified part:
case {a: 1, b: 2, c: 3} in {a: Integer} "matched" else "not matched" end #=> "matched"