patm 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +24 -2
- data/lib/patm.rb +178 -43
- data/patm.gemspec +1 -1
- data/spec/patm_spec.rb +55 -6
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d2a4036ae8e3a9b302bd189406ebb284f3efcc54
|
4
|
+
data.tar.gz: 10b6f6831b67755280f6e6ba5faf145a3ddf8910
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50f3198622f079bc716eb064a4e8cfbdad3f63bfd6f7c9f76c750fefd35e86301513c79542b777c5c4d7594165632acdcbb00e213661a544cc8e61fbf439ef72
|
7
|
+
data.tar.gz: 093665d2fcb727165d6fda3cd9c214805be766f70b15cf565ec7670aa585a21c280514687298dd2aa64558248633fbee7f815f836a9e6207c00ced7ece6e2b7e
|
data/README.md
CHANGED
@@ -102,21 +102,36 @@ end
|
|
102
102
|
|
103
103
|
## Patterns
|
104
104
|
|
105
|
-
###
|
105
|
+
### Value
|
106
106
|
|
107
|
-
|
107
|
+
Value patterns such as `1, :x, String, ...` matches if `pattern === target_value` is true.
|
108
108
|
|
109
109
|
### Array
|
110
110
|
|
111
|
+
`[1, 2, _any]` matches `[1, 2, 3]`, `[1, 2, :x]`, etc.
|
112
|
+
|
111
113
|
`[1, 2, _xs]` matches `[1, 2]`, `[1, 2, 3]`, `[1, 2, 3, 4]`, etc.
|
114
|
+
|
112
115
|
`[1, _xs, 2]` matches `[1, 2]`, `[1, 10, 2]`, etc.
|
113
116
|
|
114
117
|
Note: More than one `_xs` in same array is invalid.
|
115
118
|
|
119
|
+
### Hash
|
120
|
+
|
121
|
+
`{a: 1}` matches `{a: 1}`, `{a: 1, b: 2}`, etc.
|
122
|
+
|
123
|
+
`{a: 1, Patm.exact => true}` matches only `{a: 1}`.
|
124
|
+
|
125
|
+
`{a: 1, b: Patm.opt(2)}` matches `{a: 1}`, `{a: 1, b: 2}`.
|
126
|
+
|
116
127
|
### Capture
|
117
128
|
|
118
129
|
`_1`, `_2`, etc matches any value, and capture the value as correspond match group.
|
119
130
|
|
131
|
+
`Pattern#[capture_name]` also used for capture.`Patm._any[:foo]` capture any value as `foo`.
|
132
|
+
|
133
|
+
Captured values are accessible through `Match#_1, _2, ...` and `Match#[capture_name]`
|
134
|
+
|
120
135
|
### Compose
|
121
136
|
|
122
137
|
`_1&[_any, _any]` matches any two element array, and capture the array as _1.
|
@@ -125,6 +140,13 @@ Note: More than one `_xs` in same array is invalid.
|
|
125
140
|
|
126
141
|
## Changes
|
127
142
|
|
143
|
+
### 2.0.0(Unreleased)
|
144
|
+
|
145
|
+
- Named capture
|
146
|
+
- Patm::GROUPS is obsolete. Use `pattern[number_or_name]` or `Patm._1, _2, ...` instead.
|
147
|
+
- More optimize for compiled pattern.
|
148
|
+
- Hash patterns
|
149
|
+
|
128
150
|
### 1.0.0
|
129
151
|
|
130
152
|
- DSL
|
data/lib/patm.rb
CHANGED
@@ -5,7 +5,7 @@ module Patm
|
|
5
5
|
case plain
|
6
6
|
when Pattern
|
7
7
|
plain
|
8
|
-
when Array
|
8
|
+
when ::Array
|
9
9
|
array = plain.map{|a| build_from(a)}
|
10
10
|
rest_index = array.index(&:rest?)
|
11
11
|
if rest_index
|
@@ -16,13 +16,47 @@ module Patm
|
|
16
16
|
else
|
17
17
|
Arr.new(array)
|
18
18
|
end
|
19
|
+
when ::Hash
|
20
|
+
Hash.new(
|
21
|
+
plain.each_with_object({}) do|(k, v), h|
|
22
|
+
h[k] = build_from(v) if k != Patm.exact
|
23
|
+
end,
|
24
|
+
plain[Patm.exact]
|
25
|
+
)
|
19
26
|
else
|
20
27
|
Obj.new(plain)
|
21
28
|
end
|
22
29
|
end
|
23
30
|
|
31
|
+
module Util
|
32
|
+
def self.compile_value(value, free_index)
|
33
|
+
if value.is_a?(Numeric) || value.is_a?(String) || value.is_a?(Symbol)
|
34
|
+
[
|
35
|
+
value.inspect,
|
36
|
+
[],
|
37
|
+
free_index,
|
38
|
+
]
|
39
|
+
else
|
40
|
+
[
|
41
|
+
"_ctx[#{free_index}]",
|
42
|
+
[value],
|
43
|
+
free_index + 1,
|
44
|
+
]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Use in Hash pattern.
|
50
|
+
def opt
|
51
|
+
Opt.new(self)
|
52
|
+
end
|
53
|
+
|
24
54
|
def execute(match, obj); true; end
|
25
55
|
|
56
|
+
def opt?
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
26
60
|
def rest?
|
27
61
|
false
|
28
62
|
end
|
@@ -31,14 +65,18 @@ module Patm
|
|
31
65
|
And.new([self, rhs])
|
32
66
|
end
|
33
67
|
|
68
|
+
def [](name)
|
69
|
+
self & Named.new(name)
|
70
|
+
end
|
71
|
+
|
34
72
|
def compile
|
35
73
|
src, context, _ = self.compile_internal(0)
|
36
74
|
|
37
|
-
Compiled.new(self.inspect, src, context)
|
75
|
+
Compiled.new(self.inspect, src || "true", context)
|
38
76
|
end
|
39
77
|
|
40
|
-
# free_index:Numeric -> [src, context, free_index]
|
41
|
-
# variables: _ctx, _match,
|
78
|
+
# free_index:Numeric -> target_name:String -> [src:String|nil, context:Array, free_index:Numeric]
|
79
|
+
# variables: _ctx, _match, (target_name)
|
42
80
|
def compile_internal(free_index, target_name = "_obj")
|
43
81
|
[
|
44
82
|
"_ctx[#{free_index}].execute(_match, #{target_name})",
|
@@ -69,6 +107,82 @@ module Patm
|
|
69
107
|
def inspect; "<compiled>#{@desc}"; end
|
70
108
|
end
|
71
109
|
|
110
|
+
class Hash < self
|
111
|
+
def initialize(hash, exact)
|
112
|
+
@pat = hash
|
113
|
+
@exact = exact
|
114
|
+
@non_opt_count = @pat.values.count{|v| !v.opt? }
|
115
|
+
end
|
116
|
+
def execute(match, obj)
|
117
|
+
return false unless obj.is_a?(::Hash)
|
118
|
+
obj.size >= @non_opt_count &&
|
119
|
+
(!@exact || obj.keys.all?{|k| @pat.has_key?(k) }) &&
|
120
|
+
@pat.all? {|k, pat|
|
121
|
+
if obj.has_key?(k)
|
122
|
+
pat.execute(match, obj[k])
|
123
|
+
else
|
124
|
+
pat.opt?
|
125
|
+
end
|
126
|
+
}
|
127
|
+
end
|
128
|
+
def inspect; @pat.inspect; end
|
129
|
+
def compile_internal(free_index, target_name = "_obj")
|
130
|
+
i = free_index
|
131
|
+
ctxs = []
|
132
|
+
src = []
|
133
|
+
|
134
|
+
ctxs << [@pat]
|
135
|
+
i += 1
|
136
|
+
|
137
|
+
pat = "_ctx[#{free_index}]"
|
138
|
+
src << "#{target_name}.is_a?(::Hash)"
|
139
|
+
src << "#{target_name}.size >= #{@non_opt_count}"
|
140
|
+
if @exact
|
141
|
+
src << "#{target_name}.keys.all?{|k| #{pat}.has_key?(k) }"
|
142
|
+
end
|
143
|
+
tname = "#{target_name}_elm"
|
144
|
+
@pat.each do|k, v|
|
145
|
+
key_src, c, i = Util.compile_value(k, i)
|
146
|
+
ctxs << c
|
147
|
+
s, c, i = v.compile_internal(i, tname)
|
148
|
+
body =
|
149
|
+
if s
|
150
|
+
"(#{tname} = #{target_name}[#{key_src}]; #{s})"
|
151
|
+
else
|
152
|
+
"true"
|
153
|
+
end
|
154
|
+
src <<
|
155
|
+
if v.opt?
|
156
|
+
"(!#{target_name}.has_key?(#{key_src}) || #{body})"
|
157
|
+
else
|
158
|
+
"(#{target_name}.has_key?(#{key_src}) && #{body})"
|
159
|
+
end
|
160
|
+
ctxs << c
|
161
|
+
end
|
162
|
+
[
|
163
|
+
src.join(" &&\n"),
|
164
|
+
ctxs.flatten(1),
|
165
|
+
i,
|
166
|
+
]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class Opt < self
|
171
|
+
def initialize(pat)
|
172
|
+
@pat = pat
|
173
|
+
end
|
174
|
+
def opt?
|
175
|
+
true
|
176
|
+
end
|
177
|
+
def execute(match, obj)
|
178
|
+
@pat.execute(match, obj)
|
179
|
+
end
|
180
|
+
def inspect; "?#{@pat.inspect}"; end
|
181
|
+
def compile_internal(free_index, target_name = "_obj")
|
182
|
+
@pat.compile_internal(free_index, target_name)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
72
186
|
class Arr < self
|
73
187
|
def initialize(head, rest = nil, tail = [])
|
74
188
|
@head = head
|
@@ -114,26 +228,28 @@ module Patm
|
|
114
228
|
elm_target_name = "#{target_name}_elm"
|
115
229
|
@head.each_with_index do|h, hi|
|
116
230
|
s, c, i = h.compile_internal(i, elm_target_name)
|
117
|
-
srcs << "(#{elm_target_name} = #{target_name}[#{hi}]; #{s})"
|
231
|
+
srcs << "(#{elm_target_name} = #{target_name}[#{hi}]; #{s})" if s
|
118
232
|
ctxs << c
|
119
233
|
end
|
120
234
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
235
|
+
unless @tail.empty?
|
236
|
+
srcs << "(#{target_name}_t = #{target_name}[(-#{@tail.size})..-1]; true)"
|
237
|
+
@tail.each_with_index do|t, ti|
|
238
|
+
s, c, i = t.compile_internal(i, elm_target_name)
|
239
|
+
srcs << "(#{elm_target_name} = #{target_name}_t[#{ti}]; #{s})" if s
|
240
|
+
ctxs << c
|
241
|
+
end
|
126
242
|
end
|
127
243
|
|
128
244
|
if @rest
|
129
245
|
tname = "#{target_name}_r"
|
130
246
|
s, c, i = @rest.compile_internal(i, tname)
|
131
|
-
srcs << "(#{tname} = #{target_name}[#{@head.size}..-(#{@tail.size+1})];#{s})"
|
247
|
+
srcs << "(#{tname} = #{target_name}[#{@head.size}..-(#{@tail.size+1})];#{s})" if s
|
132
248
|
ctxs << c
|
133
249
|
end
|
134
250
|
|
135
251
|
[
|
136
|
-
srcs.map{|s| "(#{s})"}.join(" &&\n"),
|
252
|
+
srcs.compact.map{|s| "(#{s})"}.join(" &&\n"),
|
137
253
|
ctxs.flatten(1),
|
138
254
|
i
|
139
255
|
]
|
@@ -150,7 +266,7 @@ module Patm
|
|
150
266
|
def inspect; "..."; end
|
151
267
|
def compile_internal(free_index, target_name = "_obj")
|
152
268
|
[
|
153
|
-
|
269
|
+
nil,
|
154
270
|
[],
|
155
271
|
free_index
|
156
272
|
]
|
@@ -171,10 +287,11 @@ module Patm
|
|
171
287
|
end
|
172
288
|
|
173
289
|
def compile_internal(free_index, target_name = "_obj")
|
290
|
+
val_src, c, i = Util.compile_value(@obj, free_index)
|
174
291
|
[
|
175
|
-
"
|
176
|
-
|
177
|
-
|
292
|
+
"#{val_src} === #{target_name}",
|
293
|
+
c,
|
294
|
+
i
|
178
295
|
]
|
179
296
|
end
|
180
297
|
end
|
@@ -184,26 +301,28 @@ module Patm
|
|
184
301
|
def inspect; 'ANY'; end
|
185
302
|
def compile_internal(free_index, target_name = "_obj")
|
186
303
|
[
|
187
|
-
|
304
|
+
nil,
|
188
305
|
[],
|
189
306
|
free_index
|
190
307
|
]
|
191
308
|
end
|
192
309
|
end
|
193
310
|
|
194
|
-
class
|
195
|
-
def initialize(
|
196
|
-
|
311
|
+
class Named < self
|
312
|
+
def initialize(name)
|
313
|
+
raise ::ArgumentError unless name.is_a?(Symbol) || name.is_a?(Numeric)
|
314
|
+
@name = name
|
197
315
|
end
|
198
|
-
attr_reader :
|
199
|
-
|
200
|
-
|
316
|
+
attr_reader :name
|
317
|
+
alias index name # compatibility
|
318
|
+
def execute(match, obj)
|
319
|
+
match[@name] = obj
|
201
320
|
true
|
202
321
|
end
|
203
|
-
def inspect; "
|
322
|
+
def inspect; "NAMED(#{@name})"; end
|
204
323
|
def compile_internal(free_index, target_name = "_obj")
|
205
324
|
[
|
206
|
-
"_match[#{@
|
325
|
+
"_match[#{@name.inspect}] = #{target_name}; true",
|
207
326
|
[],
|
208
327
|
free_index
|
209
328
|
]
|
@@ -226,11 +345,17 @@ module Patm
|
|
226
345
|
end
|
227
346
|
|
228
347
|
[
|
229
|
-
srcs.map{|s| "(#{s})" }.join(" #{@op_str}\n"),
|
348
|
+
srcs.compact.map{|s| "(#{s})" }.join(" #{@op_str}\n"),
|
230
349
|
ctxs.flatten(1),
|
231
350
|
i
|
232
351
|
]
|
233
352
|
end
|
353
|
+
def rest?
|
354
|
+
@pats.any?(&:rest?)
|
355
|
+
end
|
356
|
+
def opt?
|
357
|
+
@pats.any?(&:opt?)
|
358
|
+
end
|
234
359
|
end
|
235
360
|
|
236
361
|
class Or < LogicalOp
|
@@ -242,9 +367,6 @@ module Patm
|
|
242
367
|
pat.execute(mmatch, obj)
|
243
368
|
end
|
244
369
|
end
|
245
|
-
def rest?
|
246
|
-
@pats.any?(&:rest?)
|
247
|
-
end
|
248
370
|
def inspect
|
249
371
|
"OR(#{@pats.map(&:inspect).join(',')})"
|
250
372
|
end
|
@@ -259,17 +381,12 @@ module Patm
|
|
259
381
|
pat.execute(mmatch, obj)
|
260
382
|
end
|
261
383
|
end
|
262
|
-
def rest?
|
263
|
-
@pats.any?(&:rest?)
|
264
|
-
end
|
265
384
|
def inspect
|
266
385
|
"AND(#{@pats.map(&:inspect).join(',')})"
|
267
386
|
end
|
268
387
|
end
|
269
388
|
end
|
270
389
|
|
271
|
-
GROUP = 100.times.map{|i| Pattern::Group.new(i) }
|
272
|
-
|
273
390
|
def self.or(*pats)
|
274
391
|
Pattern::Or.new(pats.map{|p| Pattern.build_from(p) })
|
275
392
|
end
|
@@ -282,10 +399,28 @@ module Patm
|
|
282
399
|
@xs = Pattern::ArrRest.new
|
283
400
|
end
|
284
401
|
|
402
|
+
# Use in hash value.
|
403
|
+
# Mark this pattern is optional.
|
404
|
+
def self.opt(pat = _any)
|
405
|
+
Pattern::Opt.new(Pattern.build_from(pat))
|
406
|
+
end
|
407
|
+
|
408
|
+
EXACT = Object.new
|
409
|
+
def EXACT.inspect
|
410
|
+
"EXACT"
|
411
|
+
end
|
412
|
+
# Use in Hash key.
|
413
|
+
# Specify exact match or not.
|
414
|
+
def self.exact
|
415
|
+
EXACT
|
416
|
+
end
|
417
|
+
|
418
|
+
PREDEF_GROUP_SIZE = 100
|
419
|
+
|
285
420
|
class <<self
|
286
|
-
|
287
|
-
define_method "_#{
|
288
|
-
|
421
|
+
PREDEF_GROUP_SIZE.times do|i|
|
422
|
+
define_method "_#{i}" do
|
423
|
+
Pattern::Named.new(i)
|
289
424
|
end
|
290
425
|
end
|
291
426
|
end
|
@@ -349,9 +484,9 @@ module Patm
|
|
349
484
|
@group[i] = val
|
350
485
|
end
|
351
486
|
|
352
|
-
|
353
|
-
define_method "_#{
|
354
|
-
self[
|
487
|
+
PREDEF_GROUP_SIZE.times.each do|i|
|
488
|
+
define_method "_#{i}" do
|
489
|
+
self[i]
|
355
490
|
end
|
356
491
|
end
|
357
492
|
end
|
@@ -367,9 +502,9 @@ module Patm
|
|
367
502
|
end
|
368
503
|
|
369
504
|
def [](i); @match[i]; end
|
370
|
-
|
371
|
-
define_method "_#{
|
372
|
-
@match[
|
505
|
+
PREDEF_GROUP_SIZE.times do|i|
|
506
|
+
define_method "_#{i}" do
|
507
|
+
@match[i]
|
373
508
|
end
|
374
509
|
end
|
375
510
|
end
|
data/patm.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.platform = Gem::Platform::RUBY
|
3
3
|
s.name = 'patm'
|
4
|
-
s.version = '
|
4
|
+
s.version = '2.0.0'
|
5
5
|
s.summary = 'PATtern Matching library'
|
6
6
|
s.description = 'Pattern matching library for plain data structure'
|
7
7
|
s.required_ruby_version = '>= 1.9.0'
|
data/spec/patm_spec.rb
CHANGED
@@ -24,14 +24,20 @@ module PatmHelper
|
|
24
24
|
|
25
25
|
def and_capture(g1, g2 = nil, g3 = nil, g4 = nil)
|
26
26
|
these_matches(
|
27
|
-
self, _capture(self, g1, g2, g3, g4)
|
27
|
+
self, _capture(self, {1 => g1, 2 => g2, 3 => g3, 4 => g4})
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def and_named_capture(capture)
|
32
|
+
these_matches(
|
33
|
+
self, _capture(self, capture)
|
28
34
|
)
|
29
35
|
end
|
30
36
|
end
|
31
37
|
|
32
|
-
matcher :_capture do|m,
|
38
|
+
matcher :_capture do|m, capture|
|
33
39
|
match do|_|
|
34
|
-
[m.match[1], m.match[2], m.match[3], m.match[4]] ==
|
40
|
+
[m.match[1], m.match[2], m.match[3], m.match[4]] == capture.values_at(1,2,3,4)
|
35
41
|
end
|
36
42
|
end
|
37
43
|
|
@@ -206,9 +212,9 @@ describe Patm::Pattern do
|
|
206
212
|
it { should match_to([0, 1, 2, 3]).and_capture([2, 3]) }
|
207
213
|
end
|
208
214
|
|
209
|
-
pattern [0, 1, Patm._xs, 2] do
|
210
|
-
it { should match_to([0,1,2]) }
|
211
|
-
it { should match_to([0,1,10,20,30,2]) }
|
215
|
+
pattern [0, 1, Patm._xs[1], 2] do
|
216
|
+
it { should match_to([0,1,2]).and_capture([]) }
|
217
|
+
it { should match_to([0,1,10,20,30,2]).and_capture([10,20,30]) }
|
212
218
|
it { should_not match_to([0,1]) }
|
213
219
|
end
|
214
220
|
|
@@ -217,6 +223,45 @@ describe Patm::Pattern do
|
|
217
223
|
it { should_not match_to [0, [1, 3]] }
|
218
224
|
end
|
219
225
|
|
226
|
+
pattern Patm._any[:x] do
|
227
|
+
it { should match_to("aaa").and_named_capture(:x => "aaa") }
|
228
|
+
end
|
229
|
+
|
230
|
+
pattern(a: Patm._any[1]) do
|
231
|
+
it { should_not match_to {} }
|
232
|
+
it { should match_to(a: 1).and_capture(1) }
|
233
|
+
it { should match_to(a: 1, b: 2).and_capture(1) }
|
234
|
+
end
|
235
|
+
|
236
|
+
pattern(a: Patm._any, Patm.exact => false) do
|
237
|
+
it { should_not match_to(b: 1) }
|
238
|
+
it { should match_to(a: 1) }
|
239
|
+
it { should match_to(a: 1, b: 2) }
|
240
|
+
end
|
241
|
+
|
242
|
+
pattern(a: Patm._any, Patm.exact => true) do
|
243
|
+
it { should_not match_to(b: 1) }
|
244
|
+
it { should match_to(a: 1) }
|
245
|
+
it { should_not match_to(a: 1, b: 2) }
|
246
|
+
end
|
247
|
+
|
248
|
+
pattern(a: Patm._any[1].opt) do
|
249
|
+
it { should match_to({}).and_capture(nil) }
|
250
|
+
it { should match_to({a: 1}).and_capture(1) }
|
251
|
+
end
|
252
|
+
|
253
|
+
pattern(a: Patm._any[1], b: Patm._any[2].opt) do
|
254
|
+
it { should_not match_to({}) }
|
255
|
+
it { should match_to({a: 1}).and_capture(1, nil) }
|
256
|
+
it { should match_to({a: 1, b: 2}).and_capture(1, 2) }
|
257
|
+
end
|
258
|
+
|
259
|
+
pattern({a: 1} => {b: 2}) do
|
260
|
+
it { should_not match_to({a: 1} => {b: 0}) }
|
261
|
+
it { should_not match_to({a: 0} => {b: 2}) }
|
262
|
+
it { should match_to({a: 1} => {b: 2}) }
|
263
|
+
end
|
264
|
+
|
220
265
|
context 'regression' do
|
221
266
|
pattern [:assign, [:var_field, [:@ident, Patm._1, [Patm._2, Patm._3]]], Patm._4] do
|
222
267
|
it { should match_to([:assign, [:var_field, [:@ident, 10, [20, 30]]], false]).and_capture(10, 20, 30, false) }
|
@@ -225,5 +270,9 @@ describe Patm::Pattern do
|
|
225
270
|
it { should match_to [1] }
|
226
271
|
it { should match_to [2] }
|
227
272
|
end
|
273
|
+
pattern [Patm._1, 2, [Patm._any, 3], Patm._xs[1], 4] do
|
274
|
+
it { should match_to([1, 2, [10, 3], 4]).and_capture([]) }
|
275
|
+
it { should match_to([1, 2, [10, 3], 20, 4]).and_capture([20]) }
|
276
|
+
end
|
228
277
|
end
|
229
278
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: patm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- todesking
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-05-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -72,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
72
72
|
version: '0'
|
73
73
|
requirements: []
|
74
74
|
rubyforge_project:
|
75
|
-
rubygems_version: 2.
|
75
|
+
rubygems_version: 2.2.2
|
76
76
|
signing_key:
|
77
77
|
specification_version: 4
|
78
78
|
summary: PATtern Matching library
|