pattern-match 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|