matchmaker 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
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
+