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 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"