pattern-match 0.5.1 → 1.0.0
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.
- 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
|