[Bug #20482] [DOC] Clarify about pattern maching guard clause
[ruby.git] / doc / syntax / pattern_matching.rdoc
blob6a30380f46b4b126ffbf898836ec8e6a4b307e01
1 = Pattern matching
3 Pattern matching is a feature allowing deep matching of structured values: checking the structure and binding the matched parts to local variables.
5 Pattern matching in Ruby is implemented with the +case+/+in+ expression:
7     case <expression>
8     in <pattern1>
9       ...
10     in <pattern2>
11       ...
12     in <pattern3>
13       ...
14     else
15       ...
16     end
18 (Note that +in+ and +when+ branches can NOT be mixed in one +case+ expression.)
20 Or with the <code>=></code> operator and the +in+ operator, which can be used in a standalone expression:
22     <expression> => <pattern>
24     <expression> in <pattern>
26 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.
28 Therefore, the +case+ expression might be used for conditional matching and unpacking:
30   config = {db: {user: 'admin', password: 'abc123'}}
32   case config
33   in db: {user:} # matches subhash and puts matched value in variable user
34     puts "Connect with user '#{user}'"
35   in connection: {username: }
36     puts "Connect with user '#{username}'"
37   else
38     puts "Unrecognized structure of config"
39   end
40   # Prints: "Connect with user 'admin'"
42 whilst the <code>=></code> operator is most useful when the expected data structure is known beforehand, to just unpack parts of it:
44   config = {db: {user: 'admin', password: 'abc123'}}
46   config => {db: {user:}} # will raise if the config's structure is unexpected
48   puts "Connect with user '#{user}'"
49   # Prints: "Connect with user 'admin'"
51 <code><expression> in <pattern></code> is the same as <code>case <expression>; in <pattern>; true; else false; end</code>.
52 You can use it when you only want to know if a pattern has been matched or not:
54   users = [{name: "Alice", age: 12}, {name: "Bob", age: 23}]
55   users.any? {|user| user in {name: /B/, age: 20..} } #=> true
57 See below for more examples and explanations of the syntax.
59 == Patterns
61 Patterns can be:
63 * any Ruby object (matched by the <code>===</code> operator, like in +when+); (<em>Value pattern</em>)
64 * array pattern: <code>[<subpattern>, <subpattern>, <subpattern>, ...]</code>; (<em>Array pattern</em>)
65 * find pattern: <code>[*variable, <subpattern>, <subpattern>, <subpattern>, ..., *variable]</code>; (<em>Find pattern</em>)
66 * hash pattern: <code>{key: <subpattern>, key: <subpattern>, ...}</code>; (<em>Hash pattern</em>)
67 * combination of patterns with <code>|</code>; (<em>Alternative pattern</em>)
68 * variable capture: <code><pattern> => variable</code> or <code>variable</code>; (<em>As pattern</em>, <em>Variable pattern</em>)
70 Any pattern can be nested inside array/find/hash patterns where <code><subpattern></code> is specified.
72 Array patterns and find patterns match arrays, or objects that respond to +deconstruct+ (see below about the latter).
73 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.
75 An important difference between array and hash pattern behavior is that arrays match only a _whole_ array:
77   case [1, 2, 3]
78   in [Integer, Integer]
79     "matched"
80   else
81     "not matched"
82   end
83   #=> "not matched"
85 while the hash matches even if there are other keys besides the specified part:
87   case {a: 1, b: 2, c: 3}
88   in {a: Integer}
89     "matched"
90   else
91     "not matched"
92   end
93   #=> "matched"
95 <code>{}</code> is the only exclusion from this rule. It matches only if an empty hash is given:
97   case {a: 1, b: 2, c: 3}
98   in {}
99     "matched"
100   else
101     "not matched"
102   end
103   #=> "not matched"
105   case {}
106   in {}
107     "matched"
108   else
109     "not matched"
110   end
111   #=> "matched"
113 There is also a way to specify there should be no other keys in the matched hash except those explicitly specified by the pattern, with <code>**nil</code>:
115   case {a: 1, b: 2}
116   in {a: Integer, **nil} # this will not match the pattern having keys other than a:
117     "matched a part"
118   in {a: Integer, b: Integer, **nil}
119     "matched a whole"
120   else
121     "not matched"
122   end
123   #=> "matched a whole"
125 Both array and hash patterns support "rest" specification:
127   case [1, 2, 3]
128   in [Integer, *]
129     "matched"