matchmaker 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README +310 -0
- data/README.markdown +310 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/lib/matchmaker.rb +479 -0
- data/matchmaker.gemspec +55 -0
- data/spec/case_spec.rb +466 -0
- data/spec/spec_helper.rb +9 -0
- metadata +77 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Howard Yeh
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,310 @@
|
|
1
|
+
|
2
|
+
Matchmaker is a powerful and expressive DSL that
|
3
|
+
brings pattern matching into Ruby. Often we need
|
4
|
+
to check if an object is what we expect, and if
|
5
|
+
so, we want to take it apart. Pattern matching is
|
6
|
+
an expressive idiom from functional programming
|
7
|
+
languages to make checking on an object and taking
|
8
|
+
it apart concisely readable.
|
9
|
+
|
10
|
+
# Install
|
11
|
+
|
12
|
+
> sudo gem install hayeah-matchmaker
|
13
|
+
> irb -rubygems
|
14
|
+
irb> require 'matchmaker'
|
15
|
+
irb> Case(1) { of(1) }
|
16
|
+
# => true
|
17
|
+
|
18
|
+
# Case Statement
|
19
|
+
|
20
|
+
A case statement can have many alternative
|
21
|
+
patterns to match. The patterns are run in
|
22
|
+
sequence until the first one that matches. If no
|
23
|
+
pattern matches, a `Case::NoMatch` exception is
|
24
|
+
raised.
|
25
|
+
|
26
|
+
Case(1) {
|
27
|
+
of(1)
|
28
|
+
of(:b)
|
29
|
+
} # => true
|
30
|
+
|
31
|
+
Case(2) {
|
32
|
+
of(1)
|
33
|
+
of(:b)
|
34
|
+
} # => raise Case::NoMatch
|
35
|
+
|
36
|
+
Case(:b) {
|
37
|
+
of(1)
|
38
|
+
of(:b)
|
39
|
+
} # => true
|
40
|
+
|
41
|
+
Matchmaker uses the Case DSL to build a runnable
|
42
|
+
pattern matcher. You can store the pattern matcher
|
43
|
+
in a constant or variable, so Matchmaker doesn't
|
44
|
+
have to build it everytime you use it.
|
45
|
+
|
46
|
+
c = Case.new {
|
47
|
+
of(1)
|
48
|
+
of(:b)
|
49
|
+
}
|
50
|
+
c.match(1) => true
|
51
|
+
c.match(0) => Case::NoMatch
|
52
|
+
c.match(:b) => true
|
53
|
+
|
54
|
+
For each pattern in the case statement, there can
|
55
|
+
be an action associated with it. The action is run
|
56
|
+
when the pattern of that branch matches, and the
|
57
|
+
result of the action returned:
|
58
|
+
|
59
|
+
c = Case.new {
|
60
|
+
of(1) { :a }
|
61
|
+
of(2) { :b }
|
62
|
+
of(3) # { true } by default
|
63
|
+
}
|
64
|
+
c.match(1) # => :a
|
65
|
+
c.match(2) # => :b
|
66
|
+
c.match(3) # => true
|
67
|
+
|
68
|
+
# Simple Patterns
|
69
|
+
|
70
|
+
Literals ruby objects are matched by `==`
|
71
|
+
|
72
|
+
of(1) # matches 1
|
73
|
+
of(:a) # matches :a
|
74
|
+
of("a") # matches "a"
|
75
|
+
|
76
|
+
A regex is used to match string
|
77
|
+
|
78
|
+
# matches "0abc0"
|
79
|
+
of(/abc/)
|
80
|
+
|
81
|
+
A class is used to match objects of the that class
|
82
|
+
|
83
|
+
# matches "abc"
|
84
|
+
of(String)
|
85
|
+
|
86
|
+
A range can be used to match a range of integers
|
87
|
+
|
88
|
+
# matches integer within 1 and 10
|
89
|
+
of(1..10)
|
90
|
+
|
91
|
+
An array should be an array of patterns that
|
92
|
+
matches an array object, such that each element in
|
93
|
+
the array should match its pattern.
|
94
|
+
|
95
|
+
# matches ["a",[],{}]
|
96
|
+
of([String,Array,Hash])
|
97
|
+
|
98
|
+
# Destructuring and Pattern Guard
|
99
|
+
|
100
|
+
There are patterns to match common ruby
|
101
|
+
objects. For example, Case#string is a method of
|
102
|
+
the DSL to build the string pattern.
|
103
|
+
|
104
|
+
of(string) # matches any string
|
105
|
+
of(string("a")) # matches "a"
|
106
|
+
of(string(/foo/)) # matches any string of that regexp
|
107
|
+
|
108
|
+
These pattern methods can make variable bindings
|
109
|
+
of the matched object,
|
110
|
+
|
111
|
+
Case([1,"a"]) {
|
112
|
+
of([1,string(/a/,:a)]) { a }
|
113
|
+
} # => "a"
|
114
|
+
|
115
|
+
In this example, the pattern sets the variable
|
116
|
+
`:a` to the matched string. These variables are
|
117
|
+
actually bindings. Binding of the same name in
|
118
|
+
different patterns must equal to each other,
|
119
|
+
otherwise the overall pattern won't match.
|
120
|
+
|
121
|
+
c = Case.new {
|
122
|
+
of([string(/a/,:a),string(/b/,:a)])
|
123
|
+
}
|
124
|
+
c.match(["ab","ab"]) # => true
|
125
|
+
c.match(["ab","ba"]) # Case::NoMatch
|
126
|
+
|
127
|
+
A guard is an arbitray ruby block associated with
|
128
|
+
a pattern, so that a pattern matches iff the guard
|
129
|
+
returns true.
|
130
|
+
|
131
|
+
c = Case.new {
|
132
|
+
of(string(/a/) {|s| s.length == 2 })
|
133
|
+
}
|
134
|
+
c.match("ab") # => true
|
135
|
+
c.match("ba") # => true
|
136
|
+
c.match("abc") # Case::NoMatch
|
137
|
+
|
138
|
+
# Value Patterns
|
139
|
+
|
140
|
+
These patterns are used to match a single Ruby
|
141
|
+
object. See later for structural patterns for ways
|
142
|
+
to combine these value patterns. All these methods
|
143
|
+
can make binding and take a guard, as in
|
144
|
+
|
145
|
+
of(some_pattern(pattern_spec,:binding) {|matched_value|
|
146
|
+
some_more_test_on(matched_value)
|
147
|
+
})
|
148
|
+
|
149
|
+
## Case#_
|
150
|
+
|
151
|
+
This is the wildcard that matches anything
|
152
|
+
|
153
|
+
of(_)
|
154
|
+
|
155
|
+
You can use binding to say "I don't care what this
|
156
|
+
and that are, but I want them to be the same", like so,
|
157
|
+
|
158
|
+
of([_(:a),1,_(:a)])
|
159
|
+
|
160
|
+
The pattern matcher binds whatever matches the
|
161
|
+
first and last element of the array to ":a", the
|
162
|
+
binding fails unless those elements are the same.
|
163
|
+
|
164
|
+
## Case#a
|
165
|
+
|
166
|
+
Matches any object of a class.
|
167
|
+
|
168
|
+
of(a(String))
|
169
|
+
|
170
|
+
## Case#literal
|
171
|
+
|
172
|
+
Matches an object by its `==` method.
|
173
|
+
|
174
|
+
of(literal(1))
|
175
|
+
of(literal(:b))
|
176
|
+
|
177
|
+
## Case#integer
|
178
|
+
|
179
|
+
Matches an integer.
|
180
|
+
|
181
|
+
of(integer) # any integer
|
182
|
+
of(integer(1)) # matches 1
|
183
|
+
of(integer(1..10)) # matches a range
|
184
|
+
# matches any number in the set
|
185
|
+
of(integer([1,3,5,7,9]))
|
186
|
+
|
187
|
+
## Case#string
|
188
|
+
|
189
|
+
of(string)
|
190
|
+
of(string("abc"))
|
191
|
+
of(string(/abc/))
|
192
|
+
|
193
|
+
## Case#symbol
|
194
|
+
|
195
|
+
of(string)
|
196
|
+
of(string(:abc))
|
197
|
+
# matches a symbol if its to_s matches the regexp.
|
198
|
+
of(string(/abc/))
|
199
|
+
|
200
|
+
|
201
|
+
# Structural Patterns
|
202
|
+
|
203
|
+
For "container" objects like arrays and hashes,
|
204
|
+
pattern matching is a nice way to specify the
|
205
|
+
properties of the object, and taking it apart.
|
206
|
+
|
207
|
+
|
208
|
+
## Case#array
|
209
|
+
|
210
|
+
of([]) # == of(array([]))
|
211
|
+
of([1,2]) # matches exactly [1,2]
|
212
|
+
of([symbol,string,symbol])
|
213
|
+
# matches an array the first and last element are
|
214
|
+
# the same symbol, the second element is a string
|
215
|
+
of([symbol(nil,:a),string,symbol(nil,:a)])
|
216
|
+
|
217
|
+
You can match the tail of an array by using the
|
218
|
+
special method `Case#_!`
|
219
|
+
|
220
|
+
c = Case.new {
|
221
|
+
of([1,2,_!(integer)])
|
222
|
+
}
|
223
|
+
c.match([1]) # Case::NoMatch
|
224
|
+
c.match([1,2]) # => true
|
225
|
+
c.match([1,2,3]) # => true
|
226
|
+
c.match([1,2,3,4,5]) # => true
|
227
|
+
c.match([1,2,3,:a]) # => Case::NoMatch
|
228
|
+
|
229
|
+
this pattern matches any array whose first two
|
230
|
+
elements are 1 and 2, the rest are integers.
|
231
|
+
|
232
|
+
|
233
|
+
## Case#hash
|
234
|
+
|
235
|
+
Hashes are pattern matched by specifying the what
|
236
|
+
pattern a key's value should match. A key can be
|
237
|
+
either be required, or optional, for the pattern
|
238
|
+
matching to succeed.
|
239
|
+
|
240
|
+
c = Case.new {
|
241
|
+
of("required" => integer, ["optional"] => string)
|
242
|
+
}
|
243
|
+
c.match("required" => 10, "optional" => "a") # => true
|
244
|
+
c.match("required" => 10, "optional" => 1) # Case::NoMatch
|
245
|
+
c.match("required" => 10) # => true
|
246
|
+
c.match("required" => "a") # => Case::NoMatch
|
247
|
+
|
248
|
+
The optional key is denoted by wrapping that in an
|
249
|
+
array.
|
250
|
+
|
251
|
+
## Case#one_of
|
252
|
+
|
253
|
+
This pattern matches if any one of its array of
|
254
|
+
patterns matches.
|
255
|
+
|
256
|
+
c = Case.new {
|
257
|
+
of(one_of([integer,string]))
|
258
|
+
}
|
259
|
+
c.match(10) # => true
|
260
|
+
c.match("yay") # => true
|
261
|
+
c.match(:foo) # => Case::NoMatch
|
262
|
+
|
263
|
+
# Higher Order Pattern
|
264
|
+
|
265
|
+
The pattern matcher is just constructed with a
|
266
|
+
bunch of objects. So it's possible to save a
|
267
|
+
pattern in a variable, and use that to build
|
268
|
+
larger patterns.
|
269
|
+
|
270
|
+
Build a two element array of a custom pattern,
|
271
|
+
|
272
|
+
c = Case.new {
|
273
|
+
my_pattern = [symbol,string]
|
274
|
+
of([my_pattern,my_pattern])
|
275
|
+
}
|
276
|
+
|
277
|
+
Generate pattern with lambda,
|
278
|
+
|
279
|
+
c = Case.new {
|
280
|
+
pattern = lambda {|pattern1,pattern2| [pattern1,pattern2]}
|
281
|
+
of(pattern.call(symbol,string))
|
282
|
+
of(pattern.call(string,symbol))
|
283
|
+
}
|
284
|
+
|
285
|
+
## Case#is
|
286
|
+
|
287
|
+
This method is used to coerce an object into
|
288
|
+
pattern if it isn't already.
|
289
|
+
|
290
|
+
is(/regexp/) # string(regexp)
|
291
|
+
is(some_class) # matches by class
|
292
|
+
is(obj) # literal(obj) for any object
|
293
|
+
|
294
|
+
Mostly useful for higher order stuff you are
|
295
|
+
doing.
|
296
|
+
|
297
|
+
## Case#bind
|
298
|
+
|
299
|
+
This is used to matched values to variables. It
|
300
|
+
takes a pattern, and a binding name, and possibly
|
301
|
+
a guard.
|
302
|
+
|
303
|
+
c = Case.new {
|
304
|
+
foo = is([string])
|
305
|
+
of(bind(foo,:a)) { [1,a] }
|
306
|
+
of(bind([foo],:a)) { [2,a] }
|
307
|
+
}
|
308
|
+
c.match(["a"]) # => [1,["a"]]
|
309
|
+
c.match([["a"]]) # => [2,[["a"]]]
|
310
|
+
|
data/README.markdown
ADDED
@@ -0,0 +1,310 @@
|
|
1
|
+
|
2
|
+
Matchmaker is a powerful and expressive DSL that
|
3
|
+
brings pattern matching into Ruby. Often we need
|
4
|
+
to check if an object is what we expect, and if
|
5
|
+
so, we want to take it apart. Pattern matching is
|
6
|
+
an expressive idiom from functional programming
|
7
|
+
languages to make checking on an object and taking
|
8
|
+
it apart concisely readable.
|
9
|
+
|
10
|
+
# Install
|
11
|
+
|
12
|
+
> sudo gem install hayeah-matchmaker
|
13
|
+
> irb -rubygems
|
14
|
+
irb> require 'matchmaker'
|
15
|
+
irb> Case(1) { of(1) }
|
16
|
+
# => true
|
17
|
+
|
18
|
+
# Case Statement
|
19
|
+
|
20
|
+
A case statement can have many alternative
|
21
|
+
patterns to match. The patterns are run in
|
22
|
+
sequence until the first one that matches. If no
|
23
|
+
pattern matches, a `Case::NoMatch` exception is
|
24
|
+
raised.
|
25
|
+
|
26
|
+
Case(1) {
|
27
|
+
of(1)
|
28
|
+
of(:b)
|
29
|
+
} # => true
|
30
|
+
|
31
|
+
Case(2) {
|
32
|
+
of(1)
|
33
|
+
of(:b)
|
34
|
+
} # => raise Case::NoMatch
|
35
|
+
|
36
|
+
Case(:b) {
|
37
|
+
of(1)
|
38
|
+
of(:b)
|
39
|
+
} # => true
|
40
|
+
|
41
|
+
Matchmaker uses the Case DSL to build a runnable
|
42
|
+
pattern matcher. You can store the pattern matcher
|
43
|
+
in a constant or variable, so Matchmaker doesn't
|
44
|
+
have to build it everytime you use it.
|
45
|
+
|
46
|
+
c = Case.new {
|
47
|
+
of(1)
|
48
|
+
of(:b)
|
49
|
+
}
|
50
|
+
c.match(1) # => true
|
51
|
+
c.match(0) # => Case::NoMatch
|
52
|
+
c.match(:b) # => true
|
53
|
+
|
54
|
+
For each pattern in the case statement, there can
|
55
|
+
be an action associated with it. The action is run
|
56
|
+
when the pattern of that branch matches, and the
|
57
|
+
result of the action returned:
|
58
|
+
|
59
|
+
c = Case.new {
|
60
|
+
of(1) { :a }
|
61
|
+
of(2) { :b }
|
62
|
+
of(3) # { true } by default
|
63
|
+
}
|
64
|
+
c.match(1) # => :a
|
65
|
+
c.match(2) # => :b
|
66
|
+
c.match(3) # => true
|
67
|
+
|
68
|
+
# Simple Patterns
|
69
|
+
|
70
|
+
Literals ruby objects are matched by `==`
|
71
|
+
|
72
|
+
of(1) # matches 1
|
73
|
+
of(:a) # matches :a
|
74
|
+
of("a") # matches "a"
|
75
|
+
|
76
|
+
A regex is used to match string
|
77
|
+
|
78
|
+
# matches "0abc0"
|
79
|
+
of(/abc/)
|
80
|
+
|
81
|
+
A class is used to match objects of the that class
|
82
|
+
|
83
|
+
# matches "abc"
|
84
|
+
of(String)
|
85
|
+
|
86
|
+
A range can be used to match a range of integers
|
87
|
+
|
88
|
+
# matches integer within 1 and 10
|
89
|
+
of(1..10)
|
90
|
+
|
91
|
+
An array should be an array of patterns that
|
92
|
+
matches an array object, such that each element in
|
93
|
+
the array should match its pattern.
|
94
|
+
|
95
|
+
# matches ["a",[],{}]
|
96
|
+
of([String,Array,Hash])
|
97
|
+
|
98
|
+
# Destructuring and Pattern Guard
|
99
|
+
|
100
|
+
There are patterns to match common ruby
|
101
|
+
objects. For example, Case#string is a method of
|
102
|
+
the DSL to build the string pattern.
|
103
|
+
|
104
|
+
of(string) # matches any string
|
105
|
+
of(string("a")) # matches "a"
|
106
|
+
of(string(/foo/)) # matches any string of that regexp
|
107
|
+
|
108
|
+
These pattern methods can make variable bindings
|
109
|
+
of the matched object,
|
110
|
+
|
111
|
+
Case([1,"a"]) {
|
112
|
+
of([1,string(/a/,:a)]) { a }
|
113
|
+
} # => "a"
|
114
|
+
|
115
|
+
In this example, the pattern sets the variable
|
116
|
+
`:a` to the matched string. These variables are
|
117
|
+
actually bindings. Binding of the same name in
|
118
|
+
different patterns must equal to each other,
|
119
|
+
otherwise the overall pattern won't match.
|
120
|
+
|
121
|
+
c = Case.new {
|
122
|
+
of([string(/a/,:a),string(/b/,:a)])
|
123
|
+
}
|
124
|
+
c.match(["ab","ab"]) # => true
|
125
|
+
c.match(["ab","ba"]) # Case::NoMatch
|
126
|
+
|
127
|
+
A guard is an arbitray ruby block associated with
|
128
|
+
a pattern, so that a pattern matches iff the guard
|
129
|
+
returns true.
|
130
|
+
|
131
|
+
c = Case.new {
|
132
|
+
of(string(/a/) {|s| s.length == 2 })
|
133
|
+
}
|
134
|
+
c.match("ab") # => true
|
135
|
+
c.match("ba") # => true
|
136
|
+
c.match("abc") # Case::NoMatch
|
137
|
+
|
138
|
+
# Value Patterns
|
139
|
+
|
140
|
+
These patterns are used to match a single Ruby
|
141
|
+
object. See later for structural patterns for ways
|
142
|
+
to combine these value patterns. All these methods
|
143
|
+
can make binding and take a guard, as in
|
144
|
+
|
145
|
+
of(some_pattern(pattern_spec,:binding) {|matched_value|
|
146
|
+
some_more_test_on(matched_value)
|
147
|
+
})
|
148
|
+
|
149
|
+
## Case#_
|
150
|
+
|
151
|
+
This is the wildcard that matches anything
|
152
|
+
|
153
|
+
of(_)
|
154
|
+
|
155
|
+
You can use binding to say "I don't care what this
|
156
|
+
and that are, but I want them to be the same", like so,
|
157
|
+
|
158
|
+
of([_(:a),1,_(:a)])
|
159
|
+
|
160
|
+
The pattern matcher binds whatever matches the
|
161
|
+
first and last element of the array to ":a", the
|
162
|
+
binding fails unless those elements are the same.
|
163
|
+
|
164
|
+
## Case#a
|
165
|
+
|
166
|
+
Matches any object of a class.
|
167
|
+
|
168
|
+
of(a(String))
|
169
|
+
|
170
|
+
## Case#literal
|
171
|
+
|
172
|
+
Matches an object by its `==` method.
|
173
|
+
|
174
|
+
of(literal(1))
|
175
|
+
of(literal(:b))
|
176
|
+
|
177
|
+
## Case#integer
|
178
|
+
|
179
|
+
Matches an integer.
|
180
|
+
|
181
|
+
of(integer) # any integer
|
182
|
+
of(integer(1)) # matches 1
|
183
|
+
of(integer(1..10)) # matches a range
|
184
|
+
of(integer([1,3,5,7,9])) # matches any number in the set
|
185
|
+
|
186
|
+
## Case#string
|
187
|
+
|
188
|
+
of(string)
|
189
|
+
of(string("abc"))
|
190
|
+
of(string(/abc/))
|
191
|
+
|
192
|
+
## Case#symbol
|
193
|
+
|
194
|
+
of(string)
|
195
|
+
of(string(:abc))
|
196
|
+
# matches a symbol if its to_s matches the regexp.
|
197
|
+
of(string(/abc/))
|
198
|
+
|
199
|
+
|
200
|
+
# Structural Patterns
|
201
|
+
|
202
|
+
For "container" objects like arrays and hashes,
|
203
|
+
pattern matching is a nice way to specify the
|
204
|
+
properties of the object, and taking it apart.
|
205
|
+
|
206
|
+
|
207
|
+
## Case#array
|
208
|
+
|
209
|
+
of([]) # == of(array([]))
|
210
|
+
of([1,2]) # matches exactly [1,2]
|
211
|
+
of([symbol,string,symbol])
|
212
|
+
|
213
|
+
# matches an array the first and last element are
|
214
|
+
# the same symbol, the second element is a string
|
215
|
+
of([symbol(nil,:a),string,symbol(nil,:a)])
|
216
|
+
|
217
|
+
You can match the tail of an array by using the
|
218
|
+
special method `Case#_!`
|
219
|
+
|
220
|
+
c = Case.new {
|
221
|
+
of([1,2,_!(integer)])
|
222
|
+
}
|
223
|
+
c.match([1]) # Case::NoMatch
|
224
|
+
c.match([1,2]) # => true
|
225
|
+
c.match([1,2,3]) # => true
|
226
|
+
c.match([1,2,3,4,5]) # => true
|
227
|
+
c.match([1,2,3,:a]) # Case::NoMatch
|
228
|
+
|
229
|
+
this pattern matches any array whose first two
|
230
|
+
elements are 1 and 2, the rest are integers.
|
231
|
+
|
232
|
+
|
233
|
+
## Case#hash
|
234
|
+
|
235
|
+
Hashes are pattern matched by specifying the what
|
236
|
+
pattern a key's value should match. A key can be
|
237
|
+
either be required, or optional, for the pattern
|
238
|
+
matching to succeed.
|
239
|
+
|
240
|
+
c = Case.new {
|
241
|
+
of("required" => integer, ["optional"] => string)
|
242
|
+
}
|
243
|
+
c.match("required" => 10, "optional" => "a") # => true
|
244
|
+
c.match("required" => 10, "optional" => 1) # Case::NoMatch
|
245
|
+
c.match("required" => 10) # => true
|
246
|
+
c.match("required" => "a") # => Case::NoMatch
|
247
|
+
|
248
|
+
The optional key is denoted by wrapping that in an
|
249
|
+
array.
|
250
|
+
|
251
|
+
## Case#one_of
|
252
|
+
|
253
|
+
This pattern matches if any one of its array of
|
254
|
+
patterns matches.
|
255
|
+
|
256
|
+
c = Case.new {
|
257
|
+
of(one_of([integer,string]))
|
258
|
+
}
|
259
|
+
c.match(10) # => true
|
260
|
+
c.match("yay") # => true
|
261
|
+
c.match(:foo) # => Case::NoMatch
|
262
|
+
|
263
|
+
# Higher Order Pattern
|
264
|
+
|
265
|
+
The pattern matcher is just constructed with a
|
266
|
+
bunch of objects. So it's possible to save a
|
267
|
+
pattern in a variable, and use that to build
|
268
|
+
larger patterns.
|
269
|
+
|
270
|
+
Build a two element array of a custom pattern,
|
271
|
+
|
272
|
+
c = Case.new {
|
273
|
+
my_pattern = [symbol,string]
|
274
|
+
of([my_pattern,my_pattern])
|
275
|
+
}
|
276
|
+
|
277
|
+
Generate pattern with lambda,
|
278
|
+
|
279
|
+
c = Case.new {
|
280
|
+
pattern = lambda {|pattern1,pattern2| [pattern1,pattern2]}
|
281
|
+
of(pattern.call(symbol,string))
|
282
|
+
of(pattern.call(string,symbol))
|
283
|
+
}
|
284
|
+
|
285
|
+
## Case#is
|
286
|
+
|
287
|
+
This method is used to coerce an object into
|
288
|
+
pattern if it isn't already.
|
289
|
+
|
290
|
+
is(/regexp/) # string(regexp)
|
291
|
+
is(some_class) # matches by class
|
292
|
+
is(obj) # literal(obj) for any object
|
293
|
+
|
294
|
+
Mostly useful for higher order stuff you are
|
295
|
+
doing.
|
296
|
+
|
297
|
+
## Case#bind
|
298
|
+
|
299
|
+
This is used to matched values to variables. It
|
300
|
+
takes a pattern, and a binding name, and possibly
|
301
|
+
a guard.
|
302
|
+
|
303
|
+
c = Case.new {
|
304
|
+
foo = is([string])
|
305
|
+
of(bind(foo,:a)) { [1,a] }
|
306
|
+
of(bind([foo],:a)) { [2,a] }
|
307
|
+
}
|
308
|
+
c.match(["a"]) # => [1,["a"]]
|
309
|
+
c.match([["a"]]) # => [2,[["a"]]]
|
310
|
+
|