pattern-match 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/BSDL +1 -1
- data/COPYING +1 -1
- data/README.rdoc +0 -27
- data/lib/pattern-match.rb +74 -140
- data/lib/pattern-match/version.rb +1 -1
- data/test/test_pattern-match.rb +6 -76
- metadata +12 -7
data/BSDL
CHANGED
data/COPYING
CHANGED
data/README.rdoc
CHANGED
@@ -49,18 +49,6 @@ or
|
|
49
49
|
}
|
50
50
|
end
|
51
51
|
|
52
|
-
# With Refinements
|
53
|
-
def balance(left, key, right)
|
54
|
-
match([left, key, right]) {
|
55
|
-
with(_[R[a, x, b], y, R[c, z, d]]) { R[B[a, x, b], y, B[c, z, d]] }
|
56
|
-
with(_[R[R[a, x, b], y, c], z, d]) { R[B[a, x, b], y, B[c, z, d]] }
|
57
|
-
with(_[R[a, x, R[b, y, c]], z, d]) { R[B[a, x, b], y, B[c, z, d]] }
|
58
|
-
with(_[a, x, R[b, y, R[c, z, d]]]) { R[B[a, x, b], y, B[c, z, d]] }
|
59
|
-
with(_[a, x, R[R[b, y, c], z, d]]) { R[B[a, x, b], y, B[c, z, d]] }
|
60
|
-
with(_) { B[left, key, right] }
|
61
|
-
}
|
62
|
-
end
|
63
|
-
|
64
52
|
## (D)
|
65
53
|
class EMail
|
66
54
|
def self.deconstruct(value)
|
@@ -74,13 +62,6 @@ or
|
|
74
62
|
}
|
75
63
|
}
|
76
64
|
|
77
|
-
# With Refinements
|
78
|
-
match(['foo-bar@example.com', 'baz-bar@example.com']) {
|
79
|
-
with(_[mail & EMail[name & /(\w+)-(\w+)/[firstname, 'bar'], domain], ___]) {
|
80
|
-
p [firstname, name, domain, mail] # => [["foo", "baz"], ["foo-bar", "baz-bar"], ["example.com", "example.com"], ["foo-bar@example.com", "baz-bar@example.com"]]
|
81
|
-
}
|
82
|
-
}
|
83
|
-
|
84
65
|
## (E)
|
85
66
|
match(10) {
|
86
67
|
with(Object.(:to_i => a, :foobar => b)) { :not_match }
|
@@ -89,14 +70,6 @@ or
|
|
89
70
|
}
|
90
71
|
}
|
91
72
|
|
92
|
-
# With Refinements
|
93
|
-
match(10) {
|
94
|
-
with(:to_i[a] & :foobar[b]) { :not_match }
|
95
|
-
with(:to_i[a] & :to_s.(16)[b])) {
|
96
|
-
p [a, b] #=> [10, "a"]
|
97
|
-
}
|
98
|
-
}
|
99
|
-
|
100
73
|
You can see another example in test/test_pattern-match.rb.
|
101
74
|
|
102
75
|
== Development
|
data/lib/pattern-match.rb
CHANGED
@@ -1,26 +1,10 @@
|
|
1
1
|
# pattern-match.rb
|
2
2
|
#
|
3
|
-
# Copyright (C) 2012 Kazuki Tsujimoto, All rights reserved.
|
3
|
+
# Copyright (C) 2012-2013 Kazuki Tsujimoto, All rights reserved.
|
4
4
|
|
5
5
|
require 'pattern-match/version'
|
6
6
|
|
7
7
|
module PatternMatch
|
8
|
-
if Module.private_method_defined? :refine
|
9
|
-
SUPPORT_REFINEMENTS = true
|
10
|
-
else
|
11
|
-
SUPPORT_REFINEMENTS = false
|
12
|
-
Module.module_eval do
|
13
|
-
private
|
14
|
-
|
15
|
-
def refine(klass, &block)
|
16
|
-
klass.class_eval(&block)
|
17
|
-
end
|
18
|
-
|
19
|
-
def using(klass)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
8
|
module Deconstructable
|
25
9
|
def call(*subpatterns)
|
26
10
|
if Object == self
|
@@ -33,117 +17,15 @@ module PatternMatch
|
|
33
17
|
PatternDeconstructor.new(self, *subpatterns)
|
34
18
|
end
|
35
19
|
end
|
36
|
-
|
37
|
-
if SUPPORT_REFINEMENTS
|
38
|
-
alias [] call
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
module NameSpace
|
43
|
-
refine Class do
|
44
|
-
include Deconstructable
|
45
|
-
|
46
|
-
def deconstruct(val)
|
47
|
-
raise NotImplementedError, "need to define `#{__method__}'"
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def accept_self_instance_only(val)
|
53
|
-
raise PatternNotMatch unless val.kind_of?(self)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
refine Array.singleton_class do
|
58
|
-
def deconstruct(val)
|
59
|
-
accept_self_instance_only(val)
|
60
|
-
val
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
refine Struct.singleton_class do
|
65
|
-
def deconstruct(val)
|
66
|
-
accept_self_instance_only(val)
|
67
|
-
val.values
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
refine Complex.singleton_class do
|
72
|
-
def deconstruct(val)
|
73
|
-
accept_self_instance_only(val)
|
74
|
-
val.rect
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
refine Rational.singleton_class do
|
79
|
-
def deconstruct(val)
|
80
|
-
accept_self_instance_only(val)
|
81
|
-
[val.numerator, val.denominator]
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
refine MatchData.singleton_class do
|
86
|
-
def deconstruct(val)
|
87
|
-
accept_self_instance_only(val)
|
88
|
-
val.captures.empty? ? [val[0]] : val.captures
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
if SUPPORT_REFINEMENTS
|
93
|
-
def Struct.method_added(name)
|
94
|
-
if name == members[0]
|
95
|
-
this = self
|
96
|
-
PatternMatch::NameSpace.module_eval do
|
97
|
-
refine this.singleton_class do
|
98
|
-
include Deconstructable
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
refine Proc do
|
105
|
-
include Deconstructable
|
106
|
-
|
107
|
-
def deconstruct(val)
|
108
|
-
[self === val]
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
refine Symbol do
|
113
|
-
include Deconstructable
|
114
|
-
|
115
|
-
def deconstruct(val)
|
116
|
-
[self.to_proc === val]
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
refine Symbol do
|
122
|
-
def call(*args)
|
123
|
-
Proc.new {|obj| obj.__send__(self, *args) }
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
refine Regexp do
|
128
|
-
include Deconstructable
|
129
|
-
|
130
|
-
def deconstruct(val)
|
131
|
-
m = Regexp.new("\\A#{source}\\z", options).match(val.to_s)
|
132
|
-
raise PatternNotMatch unless m
|
133
|
-
m.captures.empty? ? [m[0]] : m.captures
|
134
|
-
end
|
135
|
-
end
|
136
20
|
end
|
137
21
|
|
138
22
|
class Pattern
|
139
23
|
attr_accessor :parent, :next, :prev
|
140
|
-
attr_writer :pattern_match_env
|
141
24
|
|
142
25
|
def initialize(*subpatterns)
|
143
26
|
@parent = nil
|
144
27
|
@next = nil
|
145
28
|
@prev = nil
|
146
|
-
@pattern_match_env = nil
|
147
29
|
@subpatterns = subpatterns.map {|i| i.kind_of?(Pattern) ? i : PatternValue.new(i) }
|
148
30
|
set_subpatterns_relation
|
149
31
|
end
|
@@ -189,10 +71,6 @@ module PatternMatch
|
|
189
71
|
@subpatterns.each(&:validate)
|
190
72
|
end
|
191
73
|
|
192
|
-
def pattern_match_env
|
193
|
-
@pattern_match_env || @parent.pattern_match_env
|
194
|
-
end
|
195
|
-
|
196
74
|
private
|
197
75
|
|
198
76
|
def set_subpatterns_relation
|
@@ -243,19 +121,19 @@ module PatternMatch
|
|
243
121
|
end
|
244
122
|
|
245
123
|
class PatternDeconstructor < Pattern
|
246
|
-
def initialize(
|
124
|
+
def initialize(deconstructor, *subpatterns)
|
247
125
|
super(*subpatterns)
|
248
|
-
@
|
126
|
+
@deconstructor = deconstructor
|
249
127
|
end
|
250
128
|
|
251
129
|
def match(val)
|
252
|
-
|
253
|
-
k =
|
130
|
+
deconstructed_vals = @deconstructor.deconstruct(val)
|
131
|
+
k = deconstructed_vals.length - (@subpatterns.length - 2)
|
254
132
|
quantifier = @subpatterns.find {|i| i.kind_of?(PatternQuantifier) }
|
255
133
|
if quantifier
|
256
134
|
return false unless quantifier.min_k <= k
|
257
135
|
else
|
258
|
-
return false unless @subpatterns.length ==
|
136
|
+
return false unless @subpatterns.length == deconstructed_vals.length
|
259
137
|
end
|
260
138
|
@subpatterns.flat_map do |pat|
|
261
139
|
case
|
@@ -267,7 +145,7 @@ module PatternMatch
|
|
267
145
|
else
|
268
146
|
[pat]
|
269
147
|
end
|
270
|
-
end.zip(
|
148
|
+
end.zip(deconstructed_vals).all? do |pat, v|
|
271
149
|
pat.match(v)
|
272
150
|
end
|
273
151
|
end
|
@@ -399,7 +277,6 @@ module PatternMatch
|
|
399
277
|
def with(pat_or_val, guard_proc = nil, &block)
|
400
278
|
pat = pat_or_val.kind_of?(Pattern) ? pat_or_val : PatternValue.new(pat_or_val)
|
401
279
|
pat.validate
|
402
|
-
pat.pattern_match_env = self
|
403
280
|
if pat.match(@val) and (guard_proc ? with_tmpbinding(@ctx, pat.binding, &guard_proc) : true)
|
404
281
|
ret = with_tmpbinding(@ctx, pat.binding, &block)
|
405
282
|
::Kernel.throw(:exit_match, ret)
|
@@ -428,10 +305,9 @@ module PatternMatch
|
|
428
305
|
case vals.length
|
429
306
|
when 0
|
430
307
|
uscore = PatternVariable.new(:_)
|
431
|
-
uscore.pattern_match_env = self
|
432
308
|
class << uscore
|
433
309
|
def [](*args)
|
434
|
-
|
310
|
+
Array.call(*args)
|
435
311
|
end
|
436
312
|
|
437
313
|
def match(val)
|
@@ -509,7 +385,7 @@ module PatternMatch
|
|
509
385
|
constants.each do |c|
|
510
386
|
klass = const_get(c)
|
511
387
|
next unless klass.kind_of?(Class)
|
512
|
-
if klass
|
388
|
+
if klass <= Pattern
|
513
389
|
private_constant c
|
514
390
|
end
|
515
391
|
end
|
@@ -523,13 +399,6 @@ module Kernel
|
|
523
399
|
def match(*vals, &block)
|
524
400
|
do_match = Proc.new do |val|
|
525
401
|
env = PatternMatch.const_get(:Env).new(self, val)
|
526
|
-
class << env
|
527
|
-
using ::PatternMatch::NameSpace
|
528
|
-
|
529
|
-
def call_refined_method(obj, name, *args)
|
530
|
-
obj.__send__(name, *args)
|
531
|
-
end
|
532
|
-
end
|
533
402
|
catch(:exit_match) do
|
534
403
|
env.instance_eval(&block)
|
535
404
|
raise ::PatternMatch::NoMatchingPatternError
|
@@ -545,3 +414,68 @@ module Kernel
|
|
545
414
|
end
|
546
415
|
end
|
547
416
|
end
|
417
|
+
|
418
|
+
class Class
|
419
|
+
include PatternMatch::Deconstructable
|
420
|
+
|
421
|
+
def deconstruct(val)
|
422
|
+
raise NotImplementedError, "need to define `#{__method__}'"
|
423
|
+
end
|
424
|
+
|
425
|
+
private
|
426
|
+
|
427
|
+
def accept_self_instance_only(val)
|
428
|
+
raise PatternMatch::PatternNotMatch unless val.kind_of?(self)
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
class << Array
|
433
|
+
def deconstruct(val)
|
434
|
+
accept_self_instance_only(val)
|
435
|
+
val
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
class << Struct
|
440
|
+
def deconstruct(val)
|
441
|
+
accept_self_instance_only(val)
|
442
|
+
val.values
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
class << Complex
|
447
|
+
def deconstruct(val)
|
448
|
+
accept_self_instance_only(val)
|
449
|
+
val.rect
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
class << Rational
|
454
|
+
def deconstruct(val)
|
455
|
+
accept_self_instance_only(val)
|
456
|
+
[val.numerator, val.denominator]
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
class << MatchData
|
461
|
+
def deconstruct(val)
|
462
|
+
accept_self_instance_only(val)
|
463
|
+
val.captures.empty? ? [val[0]] : val.captures
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
class Regexp
|
468
|
+
include PatternMatch::Deconstructable
|
469
|
+
|
470
|
+
def deconstruct(val)
|
471
|
+
m = Regexp.new("\\A#{source}\\z", options).match(val.to_s)
|
472
|
+
raise PatternMatch::PatternNotMatch unless m
|
473
|
+
m.captures.empty? ? [m[0]] : m.captures
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
class Symbol
|
478
|
+
def call(*args)
|
479
|
+
Proc.new {|obj| obj.__send__(self, *args) }
|
480
|
+
end
|
481
|
+
end
|
data/test/test_pattern-match.rb
CHANGED
@@ -312,7 +312,7 @@ class TestPatternMatch < Test::Unit::TestCase
|
|
312
312
|
assert_equal(1, 2.times.find(&match { with(1) { true }; with(_) { false } }))
|
313
313
|
end
|
314
314
|
|
315
|
-
def
|
315
|
+
def test_deconstructor_class
|
316
316
|
assert_raise(NotImplementedError) {
|
317
317
|
c = Class.new
|
318
318
|
match(0) {
|
@@ -322,7 +322,7 @@ class TestPatternMatch < Test::Unit::TestCase
|
|
322
322
|
}
|
323
323
|
end
|
324
324
|
|
325
|
-
def
|
325
|
+
def test_deconstructor_class_struct
|
326
326
|
s = Struct.new(:a, :b, :c)
|
327
327
|
match(s[0, 1, 2]) {
|
328
328
|
with(s.(a, b, c)) {
|
@@ -334,20 +334,7 @@ class TestPatternMatch < Test::Unit::TestCase
|
|
334
334
|
}
|
335
335
|
end
|
336
336
|
|
337
|
-
def
|
338
|
-
skip 'refinements not supported' unless PatternMatch::SUPPORT_REFINEMENTS
|
339
|
-
s = Struct.new(:a, :b, :c)
|
340
|
-
match(s[0, 1, 2]) {
|
341
|
-
with(s[a, b, c]) {
|
342
|
-
assert_equal(0, a)
|
343
|
-
assert_equal(1, b)
|
344
|
-
assert_equal(2, c)
|
345
|
-
}
|
346
|
-
with(_) { flunk }
|
347
|
-
}
|
348
|
-
end
|
349
|
-
|
350
|
-
def test_extractor_class_complex
|
337
|
+
def test_deconstructor_class_complex
|
351
338
|
match(Complex(0, 1)) {
|
352
339
|
with(Complex.(a, b)) {
|
353
340
|
assert_equal(0, a)
|
@@ -357,7 +344,7 @@ class TestPatternMatch < Test::Unit::TestCase
|
|
357
344
|
}
|
358
345
|
end
|
359
346
|
|
360
|
-
def
|
347
|
+
def test_deconstructor_class_rational
|
361
348
|
match(Rational(0, 1)) {
|
362
349
|
with(Rational.(a, b)) {
|
363
350
|
assert_equal(0, a)
|
@@ -367,7 +354,7 @@ class TestPatternMatch < Test::Unit::TestCase
|
|
367
354
|
}
|
368
355
|
end
|
369
356
|
|
370
|
-
def
|
357
|
+
def test_deconstructor_class_matchdata
|
371
358
|
m = /.../.match('abc')
|
372
359
|
match(m) {
|
373
360
|
with(MatchData.(a)) {
|
@@ -387,7 +374,7 @@ class TestPatternMatch < Test::Unit::TestCase
|
|
387
374
|
}
|
388
375
|
end
|
389
376
|
|
390
|
-
def
|
377
|
+
def test_deconstructor_obj_regexp
|
391
378
|
match('abc') {
|
392
379
|
with(/./.(a)) { flunk }
|
393
380
|
with(a & /.../.(b)) {
|
@@ -408,48 +395,6 @@ class TestPatternMatch < Test::Unit::TestCase
|
|
408
395
|
}
|
409
396
|
end
|
410
397
|
|
411
|
-
def test_extractor_obj_regexp_with_refinements
|
412
|
-
skip 'refinements not supported' unless PatternMatch::SUPPORT_REFINEMENTS
|
413
|
-
match('abc') {
|
414
|
-
with(/./[a]) { flunk }
|
415
|
-
with(a & /.../[b]) {
|
416
|
-
assert_equal('abc', a)
|
417
|
-
assert_equal('abc', b)
|
418
|
-
}
|
419
|
-
with(_) { flunk }
|
420
|
-
}
|
421
|
-
|
422
|
-
match('abc') {
|
423
|
-
with(a & /(.)(.)(.)/[b, c ,d]) {
|
424
|
-
assert_equal('abc', a)
|
425
|
-
assert_equal('a', b)
|
426
|
-
assert_equal('b', c)
|
427
|
-
assert_equal('c', d)
|
428
|
-
}
|
429
|
-
with(_) { flunk }
|
430
|
-
}
|
431
|
-
end
|
432
|
-
|
433
|
-
def test_extractor_obj_proc_with_refinements
|
434
|
-
skip 'refinements not supported' unless PatternMatch::SUPPORT_REFINEMENTS
|
435
|
-
match(0) {
|
436
|
-
with((Proc.new {|i| i + 1 })[a]) {
|
437
|
-
assert_equal(1, a)
|
438
|
-
}
|
439
|
-
with(_) { flunk }
|
440
|
-
}
|
441
|
-
end
|
442
|
-
|
443
|
-
def test_extractor_obj_symbol_with_refinements
|
444
|
-
skip 'refinements not supported' unless PatternMatch::SUPPORT_REFINEMENTS
|
445
|
-
match(0) {
|
446
|
-
with(:to_s[a]) {
|
447
|
-
assert_equal('0', a)
|
448
|
-
}
|
449
|
-
with(_) { flunk }
|
450
|
-
}
|
451
|
-
end
|
452
|
-
|
453
398
|
def test_object
|
454
399
|
match(10) {
|
455
400
|
with(Object.(:to_i => a, :to_s.(16) => b, :no_method => c)) { flunk }
|
@@ -484,19 +429,4 @@ class TestPatternMatch < Test::Unit::TestCase
|
|
484
429
|
with(_) { flunk }
|
485
430
|
}
|
486
431
|
end
|
487
|
-
|
488
|
-
def test_refine_after_requiring_library
|
489
|
-
c = Class.new
|
490
|
-
::PatternMatch::NameSpace.module_eval {
|
491
|
-
refine c.singleton_class do
|
492
|
-
def deconstruct(*)
|
493
|
-
[:c]
|
494
|
-
end
|
495
|
-
end
|
496
|
-
}
|
497
|
-
match(:c) {
|
498
|
-
with(c.(a)) { assert_equal(:c, a) }
|
499
|
-
with(_) { flunk }
|
500
|
-
}
|
501
|
-
end
|
502
432
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pattern-match
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,12 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
25
30
|
description: A pattern matching library.
|
26
31
|
email:
|
27
32
|
- kazuki@callcc.net
|
@@ -57,7 +62,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
62
|
version: '0'
|
58
63
|
segments:
|
59
64
|
- 0
|
60
|
-
hash:
|
65
|
+
hash: -3372255759969491054
|
61
66
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
67
|
none: false
|
63
68
|
requirements:
|
@@ -66,10 +71,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
71
|
version: '0'
|
67
72
|
segments:
|
68
73
|
- 0
|
69
|
-
hash:
|
74
|
+
hash: -3372255759969491054
|
70
75
|
requirements: []
|
71
76
|
rubyforge_project:
|
72
|
-
rubygems_version: 1.8.
|
77
|
+
rubygems_version: 1.8.23
|
73
78
|
signing_key:
|
74
79
|
specification_version: 3
|
75
80
|
summary: A pattern matching library
|