pattern-match 0.5.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +26 -2
- data/BSDL +1 -1
- data/COPYING +1 -1
- data/README.rdoc +15 -2
- data/Rakefile +1 -0
- data/lib/pattern-match.rb +2 -2
- data/lib/pattern-match/core.rb +69 -112
- data/lib/pattern-match/deconstructor.rb +58 -40
- data/lib/pattern-match/disable_refinements.rb +25 -0
- data/lib/pattern-match/experimental.rb +144 -0
- data/lib/pattern-match/version.rb +1 -1
- data/pattern-match.gemspec +2 -0
- data/test/helper.rb +8 -0
- data/test/test_experimental.rb +63 -7
- data/test/test_standard.rb +67 -35
- metadata +21 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef7bf869eb224fa684f0d76e818765b7c29bac7a
|
4
|
+
data.tar.gz: 8f0250bc045bc40226c470eeecc0d4cb19c9948e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da3c2aee6e261dc82bac97d578629b2d92a4449e6eb10ccd8f321fbd99330f2b505cde23df1e10080e7f9d2549ce40a9ba2c20c6e680d0fc6abe2c701cea3596
|
7
|
+
data.tar.gz: 5c7108710be125a049fe4fde57a1292e6e820a87cb414ef6fe7db18ad6d339da2549659381ea018b17de6469adcf51cb90240fa532c8ea92b44d027f3065f847
|
data/.travis.yml
CHANGED
@@ -1,6 +1,30 @@
|
|
1
1
|
rvm:
|
2
|
-
- 1.9.2
|
3
2
|
- 1.9.3
|
4
3
|
- 2.0.0
|
5
|
-
- 2.1
|
4
|
+
- 2.1
|
5
|
+
- 2.2
|
6
6
|
- ruby-head
|
7
|
+
- jruby-19mode
|
8
|
+
env:
|
9
|
+
- TEST="test/test_*"
|
10
|
+
- TEST="test/test_standard.rb"
|
11
|
+
- DISABLE_REFINEMENTS=1 TEST="test/test_*"
|
12
|
+
- DISABLE_REFINEMENTS=1 TEST="test/test_standard.rb"
|
13
|
+
matrix:
|
14
|
+
exclude:
|
15
|
+
- rvm: 1.9.3
|
16
|
+
env: TEST="test/test_*"
|
17
|
+
- rvm: 1.9.3
|
18
|
+
env: TEST="test/test_standard.rb"
|
19
|
+
- rvm: 2.0.0
|
20
|
+
env: TEST="test/test_*"
|
21
|
+
- rvm: 2.0.0
|
22
|
+
env: TEST="test/test_standard.rb"
|
23
|
+
- rvm: jruby-19mode
|
24
|
+
env: TEST="test/test_*"
|
25
|
+
- rvm: jruby-19mode
|
26
|
+
env: TEST="test/test_standard.rb"
|
27
|
+
- rvm: jruby-19mode
|
28
|
+
env: DISABLE_REFINEMENTS=1 TEST="test/test_*"
|
29
|
+
allow_failures:
|
30
|
+
- rvm: ruby-head
|
data/BSDL
CHANGED
data/COPYING
CHANGED
data/README.rdoc
CHANGED
@@ -19,9 +19,10 @@ or
|
|
19
19
|
$ bundle install --path vendor/bundle
|
20
20
|
|
21
21
|
== Basic Usage
|
22
|
-
pattern-match library provides
|
22
|
+
pattern-match library provides <code>Object#match</code>.
|
23
23
|
|
24
24
|
require 'pattern-match'
|
25
|
+
using PatternMatch
|
25
26
|
|
26
27
|
match(object) do
|
27
28
|
with(pattern[, guard]) do
|
@@ -111,7 +112,7 @@ all objects bound to variable must be equal.
|
|
111
112
|
<code>And</code>, <code>Or</code>, <code>Not</code> return and/or/not pattern.
|
112
113
|
|
113
114
|
match([0, [1]]) do
|
114
|
-
with(a & Fixnum, ! (_[2] | _[3])) { a } #=> 0
|
115
|
+
with(_[a & Fixnum, ! (_[2] | _[3])]) { a } #=> 0
|
115
116
|
end
|
116
117
|
|
117
118
|
match(0) do
|
@@ -238,6 +239,18 @@ Pattern guard can be specified as a second argument to <code>with</code>.
|
|
238
239
|
end
|
239
240
|
end
|
240
241
|
|
242
|
+
match('0') do
|
243
|
+
with(/\d+/.(a << :to_i)) do
|
244
|
+
a #=> 0
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
match([Set[0, 1, 2], Set[3, 4]]) do
|
249
|
+
with(_[Set.(a, b), Set.(c)], guard { a + b * c == 2 } ) do
|
250
|
+
[a, b, c] #=> [2, 0, 3]
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
241
254
|
* {RubyTextProcessing}[https://code.google.com/p/tokland/wiki/RubyTextProcessing]
|
242
255
|
* {yhara/tapl-ruby}[https://github.com/yhara/tapl-ruby]
|
243
256
|
|
data/Rakefile
CHANGED
data/lib/pattern-match.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# pattern-match.rb
|
2
2
|
#
|
3
|
-
# Copyright (C) 2012-
|
3
|
+
# Copyright (C) 2012-2015 Kazuki Tsujimoto, All rights reserved.
|
4
4
|
|
5
5
|
require 'pattern-match/version'
|
6
|
-
require 'pattern-match/core'
|
7
6
|
require 'pattern-match/deconstructor'
|
7
|
+
require 'pattern-match/core'
|
data/lib/pattern-match/core.rb
CHANGED
@@ -1,24 +1,12 @@
|
|
1
|
-
require 'pattern-match/
|
1
|
+
require 'pattern-match/deconstructor'
|
2
2
|
|
3
3
|
module PatternMatch
|
4
|
-
module Deconstructable
|
5
|
-
def call(*subpatterns)
|
6
|
-
pattern_matcher(*subpatterns)
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
class ::Object
|
11
|
-
def pattern_matcher(*subpatterns)
|
12
|
-
PatternObjectDeconstructor.new(self, *subpatterns)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
4
|
module HasOrderedSubPatterns
|
17
5
|
private
|
18
6
|
|
19
7
|
def set_subpatterns_relation
|
20
8
|
super
|
21
|
-
|
9
|
+
subpatterns.each_cons(2) do |a, b|
|
22
10
|
a.next = b
|
23
11
|
b.prev = a
|
24
12
|
end
|
@@ -37,7 +25,7 @@ module PatternMatch
|
|
37
25
|
end
|
38
26
|
|
39
27
|
def vars
|
40
|
-
|
28
|
+
subpatterns.map(&:vars).flatten
|
41
29
|
end
|
42
30
|
|
43
31
|
def ancestors
|
@@ -69,7 +57,11 @@ module PatternMatch
|
|
69
57
|
end
|
70
58
|
|
71
59
|
def quantified?
|
72
|
-
|
60
|
+
directly_quantified? or (root? ? false : @parent.quantified?)
|
61
|
+
end
|
62
|
+
|
63
|
+
def directly_quantified?
|
64
|
+
@next and @next.quantifier?
|
73
65
|
end
|
74
66
|
|
75
67
|
def root
|
@@ -81,13 +73,13 @@ module PatternMatch
|
|
81
73
|
end
|
82
74
|
|
83
75
|
def validate
|
84
|
-
|
76
|
+
subpatterns.each(&:validate)
|
85
77
|
end
|
86
78
|
|
87
79
|
def match(vals)
|
88
|
-
if
|
80
|
+
if directly_quantified?
|
89
81
|
q = @next
|
90
|
-
repeating_match(vals, q.
|
82
|
+
repeating_match(vals, q.greedy?) do |vs, rest|
|
91
83
|
if vs.length < q.min_k
|
92
84
|
next false
|
93
85
|
end
|
@@ -106,7 +98,7 @@ module PatternMatch
|
|
106
98
|
if @next
|
107
99
|
@next.append(pattern)
|
108
100
|
else
|
109
|
-
if
|
101
|
+
if subpatterns.empty?
|
110
102
|
if root?
|
111
103
|
new_root = PatternAnd.new(self)
|
112
104
|
self.parent = new_root
|
@@ -114,21 +106,23 @@ module PatternMatch
|
|
114
106
|
pattern.parent = @parent
|
115
107
|
@next = pattern
|
116
108
|
else
|
117
|
-
|
109
|
+
subpatterns[-1].append(pattern)
|
118
110
|
end
|
119
111
|
end
|
120
112
|
end
|
121
113
|
|
122
114
|
def inspect
|
123
|
-
"#<#{self.class.name}: subpatterns=#{
|
115
|
+
"#<#{self.class.name}: subpatterns=#{subpatterns.inspect}>"
|
124
116
|
end
|
125
117
|
|
126
118
|
private
|
127
119
|
|
128
|
-
|
120
|
+
attr_reader :subpatterns
|
121
|
+
|
122
|
+
def repeating_match(vals, is_greedy)
|
129
123
|
quantifier = @next
|
130
|
-
|
131
|
-
(
|
124
|
+
candidates = generate_candidates(vals)
|
125
|
+
(is_greedy ? candidates : candidates.reverse).each do |(vs, rest)|
|
132
126
|
vars.each {|i| i.set_bind_to(quantifier) }
|
133
127
|
begin
|
134
128
|
if yield vs, rest
|
@@ -141,14 +135,14 @@ module PatternMatch
|
|
141
135
|
false
|
142
136
|
end
|
143
137
|
|
144
|
-
def
|
138
|
+
def generate_candidates(vals)
|
145
139
|
vals.length.downto(0).map do |n|
|
146
140
|
[vals.take(n), vals.drop(n)]
|
147
141
|
end
|
148
142
|
end
|
149
143
|
|
150
144
|
def set_subpatterns_relation
|
151
|
-
|
145
|
+
subpatterns.each do |i|
|
152
146
|
i.parent = self
|
153
147
|
end
|
154
148
|
end
|
@@ -157,10 +151,10 @@ module PatternMatch
|
|
157
151
|
class PatternQuantifier < Pattern
|
158
152
|
attr_reader :min_k
|
159
153
|
|
160
|
-
def initialize(min_k,
|
154
|
+
def initialize(min_k, is_greedy)
|
161
155
|
super()
|
162
156
|
@min_k = min_k
|
163
|
-
@
|
157
|
+
@is_greedy = is_greedy
|
164
158
|
end
|
165
159
|
|
166
160
|
def validate
|
@@ -185,12 +179,12 @@ module PatternMatch
|
|
185
179
|
end
|
186
180
|
end
|
187
181
|
|
188
|
-
def
|
189
|
-
@
|
182
|
+
def greedy?
|
183
|
+
@is_greedy
|
190
184
|
end
|
191
185
|
|
192
186
|
def inspect
|
193
|
-
"#<#{self.class.name}: min_k=#{@min_k},
|
187
|
+
"#<#{self.class.name}: min_k=#{@min_k}, is_greedy=#{@is_greedy}>"
|
194
188
|
end
|
195
189
|
end
|
196
190
|
|
@@ -206,6 +200,8 @@ module PatternMatch
|
|
206
200
|
class PatternObjectDeconstructor < PatternDeconstructor
|
207
201
|
include HasOrderedSubPatterns
|
208
202
|
|
203
|
+
using PatternMatch if respond_to?(:using, true)
|
204
|
+
|
209
205
|
def initialize(deconstructor, *subpatterns)
|
210
206
|
super(*subpatterns)
|
211
207
|
@deconstructor = deconstructor
|
@@ -214,57 +210,15 @@ module PatternMatch
|
|
214
210
|
def match(vals)
|
215
211
|
super do |val|
|
216
212
|
deconstructed_vals = @deconstructor.deconstruct(val)
|
217
|
-
if
|
213
|
+
if subpatterns.empty?
|
218
214
|
next deconstructed_vals.empty?
|
219
215
|
end
|
220
|
-
|
216
|
+
subpatterns[0].match(deconstructed_vals)
|
221
217
|
end
|
222
218
|
end
|
223
219
|
|
224
220
|
def inspect
|
225
|
-
"#<#{self.class.name}: deconstructor=#{@deconstructor.inspect}, subpatterns=#{
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
class PatternKeywordArgStyleDeconstructor < PatternDeconstructor
|
230
|
-
def initialize(klass, checker, getter, *keyarg_subpatterns)
|
231
|
-
spec = normalize_keyword_arg(keyarg_subpatterns)
|
232
|
-
super(*spec.values)
|
233
|
-
@klass = klass
|
234
|
-
@checker = checker
|
235
|
-
@getter = getter
|
236
|
-
@spec = spec
|
237
|
-
end
|
238
|
-
|
239
|
-
def match(vals)
|
240
|
-
super do |val|
|
241
|
-
next false unless val.kind_of?(@klass)
|
242
|
-
next false unless @spec.keys.all? {|k| val.__send__(@checker, k) }
|
243
|
-
@spec.all? do |k, pat|
|
244
|
-
pat.match([val.__send__(@getter, k)]) rescue false
|
245
|
-
end
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
def inspect
|
250
|
-
"#<#{self.class.name}: klass=#{@klass.inspect}, spec=#{@spec.inspect}>"
|
251
|
-
end
|
252
|
-
|
253
|
-
private
|
254
|
-
|
255
|
-
def normalize_keyword_arg(subpatterns)
|
256
|
-
syms = subpatterns.take_while {|i| i.kind_of?(Symbol) }
|
257
|
-
rest = subpatterns.drop(syms.length)
|
258
|
-
hash = case rest.length
|
259
|
-
when 0
|
260
|
-
{}
|
261
|
-
when 1
|
262
|
-
rest[0]
|
263
|
-
else
|
264
|
-
raise MalformedPatternError
|
265
|
-
end
|
266
|
-
variables = Hash[syms.map {|i| [i, PatternVariable.new(i)] }]
|
267
|
-
Hash[variables.merge(hash).map {|k, v| [k, v.kind_of?(Pattern) ? v : PatternValue.new(v)] }]
|
221
|
+
"#<#{self.class.name}: deconstructor=#{@deconstructor.inspect}, subpatterns=#{subpatterns.inspect}>"
|
268
222
|
end
|
269
223
|
end
|
270
224
|
|
@@ -384,8 +338,8 @@ module PatternMatch
|
|
384
338
|
end
|
385
339
|
|
386
340
|
def match(vals)
|
387
|
-
if
|
388
|
-
repeating_match(vals, @next.
|
341
|
+
if directly_quantified?
|
342
|
+
repeating_match(vals, @next.greedy?) do |rewind|
|
389
343
|
if rewind.ntimes < @next.min_k
|
390
344
|
next false
|
391
345
|
end
|
@@ -400,20 +354,20 @@ module PatternMatch
|
|
400
354
|
|
401
355
|
def validate
|
402
356
|
super
|
403
|
-
raise MalformedPatternError if
|
357
|
+
raise MalformedPatternError if subpatterns.empty?
|
404
358
|
raise MalformedPatternError unless @parent.kind_of?(HasOrderedSubPatterns)
|
405
359
|
end
|
406
360
|
|
407
361
|
private
|
408
362
|
|
409
363
|
def make_rewind(n)
|
410
|
-
PatternRewind.new(n,
|
364
|
+
PatternRewind.new(n, subpatterns[0], directly_quantified? ? @next.next : @next)
|
411
365
|
end
|
412
366
|
|
413
|
-
def repeating_match(vals,
|
367
|
+
def repeating_match(vals, is_greedy)
|
414
368
|
quantifier = @next
|
415
|
-
|
416
|
-
(
|
369
|
+
candidates = generate_candidates(vals)
|
370
|
+
(is_greedy ? candidates : candidates.reverse).each do |rewind|
|
417
371
|
vars.each {|i| i.set_bind_to(quantifier) }
|
418
372
|
begin
|
419
373
|
with_rewind(rewind) do
|
@@ -428,37 +382,37 @@ module PatternMatch
|
|
428
382
|
false
|
429
383
|
end
|
430
384
|
|
431
|
-
def
|
385
|
+
def generate_candidates(vals)
|
432
386
|
vals.length.downto(0).map do |n|
|
433
387
|
make_rewind(n)
|
434
388
|
end
|
435
389
|
end
|
436
390
|
|
437
391
|
def with_rewind(rewind)
|
438
|
-
|
392
|
+
subpatterns[-1].next = rewind
|
439
393
|
yield rewind
|
440
394
|
ensure
|
441
|
-
|
395
|
+
subpatterns[-1].next = nil
|
442
396
|
end
|
443
397
|
end
|
444
398
|
|
445
399
|
class PatternAnd < PatternElement
|
446
400
|
def match(vals)
|
447
401
|
super do |val|
|
448
|
-
|
402
|
+
subpatterns.all? {|i| i.match([val]) }
|
449
403
|
end
|
450
404
|
end
|
451
405
|
|
452
406
|
def validate
|
453
407
|
super
|
454
|
-
raise MalformedPatternError if
|
408
|
+
raise MalformedPatternError if subpatterns.empty?
|
455
409
|
end
|
456
410
|
end
|
457
411
|
|
458
412
|
class PatternOr < PatternElement
|
459
413
|
def match(vals)
|
460
414
|
super do |val|
|
461
|
-
|
415
|
+
subpatterns.find do |i|
|
462
416
|
begin
|
463
417
|
i.match([val])
|
464
418
|
rescue PatternNotMatch
|
@@ -470,7 +424,7 @@ module PatternMatch
|
|
470
424
|
|
471
425
|
def validate
|
472
426
|
super
|
473
|
-
raise MalformedPatternError if
|
427
|
+
raise MalformedPatternError if subpatterns.empty?
|
474
428
|
raise MalformedPatternError unless vars.empty?
|
475
429
|
end
|
476
430
|
end
|
@@ -479,7 +433,7 @@ module PatternMatch
|
|
479
433
|
def match(vals)
|
480
434
|
super do |val|
|
481
435
|
begin
|
482
|
-
!
|
436
|
+
! subpatterns[0].match([val])
|
483
437
|
rescue PatternNotMatch
|
484
438
|
true
|
485
439
|
end
|
@@ -488,7 +442,7 @@ module PatternMatch
|
|
488
442
|
|
489
443
|
def validate
|
490
444
|
super
|
491
|
-
raise MalformedPatternError unless
|
445
|
+
raise MalformedPatternError unless subpatterns.length == 1
|
492
446
|
raise MalformedPatternError unless vars.empty?
|
493
447
|
end
|
494
448
|
end
|
@@ -559,7 +513,7 @@ module PatternMatch
|
|
559
513
|
::Kernel.raise ::ArgumentError, "wrong number of arguments (#{args.length} for 0)" unless args.empty?
|
560
514
|
case name.to_s
|
561
515
|
when /\A__(\d+)(\??)\z/
|
562
|
-
PatternQuantifier.new($1.to_i,
|
516
|
+
PatternQuantifier.new($1.to_i, $2.empty?)
|
563
517
|
else
|
564
518
|
PatternVariable.new(name)
|
565
519
|
end
|
@@ -570,8 +524,10 @@ module PatternMatch
|
|
570
524
|
when 0
|
571
525
|
uscore = PatternVariable.new(:_)
|
572
526
|
class << uscore
|
527
|
+
using PatternMatch if respond_to?(:using, true)
|
528
|
+
|
573
529
|
def [](*args)
|
574
|
-
Array.
|
530
|
+
Array.(*args)
|
575
531
|
end
|
576
532
|
|
577
533
|
def vars
|
@@ -685,26 +641,27 @@ module PatternMatch
|
|
685
641
|
end
|
686
642
|
private_constant :Env
|
687
643
|
end
|
688
|
-
end
|
689
644
|
|
690
|
-
|
691
|
-
private
|
645
|
+
refine Object do
|
692
646
|
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
env.
|
698
|
-
|
647
|
+
private
|
648
|
+
|
649
|
+
def match(*vals, &block)
|
650
|
+
do_match = Proc.new do |val|
|
651
|
+
env = Env.new(self, val)
|
652
|
+
catch(:exit_match) do
|
653
|
+
env.instance_eval(&block)
|
654
|
+
raise NoMatchingPatternError
|
655
|
+
end
|
656
|
+
end
|
657
|
+
case vals.length
|
658
|
+
when 0
|
659
|
+
do_match
|
660
|
+
when 1
|
661
|
+
do_match.(vals[0])
|
662
|
+
else
|
663
|
+
raise ArgumentError, "wrong number of arguments (#{vals.length} for 0..1)"
|
699
664
|
end
|
700
|
-
end
|
701
|
-
case vals.length
|
702
|
-
when 0
|
703
|
-
do_match
|
704
|
-
when 1
|
705
|
-
do_match.(vals[0])
|
706
|
-
else
|
707
|
-
raise ArgumentError, "wrong number of arguments (#{vals.length} for 0..1)"
|
708
665
|
end
|
709
666
|
end
|
710
667
|
end
|
@@ -1,60 +1,78 @@
|
|
1
|
-
require 'pattern-match/
|
1
|
+
require 'pattern-match/version'
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
module PatternMatch
|
4
|
+
refine Object do
|
5
|
+
private
|
5
6
|
|
6
|
-
|
7
|
-
|
7
|
+
def pattern_matcher(*subpatterns)
|
8
|
+
PatternObjectDeconstructor.new(self, *subpatterns)
|
9
|
+
end
|
8
10
|
end
|
9
11
|
|
10
|
-
|
12
|
+
module Deconstructable
|
13
|
+
using PatternMatch if respond_to?(:using, true)
|
11
14
|
|
12
|
-
|
13
|
-
|
15
|
+
def call(*subpatterns)
|
16
|
+
pattern_matcher(*subpatterns)
|
17
|
+
end
|
14
18
|
end
|
15
|
-
end
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
val
|
20
|
+
refine Class do
|
21
|
+
include PatternMatch::Deconstructable
|
22
|
+
|
23
|
+
def deconstruct(val)
|
24
|
+
raise NotImplementedError, "need to define `#{__method__}'"
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def accept_self_instance_only(val)
|
30
|
+
raise PatternMatch::PatternNotMatch unless val.kind_of?(self)
|
31
|
+
end
|
21
32
|
end
|
22
|
-
end
|
23
33
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
34
|
+
refine Array.singleton_class do
|
35
|
+
def deconstruct(val)
|
36
|
+
accept_self_instance_only(val)
|
37
|
+
val
|
38
|
+
end
|
28
39
|
end
|
29
|
-
end
|
30
40
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
41
|
+
refine Struct.singleton_class do
|
42
|
+
def deconstruct(val)
|
43
|
+
accept_self_instance_only(val)
|
44
|
+
val.values
|
45
|
+
end
|
35
46
|
end
|
36
|
-
end
|
37
47
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
48
|
+
refine Complex.singleton_class do
|
49
|
+
def deconstruct(val)
|
50
|
+
accept_self_instance_only(val)
|
51
|
+
val.rect
|
52
|
+
end
|
42
53
|
end
|
43
|
-
end
|
44
54
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
55
|
+
refine Rational.singleton_class do
|
56
|
+
def deconstruct(val)
|
57
|
+
accept_self_instance_only(val)
|
58
|
+
[val.numerator, val.denominator]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
refine MatchData.singleton_class do
|
63
|
+
def deconstruct(val)
|
64
|
+
accept_self_instance_only(val)
|
65
|
+
val.captures.empty? ? [val[0]] : val.captures
|
66
|
+
end
|
49
67
|
end
|
50
|
-
end
|
51
68
|
|
52
|
-
|
53
|
-
|
69
|
+
refine Regexp do
|
70
|
+
include PatternMatch::Deconstructable
|
54
71
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
72
|
+
def deconstruct(val)
|
73
|
+
m = Regexp.new("\\A#{source}\\z", options).match(val.to_s)
|
74
|
+
raise PatternMatch::PatternNotMatch unless m
|
75
|
+
m.captures.empty? ? [m[0]] : m.captures
|
76
|
+
end
|
59
77
|
end
|
60
78
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Module
|
2
|
+
methods = Module.instance_methods(false) + Module.private_instance_methods(false)
|
3
|
+
if methods.include?(:refine)
|
4
|
+
if methods.include?(:__refine_orig)
|
5
|
+
raise LoadError, "can't re-define Module#refine"
|
6
|
+
end
|
7
|
+
alias_method :__refine_orig, :refine
|
8
|
+
remove_method :refine
|
9
|
+
end
|
10
|
+
|
11
|
+
def refine(klass, &blk)
|
12
|
+
klass.class_eval(&blk)
|
13
|
+
end
|
14
|
+
|
15
|
+
begin
|
16
|
+
require 'pattern-match'
|
17
|
+
ensure
|
18
|
+
remove_method :refine
|
19
|
+
|
20
|
+
if Kernel.respond_to?(:__refine_orig, true)
|
21
|
+
alias_method :refine, :__refine_orig
|
22
|
+
remove_method :__refine_orig
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,7 +1,57 @@
|
|
1
1
|
require 'pattern-match/core'
|
2
|
+
require 'continuation'
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
raise LoadError, 'Module#prepend required' unless Module.respond_to?(:prepend, true)
|
2
6
|
|
3
7
|
module PatternMatch
|
8
|
+
class Pattern
|
9
|
+
module Backtrackable
|
10
|
+
def match(vals)
|
11
|
+
matched = super
|
12
|
+
if root? and not matched and not choice_points.empty?
|
13
|
+
restore_choice_point
|
14
|
+
end
|
15
|
+
matched
|
16
|
+
end
|
17
|
+
|
18
|
+
def choice_points
|
19
|
+
if root?
|
20
|
+
@choice_points ||= []
|
21
|
+
else
|
22
|
+
@parent.choice_points
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def repeating_match(vals, is_greedy)
|
29
|
+
super do |vs, rest|
|
30
|
+
cont = nil
|
31
|
+
if callcc {|c| cont = c; yield vs, rest }
|
32
|
+
save_choice_point(cont)
|
33
|
+
true
|
34
|
+
else
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def save_choice_point(choice_point)
|
41
|
+
choice_points.push(choice_point)
|
42
|
+
end
|
43
|
+
|
44
|
+
def restore_choice_point
|
45
|
+
choice_points.pop.call(false)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
prepend Backtrackable
|
50
|
+
end
|
51
|
+
|
4
52
|
module Deconstructable
|
53
|
+
using PatternMatch if respond_to?(:using, true)
|
54
|
+
|
5
55
|
remove_method :call
|
6
56
|
def call(*subpatterns)
|
7
57
|
if Object == self
|
@@ -31,6 +81,98 @@ module PatternMatch
|
|
31
81
|
end
|
32
82
|
end
|
33
83
|
end
|
84
|
+
|
85
|
+
class PatternKeywordArgStyleDeconstructor < PatternDeconstructor
|
86
|
+
def initialize(klass, checker, getter, *keyarg_subpatterns)
|
87
|
+
spec = normalize_keyword_arg(keyarg_subpatterns)
|
88
|
+
super(*spec.values)
|
89
|
+
@klass = klass
|
90
|
+
@checker = checker
|
91
|
+
@getter = getter
|
92
|
+
@spec = spec
|
93
|
+
end
|
94
|
+
|
95
|
+
def match(vals)
|
96
|
+
super do |val|
|
97
|
+
next false unless val.kind_of?(@klass)
|
98
|
+
next false unless @spec.keys.all? {|k| val.__send__(@checker, k) }
|
99
|
+
@spec.all? do |k, pat|
|
100
|
+
pat.match([val.__send__(@getter, k)]) rescue false
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def inspect
|
106
|
+
"#<#{self.class.name}: klass=#{@klass.inspect}, spec=#{@spec.inspect}>"
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def normalize_keyword_arg(subpatterns)
|
112
|
+
syms = subpatterns.take_while {|i| i.kind_of?(Symbol) }
|
113
|
+
rest = subpatterns.drop(syms.length)
|
114
|
+
hash = case rest.length
|
115
|
+
when 0
|
116
|
+
{}
|
117
|
+
when 1
|
118
|
+
rest[0]
|
119
|
+
else
|
120
|
+
raise MalformedPatternError
|
121
|
+
end
|
122
|
+
variables = Hash[syms.map {|i| [i, PatternVariable.new(i)] }]
|
123
|
+
Hash[variables.merge(hash).map {|k, v| [k, v.kind_of?(Pattern) ? v : PatternValue.new(v)] }]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class << Set
|
128
|
+
def pattern_matcher(*subpatterns)
|
129
|
+
PatternSetDeconstructor.new(self, *subpatterns)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class PatternSetDeconstructor < PatternDeconstructor
|
134
|
+
def initialize(klass, *subpatterns)
|
135
|
+
super(*subpatterns)
|
136
|
+
@klass = klass
|
137
|
+
end
|
138
|
+
|
139
|
+
def match(vals)
|
140
|
+
super do |val|
|
141
|
+
next false unless val.kind_of?(@klass)
|
142
|
+
members = val.to_a
|
143
|
+
next false unless subpatterns.length <= members.length
|
144
|
+
members.permutation(subpatterns.length).find do |perm|
|
145
|
+
cont = nil
|
146
|
+
if callcc {|c| cont = c; perm.zip(subpatterns).all? {|i, pat| pat.match([i]) } }
|
147
|
+
save_choice_point(cont)
|
148
|
+
true
|
149
|
+
else
|
150
|
+
false
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class PatternVariable
|
158
|
+
def <<(converter)
|
159
|
+
@converter = converter.respond_to?(:call) ? converter : converter.to_proc
|
160
|
+
self
|
161
|
+
end
|
162
|
+
|
163
|
+
prepend Module.new {
|
164
|
+
def initialize(name)
|
165
|
+
super
|
166
|
+
@converter = nil
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
def bind(val)
|
172
|
+
super(@converter ? @converter.call(val) : val)
|
173
|
+
end
|
174
|
+
}
|
175
|
+
end
|
34
176
|
end
|
35
177
|
|
36
178
|
class Hash
|
@@ -38,6 +180,8 @@ class Hash
|
|
38
180
|
end
|
39
181
|
|
40
182
|
class Object
|
183
|
+
using PatternMatch if respond_to?(:using, true)
|
184
|
+
|
41
185
|
def assert_pattern(pattern)
|
42
186
|
match(self) do
|
43
187
|
Kernel.eval("with(#{pattern}) { self }", Kernel.binding)
|
data/pattern-match.gemspec
CHANGED
@@ -16,8 +16,10 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
17
|
s.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f) }
|
18
18
|
s.require_paths = ['lib']
|
19
|
+
s.add_development_dependency 'test-unit'
|
19
20
|
s.add_development_dependency 'rake'
|
20
21
|
s.add_development_dependency 'simplecov'
|
21
22
|
s.extra_rdoc_files = ['README.rdoc']
|
22
23
|
s.rdoc_options = ['--main', 'README.rdoc']
|
24
|
+
s.licenses = ['2-clause BSDL', "Ruby's"]
|
23
25
|
end
|
data/test/helper.rb
CHANGED
data/test/test_experimental.rb
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
require_relative 'helper'
|
2
|
-
require 'test
|
3
|
-
|
4
|
-
require_relative '../lib/pattern-match/
|
2
|
+
require 'test-unit'
|
3
|
+
if ENV['DISABLE_REFINEMENTS']
|
4
|
+
require_relative '../lib/pattern-match/disable_refinements'
|
5
|
+
require_relative '../lib/pattern-match'
|
6
|
+
else
|
7
|
+
require_relative '../lib/pattern-match'
|
8
|
+
using PatternMatch
|
9
|
+
end
|
10
|
+
begin
|
11
|
+
require_relative '../lib/pattern-match/experimental'
|
12
|
+
rescue LoadError
|
13
|
+
end
|
5
14
|
|
6
15
|
class TestExperimental < Test::Unit::TestCase
|
7
16
|
def test_matcher_attribute_matcher
|
@@ -58,7 +67,7 @@ class TestExperimental < Test::Unit::TestCase
|
|
58
67
|
match({a: 0, b: 1}) do
|
59
68
|
with(Hash.(:a, :b, b: b2)) do
|
60
69
|
assert_equal(0, a)
|
61
|
-
|
70
|
+
assert_raises(NameError) { b }
|
62
71
|
assert_equal(1, b2)
|
63
72
|
end
|
64
73
|
with(_) { flunk }
|
@@ -75,18 +84,65 @@ class TestExperimental < Test::Unit::TestCase
|
|
75
84
|
with(_) { flunk }
|
76
85
|
end
|
77
86
|
|
78
|
-
|
87
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
79
88
|
match(0) do
|
80
89
|
with(Object.(a, b)) {}
|
81
90
|
end
|
82
91
|
end
|
83
92
|
end
|
84
93
|
|
94
|
+
def test_matcher_class_set
|
95
|
+
match([Set[0, 1, 2], Set[3, 4]]) do
|
96
|
+
with(_[Set.(a, b), Set.(c)], guard { a + b * c == 2 } ) do
|
97
|
+
assert_equal(2, a)
|
98
|
+
assert_equal(0, b)
|
99
|
+
assert_equal(3, c)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
85
104
|
def test_object_assert_pattern
|
86
105
|
assert_equal([0], [0].assert_pattern('_[Fixnum]'))
|
87
106
|
assert_equal([0], [0].assert_pattern('_[a & Fixnum], guard { a.even? }'))
|
88
|
-
|
107
|
+
assert_raises(PatternMatch::NoMatchingPatternError) do
|
89
108
|
[0, 1].assert_pattern('_[Fixnum]')
|
90
109
|
end
|
91
110
|
end
|
92
|
-
|
111
|
+
|
112
|
+
def test_pattern_variable_converter
|
113
|
+
match([0, 1]) do
|
114
|
+
with(_[a << :to_s, b << ->(i){ i.to_s }]) do
|
115
|
+
assert_equal('0', a)
|
116
|
+
assert_equal('1', b)
|
117
|
+
end
|
118
|
+
with(_) { flunk }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_quantifier_with_backtracking
|
123
|
+
match([[0, 0], [0, 1]]) do
|
124
|
+
with(_[_[*a, *_], _[*a, *_]]) do
|
125
|
+
assert_equal([0], a)
|
126
|
+
end
|
127
|
+
with(_) { flunk }
|
128
|
+
end
|
129
|
+
|
130
|
+
match([[0, 1], 2]) do
|
131
|
+
with(_[_[*a, *b], c], guard { a.empty? }) do
|
132
|
+
assert_equal([], a)
|
133
|
+
assert_equal([0, 1], b)
|
134
|
+
assert_equal(2, c)
|
135
|
+
end
|
136
|
+
with(_) { flunk }
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_sequence_with_backtracking
|
141
|
+
match([[0, 0, 0], [0, 1, 2]]) do
|
142
|
+
with(_[_[Seq(a), ___, *_], _[Seq(a), ___, *_]]) do
|
143
|
+
assert_equal([0], a)
|
144
|
+
end
|
145
|
+
with(_) { flunk }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end if defined? PatternMatch::AttributeMatcher
|
data/test/test_standard.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
require_relative 'helper'
|
2
|
-
require 'test
|
3
|
-
|
2
|
+
require 'test-unit'
|
3
|
+
if ENV['DISABLE_REFINEMENTS']
|
4
|
+
require_relative '../lib/pattern-match/disable_refinements'
|
5
|
+
require_relative '../lib/pattern-match'
|
6
|
+
else
|
7
|
+
require_relative '../lib/pattern-match'
|
8
|
+
using PatternMatch
|
9
|
+
end
|
4
10
|
|
5
11
|
class TestStandard < Test::Unit::TestCase
|
6
12
|
def test_basic
|
@@ -18,10 +24,10 @@ class TestStandard < Test::Unit::TestCase
|
|
18
24
|
with(_) { flunk }
|
19
25
|
end
|
20
26
|
assert_equal(4, ret)
|
21
|
-
|
22
|
-
|
27
|
+
assert_raises(NameError) { a }
|
28
|
+
assert_raises(NameError) { b }
|
23
29
|
|
24
|
-
|
30
|
+
assert_raises(PatternMatch::NoMatchingPatternError) do
|
25
31
|
match(0) do
|
26
32
|
with(1) { flunk }
|
27
33
|
with(2) { flunk }
|
@@ -39,7 +45,7 @@ class TestStandard < Test::Unit::TestCase
|
|
39
45
|
with(_) { flunk }
|
40
46
|
end
|
41
47
|
|
42
|
-
|
48
|
+
assert_raises(ArgumentError) do
|
43
49
|
match(0) do
|
44
50
|
p 1
|
45
51
|
end
|
@@ -63,21 +69,21 @@ class TestStandard < Test::Unit::TestCase
|
|
63
69
|
end
|
64
70
|
assert_equal(1, a)
|
65
71
|
assert_equal(2, b)
|
66
|
-
|
72
|
+
assert_raises(NameError) { c }
|
67
73
|
end
|
68
74
|
end
|
69
75
|
assert_equal(0, a)
|
70
|
-
|
71
|
-
|
76
|
+
assert_raises(NameError) { b }
|
77
|
+
assert_raises(NameError) { c }
|
72
78
|
end
|
73
79
|
end
|
74
|
-
|
75
|
-
|
76
|
-
|
80
|
+
assert_raises(NameError) { a }
|
81
|
+
assert_raises(NameError) { b }
|
82
|
+
assert_raises(NameError) { c }
|
77
83
|
end
|
78
84
|
|
79
85
|
def test_lexical_scoping(rec_call = false, f = nil)
|
80
|
-
|
86
|
+
omit 'not supported'
|
81
87
|
unless rec_call
|
82
88
|
match(0) do
|
83
89
|
with(a) do
|
@@ -90,7 +96,7 @@ class TestStandard < Test::Unit::TestCase
|
|
90
96
|
end
|
91
97
|
end
|
92
98
|
else
|
93
|
-
|
99
|
+
assert_raises(NameError) { a }
|
94
100
|
assert_equal(0, f.())
|
95
101
|
match(1) do
|
96
102
|
with(a) do
|
@@ -105,7 +111,7 @@ class TestStandard < Test::Unit::TestCase
|
|
105
111
|
end
|
106
112
|
|
107
113
|
def test_override_singleton_method
|
108
|
-
|
114
|
+
omit 'Module#prepend is not defined' unless Module.respond_to?(:prepend, true)
|
109
115
|
match(0) do
|
110
116
|
with(_test_override_singleton_method) do
|
111
117
|
def self._test_override_singleton_method
|
@@ -119,12 +125,12 @@ class TestStandard < Test::Unit::TestCase
|
|
119
125
|
def test_uscore
|
120
126
|
match([0, 1, Fixnum]) do
|
121
127
|
with(_[_, ! _(Float), _(Fixnum, :==)]) do
|
122
|
-
|
128
|
+
assert_raises(NameError) { _ }
|
123
129
|
end
|
124
130
|
with(_) { flunk }
|
125
131
|
end
|
126
132
|
|
127
|
-
|
133
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
128
134
|
match(0) do
|
129
135
|
with(_(0, :==, nil)) {}
|
130
136
|
end
|
@@ -228,25 +234,25 @@ class TestStandard < Test::Unit::TestCase
|
|
228
234
|
with(_) { flunk }
|
229
235
|
end
|
230
236
|
|
231
|
-
|
237
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
232
238
|
match(0) do
|
233
239
|
with(___) {}
|
234
240
|
end
|
235
241
|
end
|
236
242
|
|
237
|
-
|
243
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
238
244
|
match(0) do
|
239
245
|
with(_[___]) {}
|
240
246
|
end
|
241
247
|
end
|
242
248
|
|
243
|
-
|
249
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
244
250
|
match(0) do
|
245
251
|
with(_[_[___]]) {}
|
246
252
|
end
|
247
253
|
end
|
248
254
|
|
249
|
-
|
255
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
250
256
|
match(0) do
|
251
257
|
with(_[a, ___, ___]) {}
|
252
258
|
end
|
@@ -304,6 +310,18 @@ class TestStandard < Test::Unit::TestCase
|
|
304
310
|
end
|
305
311
|
with(_) { flunk }
|
306
312
|
end
|
313
|
+
|
314
|
+
match([0, 1]) do
|
315
|
+
with(_[a, __0, *_]) do
|
316
|
+
assert_equal([0, 1], a)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
match([0, 1]) do
|
321
|
+
with(_[a, __0?, *_]) do
|
322
|
+
assert_equal([], a)
|
323
|
+
end
|
324
|
+
end
|
307
325
|
end
|
308
326
|
|
309
327
|
def test_sequence
|
@@ -382,25 +400,25 @@ class TestStandard < Test::Unit::TestCase
|
|
382
400
|
with(_) { flunk }
|
383
401
|
end
|
384
402
|
|
385
|
-
|
403
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
386
404
|
match(0) do
|
387
405
|
with(Seq()) {}
|
388
406
|
end
|
389
407
|
end
|
390
408
|
|
391
|
-
|
409
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
392
410
|
match(0) do
|
393
411
|
with(_[Seq()]) {}
|
394
412
|
end
|
395
413
|
end
|
396
414
|
|
397
|
-
|
415
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
398
416
|
match([0]) do
|
399
417
|
with(_[a & Seq(0)]) {}
|
400
418
|
end
|
401
419
|
end
|
402
420
|
|
403
|
-
|
421
|
+
assert_raises(NotImplementedError) do
|
404
422
|
match([0]) do
|
405
423
|
with(_[Seq(a & Fixnum, ___), ___]) {}
|
406
424
|
end
|
@@ -448,7 +466,7 @@ class TestStandard < Test::Unit::TestCase
|
|
448
466
|
with(_) { flunk }
|
449
467
|
end
|
450
468
|
|
451
|
-
|
469
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
452
470
|
match(1) do
|
453
471
|
with(a | b) {}
|
454
472
|
end
|
@@ -459,19 +477,19 @@ class TestStandard < Test::Unit::TestCase
|
|
459
477
|
with(_) { flunk }
|
460
478
|
end
|
461
479
|
|
462
|
-
|
480
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
463
481
|
match(1) do
|
464
482
|
with(! a) {}
|
465
483
|
end
|
466
484
|
end
|
467
485
|
|
468
|
-
|
486
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
469
487
|
match(1) do
|
470
488
|
with(a | ___) {}
|
471
489
|
end
|
472
490
|
end
|
473
491
|
|
474
|
-
|
492
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
475
493
|
match(1) do
|
476
494
|
with(a & ___) {}
|
477
495
|
end
|
@@ -492,25 +510,25 @@ class TestStandard < Test::Unit::TestCase
|
|
492
510
|
with(_) { flunk }
|
493
511
|
end
|
494
512
|
|
495
|
-
|
513
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
496
514
|
match(1) do
|
497
515
|
with(And()) {}
|
498
516
|
end
|
499
517
|
end
|
500
518
|
|
501
|
-
|
519
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
502
520
|
match(1) do
|
503
521
|
with(Or()) {}
|
504
522
|
end
|
505
523
|
end
|
506
524
|
|
507
|
-
|
525
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
508
526
|
match(1) do
|
509
527
|
with(Not()) {}
|
510
528
|
end
|
511
529
|
end
|
512
530
|
|
513
|
-
|
531
|
+
assert_raises(PatternMatch::MalformedPatternError) do
|
514
532
|
match(1) do
|
515
533
|
with(Not(0, 1)) {}
|
516
534
|
end
|
@@ -522,14 +540,14 @@ class TestStandard < Test::Unit::TestCase
|
|
522
540
|
end
|
523
541
|
|
524
542
|
def test_match_too_many_arguments
|
525
|
-
|
543
|
+
assert_raises(ArgumentError) do
|
526
544
|
match(0, 1) do
|
527
545
|
end
|
528
546
|
end
|
529
547
|
end
|
530
548
|
|
531
549
|
def test_deconstructor_class
|
532
|
-
|
550
|
+
assert_raises(NotImplementedError) do
|
533
551
|
c = Class.new
|
534
552
|
match(0) do
|
535
553
|
with(c.(a)) do
|
@@ -610,4 +628,18 @@ class TestStandard < Test::Unit::TestCase
|
|
610
628
|
with(_) { flunk }
|
611
629
|
end
|
612
630
|
end
|
631
|
+
|
632
|
+
def test_refinements
|
633
|
+
if ENV['DISABLE_REFINEMENTS']
|
634
|
+
assert_kind_of(PatternMatch.const_get(:Pattern), eval('Class.()', TOPLEVEL_BINDING))
|
635
|
+
assert_equal(0, eval('match(0) { with(_) { 0 } }', TOPLEVEL_BINDING))
|
636
|
+
else
|
637
|
+
assert_raises(NoMethodError) do
|
638
|
+
eval('Class.()', TOPLEVEL_BINDING)
|
639
|
+
end
|
640
|
+
assert_raises(NoMethodError) do
|
641
|
+
eval('match(0) { with(_) { 0 } }', TOPLEVEL_BINDING)
|
642
|
+
end
|
643
|
+
end
|
644
|
+
end
|
613
645
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pattern-match
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kazuki Tsujimoto
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-02-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: test-unit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rake
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -56,6 +70,7 @@ files:
|
|
56
70
|
- lib/pattern-match.rb
|
57
71
|
- lib/pattern-match/core.rb
|
58
72
|
- lib/pattern-match/deconstructor.rb
|
73
|
+
- lib/pattern-match/disable_refinements.rb
|
59
74
|
- lib/pattern-match/experimental.rb
|
60
75
|
- lib/pattern-match/version.rb
|
61
76
|
- pattern-match.gemspec
|
@@ -63,7 +78,9 @@ files:
|
|
63
78
|
- test/test_experimental.rb
|
64
79
|
- test/test_standard.rb
|
65
80
|
homepage: https://github.com/k-tsj/pattern-match
|
66
|
-
licenses:
|
81
|
+
licenses:
|
82
|
+
- 2-clause BSDL
|
83
|
+
- Ruby's
|
67
84
|
metadata: {}
|
68
85
|
post_install_message:
|
69
86
|
rdoc_options:
|
@@ -83,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
100
|
version: '0'
|
84
101
|
requirements: []
|
85
102
|
rubyforge_project:
|
86
|
-
rubygems_version: 2.
|
103
|
+
rubygems_version: 2.4.5
|
87
104
|
signing_key:
|
88
105
|
specification_version: 4
|
89
106
|
summary: A pattern matching library
|