pattern-match 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a5dfb4c46f1d15a2d58257a25701821fb2346904
4
- data.tar.gz: 65976df31a660ee698f2480a1532c4b51bb38f7c
3
+ metadata.gz: 71fd4640c715750480dcad518ebc8fe68d468bf7
4
+ data.tar.gz: 84c2f108c050569e0dd6b9eb2f3ff79900ef65a3
5
5
  SHA512:
6
- metadata.gz: fb509e20044ecfb152ae2211782d4c4fd0c3b39e31f9a9554b28f47c4e1fc9dbeb724f5cc17c3c60ac2c4c9e874648eebd2830db5d97761b8d1c96767ddaf879
7
- data.tar.gz: 29110d2a035d427dcb48909f8bfd28353dd0b3dd6c0346438a5552761e2618bdf377dc8072ba4a578967a569d5481b64025bdac1780a6c73bedc9007faea7b85
6
+ metadata.gz: ba8572f327ebe6fef3109d1fe7d14ce22146a33e7c5602afc3457fa7a17110699ff1683af2d9f0cda81f98b124cc495a2a3923ef84ae5bca9df52f81ba82042f
7
+ data.tar.gz: af9f39647b62a984634f30afa28c5a7ad6d3d9b1fb39fdda5599aee5ffae9033de99aee5c6024178f23482800ee80478e1d4949857638ec0fb8233f21811b0b5
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  .bundle
2
2
  Gemfile.lock
3
+ coverage
3
4
  pkg/*
4
5
  vendor/*
@@ -2,4 +2,5 @@ rvm:
2
2
  - 1.9.2
3
3
  - 1.9.3
4
4
  - 2.0.0
5
+ - 2.1.0
5
6
  - ruby-head
data/BSDL CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (C) 2012-2013 Kazuki Tsujimoto, All rights reserved.
1
+ Copyright (C) 2012-2014 Kazuki Tsujimoto, All rights reserved.
2
2
 
3
3
  Redistribution and use in source and binary forms, with or without
4
4
  modification, are permitted provided that the following conditions
data/COPYING CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (C) 2012-2013 Kazuki Tsujimoto, All rights reserved.
1
+ Copyright (C) 2012-2014 Kazuki Tsujimoto, All rights reserved.
2
2
 
3
3
  You can redistribute it and/or modify it under either the terms of the
4
4
  2-clause BSDL (see the file BSDL), or the conditions below:
@@ -42,7 +42,7 @@ You can specify pattern guard if you want.
42
42
 
43
43
  == Patterns
44
44
  === Value
45
- An object (expect the instance of PatternMatch::Pattern) is a value pattern.
45
+ An ordinary object is a value pattern.
46
46
 
47
47
  The pattern matches an object such that <code>pattern === object</code>.
48
48
 
@@ -72,7 +72,7 @@ Consider the following example:
72
72
  with(/(.)(.)/.('a', 'b')) { :match } #=> :match
73
73
  end
74
74
 
75
- Array, Regexp object(<code>/(.)(.)/</code>) are deconstructors.
75
+ Array class(<code>Array</code>), Regexp object(<code>/(.)(.)/</code>) are deconstructors.
76
76
  You can use any object has the following features as deconstructor.
77
77
 
78
78
  * PatternMatch::Deconstructable is included in a class of deconstructor
@@ -111,7 +111,7 @@ all objects bound to variable must be equal.
111
111
  <code>And</code>, <code>Or</code>, <code>Not</code> return and/or/not pattern.
112
112
 
113
113
  match([0, [1]]) do
114
- with(a & Finuxm, ! (_[2] | _[3])) { a } #=> 0
114
+ with(a & Fixnum, ! (_[2] | _[3])) { a } #=> 0
115
115
  end
116
116
 
117
117
  match(0) do
@@ -120,12 +120,12 @@ all objects bound to variable must be equal.
120
120
  end
121
121
 
122
122
  === Quantifier
123
- <code>___</code>(triple underscore), <code>___?</code>,
124
- <code>__n</code>(double underscore + n where n >= 0), <code>__n?</code> are quantifier patterns.
123
+ <code>\___</code>, <code>\___?</code>,
124
+ <code>__n</code>(where n >= 0), <code>__n?</code> are quantifier patterns.
125
125
 
126
126
  They are equivalent to <code>*</code>, <code>*?</code>,
127
127
  <code>{n,}</code>, <code>{n,}?</code> in regular expression.
128
- You can write as <code>*pattern</code> instead of <code>pattern, ___</code>.
128
+ You can write as <code>*pattern</code> instead of <code>pattern, \___</code>.
129
129
 
130
130
  match([:a, 0, :b, :c]) do
131
131
  with(_[a & Symbol, ___, b & Fixnum, c & Symbol, ___]) do
@@ -154,6 +154,7 @@ It is equivalent to <code>()</code> in regular expression.
154
154
  * Hash.()
155
155
  * AttributeMatcher
156
156
 
157
+ To use experimental features, you must also require 'pattern-match/experimental'.
157
158
  See source code for more details.
158
159
 
159
160
  == Pattern guard
@@ -220,8 +221,10 @@ Pattern guard can be specified as a second argument to <code>with</code>.
220
221
  end #=> [1, 2, 4, 3, 4, 0]
221
222
 
222
223
  # (D)
224
+ require 'pattern-match/experimental'
225
+
223
226
  match({a: 0, b: 1}) do
224
- with(Hash.(:a, b: Object.(:odd? => true))) do
227
+ with(Hash.(:a, b: Object.(odd?: true))) do
225
228
  a #=> 0
226
229
  end
227
230
  end
@@ -235,6 +238,9 @@ Pattern guard can be specified as a second argument to <code>with</code>.
235
238
  end
236
239
  end
237
240
 
241
+ * {RubyTextProcessing}[https://code.google.com/p/tokland/wiki/RubyTextProcessing]
242
+ * {yhara/tapl-ruby}[https://github.com/yhara/tapl-ruby]
243
+
238
244
  == Reference
239
245
  * {Pattern Matching in Ruby (at Sapporo RubyKaigi 2012) // Speaker Deck}[https://speakerdeck.com/k_tsj/patternmatchinginruby]
240
246
 
@@ -1,832 +1,7 @@
1
1
  # pattern-match.rb
2
2
  #
3
- # Copyright (C) 2012-2013 Kazuki Tsujimoto, All rights reserved.
3
+ # Copyright (C) 2012-2014 Kazuki Tsujimoto, All rights reserved.
4
4
 
5
5
  require 'pattern-match/version'
6
-
7
- module PatternMatch
8
- module Deconstructable
9
- def call(*subpatterns)
10
- if Object == self
11
- PatternKeywordArgStyleDeconstructor.new(Object, :respond_to?, :__send__, *subpatterns)
12
- else
13
- pattern_matcher(*subpatterns)
14
- end
15
- end
16
- end
17
-
18
- class ::Object
19
- def pattern_matcher(*subpatterns)
20
- PatternObjectDeconstructor.new(self, *subpatterns)
21
- end
22
- end
23
-
24
- module AttributeMatcher
25
- def self.included(klass)
26
- class << klass
27
- def pattern_matcher(*subpatterns)
28
- PatternKeywordArgStyleDeconstructor.new(self, :respond_to?, :__send__, *subpatterns)
29
- end
30
- end
31
- end
32
- end
33
-
34
- module KeyMatcher
35
- def self.included(klass)
36
- class << klass
37
- def pattern_matcher(*subpatterns)
38
- PatternKeywordArgStyleDeconstructor.new(self, :has_key?, :[], *subpatterns)
39
- end
40
- end
41
- end
42
- end
43
-
44
- class Pattern
45
- attr_accessor :parent, :next, :prev
46
-
47
- def initialize(*subpatterns)
48
- @parent = nil
49
- @next = nil
50
- @prev = nil
51
- @subpatterns = subpatterns.map {|i| i.kind_of?(Pattern) ? i : PatternValue.new(i) }
52
- set_subpatterns_relation
53
- end
54
-
55
- def vars
56
- @subpatterns.map(&:vars).flatten
57
- end
58
-
59
- def ancestors
60
- root? ? [self] : parent.ancestors.unshift(self)
61
- end
62
-
63
- def binding
64
- vars.each_with_object({}) {|v, h| h[v.name] = v.val }
65
- end
66
-
67
- def &(pattern)
68
- PatternAnd.new(self, pattern)
69
- end
70
-
71
- def |(pattern)
72
- PatternOr.new(self, pattern)
73
- end
74
-
75
- def !@
76
- PatternNot.new(self)
77
- end
78
-
79
- def to_a
80
- [self, PatternQuantifier.new(0, true)]
81
- end
82
-
83
- def quantifier?
84
- raise NotImplementedError
85
- end
86
-
87
- def quantified?
88
- (@next and @next.quantifier?) || (root? ? false : @parent.quantified?)
89
- end
90
-
91
- def root
92
- root? ? self : @parent.root
93
- end
94
-
95
- def root?
96
- @parent == nil
97
- end
98
-
99
- def validate
100
- @subpatterns.each(&:validate)
101
- end
102
-
103
- def match(vals)
104
- if @next and @next.quantifier?
105
- q = @next
106
- repeating_match(vals, q.longest?) do |vs, rest|
107
- if vs.length < q.min_k
108
- next false
109
- end
110
- vs.all? {|v| yield(v) } and q.match(rest)
111
- end
112
- else
113
- if vals.empty?
114
- return false
115
- end
116
- val, *rest = vals
117
- yield(val) and (@next ? @next.match(rest) : rest.empty?)
118
- end
119
- end
120
-
121
- def append(pattern)
122
- if @next
123
- @next.append(pattern)
124
- else
125
- if @subpatterns.empty?
126
- if root?
127
- new_root = PatternAnd.new(self)
128
- self.parent = new_root
129
- end
130
- pattern.parent = @parent
131
- @next = pattern
132
- else
133
- @subpatterns[-1].append(pattern)
134
- end
135
- end
136
- end
137
-
138
- private
139
-
140
- def repeating_match(vals, longest)
141
- quantifier = @next
142
- lp = longest_patterns(vals)
143
- (longest ? lp : lp.reverse).each do |(vs, rest)|
144
- vars.each {|i| i.set_bind_to(quantifier) }
145
- begin
146
- if yield vs, rest
147
- return true
148
- end
149
- rescue PatternNotMatch
150
- end
151
- vars.each {|i| i.unset_bind_to(quantifier) }
152
- end
153
- false
154
- end
155
-
156
- def longest_patterns(vals)
157
- vals.length.downto(0).map do |n|
158
- [vals.take(n), vals.drop(n)]
159
- end
160
- end
161
-
162
- def set_subpatterns_relation
163
- @subpatterns.each do |i|
164
- i.parent = self
165
- end
166
- end
167
- end
168
-
169
- class PatternQuantifier < Pattern
170
- attr_reader :min_k
171
-
172
- def initialize(min_k, longest)
173
- super()
174
- @min_k = min_k
175
- @longest = longest
176
- end
177
-
178
- def validate
179
- super
180
- raise MalformedPatternError unless @prev and ! @prev.quantifier?
181
- seqs = ancestors.grep(PatternSequence).reverse
182
- if seqs.any? {|i| i.next and i.next.quantifier? and not i.vars.empty? }
183
- raise NotImplementedError
184
- end
185
- case @parent
186
- when PatternObjectDeconstructor
187
- # do nothing
188
- when PatternSequence
189
- # do nothing
190
- else
191
- raise MalformedPatternError
192
- end
193
- end
194
-
195
- def quantifier?
196
- true
197
- end
198
-
199
- def match(vals)
200
- if @next
201
- @next.match(vals)
202
- else
203
- vals.empty?
204
- end
205
- end
206
-
207
- def longest?
208
- @longest
209
- end
210
-
211
- def inspect
212
- "#<#{self.class.name}: min_k=#{@min_k}, longest=#{@longest}>"
213
- end
214
- end
215
-
216
- class PatternElement < Pattern
217
- def quantifier?
218
- false
219
- end
220
- end
221
-
222
- class PatternDeconstructor < PatternElement
223
- end
224
-
225
- class PatternObjectDeconstructor < PatternDeconstructor
226
- def initialize(deconstructor, *subpatterns)
227
- super(*subpatterns)
228
- @deconstructor = deconstructor
229
- end
230
-
231
- def match(vals)
232
- super do |val|
233
- deconstructed_vals = @deconstructor.deconstruct(val)
234
- if @subpatterns.empty?
235
- next deconstructed_vals.empty?
236
- end
237
- @subpatterns[0].match(deconstructed_vals)
238
- end
239
- end
240
-
241
- def inspect
242
- "#<#{self.class.name}: deconstructor=#{@deconstructor.inspect}, subpatterns=#{@subpatterns.inspect}>"
243
- end
244
-
245
- private
246
-
247
- def set_subpatterns_relation
248
- super
249
- @subpatterns.each_cons(2) do |a, b|
250
- a.next = b
251
- b.prev = a
252
- end
253
- end
254
- end
255
-
256
- class PatternKeywordArgStyleDeconstructor < PatternDeconstructor
257
- def initialize(klass, checker, getter, *keyarg_subpatterns)
258
- spec = normalize_keyword_arg(keyarg_subpatterns)
259
- super(*spec.values)
260
- @klass = klass
261
- @checker = checker
262
- @getter = getter
263
- @spec = spec
264
- end
265
-
266
- def match(vals)
267
- super do |val|
268
- next false unless val.kind_of?(@klass)
269
- next false unless @spec.keys.all? {|k| val.__send__(@checker, k) }
270
- @spec.all? do |k, pat|
271
- pat.match([val.__send__(@getter, k)]) rescue false
272
- end
273
- end
274
- end
275
-
276
- def inspect
277
- "#<#{self.class.name}: klass=#{@klass.inspect}, spec=#{@spec.inspect}>"
278
- end
279
-
280
- private
281
-
282
- def normalize_keyword_arg(subpatterns)
283
- syms = subpatterns.take_while {|i| i.kind_of?(Symbol) }
284
- rest = subpatterns.drop(syms.length)
285
- hash = case rest.length
286
- when 0
287
- {}
288
- when 1
289
- rest[0]
290
- else
291
- raise MalformedPatternError
292
- end
293
- variables = Hash[syms.map {|i, h| [i, PatternVariable.new(i)] }]
294
- Hash[variables.merge(hash).map {|k, v| [k, v.kind_of?(Pattern) ? v : PatternValue.new(v)] }]
295
- end
296
- end
297
-
298
- class PatternVariable < PatternElement
299
- attr_reader :name, :val
300
-
301
- def initialize(name)
302
- super()
303
- @name = name
304
- @val = nil
305
- @bind_to = nil
306
- end
307
-
308
- def match(vals)
309
- super do |val|
310
- bind(val)
311
- true
312
- end
313
- end
314
-
315
- def vars
316
- [self]
317
- end
318
-
319
- def set_bind_to(quantifier)
320
- n = nest_level(quantifier)
321
- if n == 0
322
- @val = @bind_to = []
323
- else
324
- outer = @val
325
- (n - 1).times do
326
- outer = outer[-1]
327
- end
328
- @bind_to = []
329
- outer << @bind_to
330
- end
331
- end
332
-
333
- def unset_bind_to(quantifier)
334
- n = nest_level(quantifier)
335
- @bind_to = nil
336
- if n == 0
337
- # do nothing
338
- else
339
- outer = @val
340
- (n - 1).times do
341
- outer = outer[-1]
342
- end
343
- outer.pop
344
- end
345
- end
346
-
347
- def inspect
348
- "#<#{self.class.name}: name=#{name.inspect}, val=#{@val.inspect}>"
349
- end
350
-
351
- private
352
-
353
- def bind(val)
354
- if quantified?
355
- @bind_to << val
356
- else
357
- @val = val
358
- end
359
- end
360
-
361
- def nest_level(quantifier)
362
- raise PatternMatchError unless quantifier.kind_of?(PatternQuantifier)
363
- qs = ancestors.map {|i| (i.next and i.next.quantifier?) ? i.next : nil }.find_all {|i| i }.reverse
364
- qs.index(quantifier) || (raise PatternMatchError)
365
- end
366
- end
367
-
368
- class PatternValue < PatternElement
369
- def initialize(val, compare_by = :===)
370
- super()
371
- @val = val
372
- @compare_by = compare_by
373
- end
374
-
375
- def match(vals)
376
- super do |val|
377
- @val.__send__(@compare_by, val)
378
- end
379
- end
380
-
381
- def inspect
382
- "#<#{self.class.name}: val=#{@val.inspect}>"
383
- end
384
- end
385
-
386
- class PatternSequence < PatternElement
387
- class PatternRewind < PatternElement
388
- attr_reader :ntimes
389
-
390
- def initialize(ntimes, head_pattern, next_pattern)
391
- super()
392
- @ntimes = ntimes
393
- @head = head_pattern
394
- @next = next_pattern
395
- end
396
-
397
- def match(vals)
398
- if @ntimes > 0
399
- @ntimes -= 1
400
- @head.match(vals)
401
- else
402
- @next ? @next.match(vals) : vals.empty?
403
- end
404
- end
405
-
406
- def inspect
407
- "#<#{self.class.name}: ntimes=#{@ntimes} head=#{@head.inspect} next=#{@next.inspect}>"
408
- end
409
- end
410
-
411
- def match(vals)
412
- if @next and @next.quantifier?
413
- repeating_match(vals, @next.longest?) do |rewind|
414
- if rewind.ntimes < @next.min_k
415
- next false
416
- end
417
- rewind.match(vals)
418
- end
419
- else
420
- with_rewind(make_rewind(1)) do |rewind|
421
- rewind.match(vals)
422
- end
423
- end
424
- end
425
-
426
- def validate
427
- super
428
- if @subpatterns.empty?
429
- raise MalformedPatternError
430
- end
431
- case @parent
432
- when PatternObjectDeconstructor
433
- # do nothing
434
- when PatternSequence
435
- # do nothing
436
- else
437
- raise MalformedPatternError
438
- end
439
- end
440
-
441
- def inspect
442
- "#<#{self.class.name}: subpatterns=#{@subpatterns.inspect}>"
443
- end
444
-
445
- private
446
-
447
- def make_rewind(n)
448
- PatternRewind.new(n, @subpatterns[0], (@next and @next.quantifier?) ? @next.next : @next)
449
- end
450
-
451
- def repeating_match(vals, longest)
452
- quantifier = @next
453
- lp = longest_patterns(vals)
454
- (longest ? lp : lp.reverse).each do |rewind|
455
- vars.each {|i| i.set_bind_to(quantifier) }
456
- begin
457
- with_rewind(rewind) do |rewind|
458
- if yield rewind
459
- return true
460
- end
461
- end
462
- rescue PatternNotMatch
463
- end
464
- vars.each {|i| i.unset_bind_to(quantifier) }
465
- end
466
- false
467
- end
468
-
469
- def longest_patterns(vals)
470
- vals.length.downto(0).map do |n|
471
- make_rewind(n)
472
- end
473
- end
474
-
475
- def with_rewind(rewind)
476
- @subpatterns[-1].next = rewind
477
- yield rewind
478
- ensure
479
- @subpatterns[-1].next = nil
480
- end
481
-
482
- def set_subpatterns_relation
483
- super
484
- @subpatterns.each_cons(2) do |a, b|
485
- a.next = b
486
- b.prev = a
487
- end
488
- end
489
- end
490
-
491
- class PatternAnd < PatternElement
492
- def match(vals)
493
- super do |val|
494
- @subpatterns.all? {|i| i.match([val]) }
495
- end
496
- end
497
-
498
- def validate
499
- super
500
- raise MalformedPatternError if @subpatterns.empty?
501
- end
502
-
503
- def inspect
504
- "#<#{self.class.name}: subpatterns=#{@subpatterns.inspect}>"
505
- end
506
- end
507
-
508
- class PatternOr < PatternElement
509
- def match(vals)
510
- super do |val|
511
- @subpatterns.find do |i|
512
- begin
513
- i.match([val])
514
- rescue PatternNotMatch
515
- false
516
- end
517
- end
518
- end
519
- end
520
-
521
- def validate
522
- super
523
- raise MalformedPatternError if @subpatterns.empty?
524
- raise MalformedPatternError unless vars.empty?
525
- end
526
-
527
- def inspect
528
- "#<#{self.class.name}: subpatterns=#{@subpatterns.inspect}>"
529
- end
530
- end
531
-
532
- class PatternNot < PatternElement
533
- def match(vals)
534
- super do |val|
535
- begin
536
- ! @subpatterns[0].match([val])
537
- rescue PatternNotMatch
538
- true
539
- end
540
- end
541
- end
542
-
543
- def validate
544
- super
545
- raise MalformedPatternError unless @subpatterns.length == 1
546
- raise MalformedPatternError unless vars.empty?
547
- end
548
-
549
- def inspect
550
- "#<#{self.class.name}: subpatterns=#{@subpatterns.inspect}>"
551
- end
552
- end
553
-
554
- class PatternCondition < PatternElement
555
- def initialize(&condition)
556
- super()
557
- @condition = condition
558
- end
559
-
560
- def match(vals)
561
- return false unless vals.empty?
562
- if @condition.call
563
- @next ? @next.match(vals) : true
564
- else
565
- false
566
- end
567
- end
568
-
569
- def validate
570
- super
571
- raise MalformedPatternError if ancestors.find {|i| i.next and ! i.next.kind_of?(PatternCondition) }
572
- end
573
-
574
- def inspect
575
- "#<#{self.class.name}: condition=#{@condition.inspect}>"
576
- end
577
- end
578
-
579
- class Env < BasicObject
580
- def initialize(ctx, val)
581
- @ctx = ctx
582
- @val = val
583
- end
584
-
585
- private
586
-
587
- def with(pat_or_val, guard_proc = nil, &block)
588
- ctx = @ctx
589
- pat = pat_or_val.kind_of?(Pattern) ? pat_or_val : PatternValue.new(pat_or_val)
590
- pat.append(
591
- PatternCondition.new do
592
- pat.vars.each_with_object({}) do |v, h|
593
- if h.has_key?(v.name)
594
- unless h[v.name] == v.val
595
- ::Kernel.raise PatternNotMatch
596
- end
597
- else
598
- h[v.name] = v.val
599
- end
600
- end
601
- true
602
- end
603
- )
604
- if guard_proc
605
- pat.append(PatternCondition.new { with_tmpbinding(ctx, pat.binding, &guard_proc) })
606
- end
607
- pat.validate
608
- if pat.match([@val])
609
- ret = with_tmpbinding(ctx, pat.binding, &block)
610
- ::Kernel.throw(:exit_match, ret)
611
- else
612
- nil
613
- end
614
- rescue PatternNotMatch
615
- end
616
-
617
- def guard(&block)
618
- block
619
- end
620
-
621
- def ___
622
- PatternQuantifier.new(0, true)
623
- end
624
-
625
- def ___?
626
- PatternQuantifier.new(0, false)
627
- end
628
-
629
- def method_missing(name, *)
630
- case name.to_s
631
- when /\A__(\d+)(\??)\z/
632
- PatternQuantifier.new($1.to_i, ! $2.empty?)
633
- else
634
- PatternVariable.new(name)
635
- end
636
- end
637
-
638
- def _(*vals)
639
- case vals.length
640
- when 0
641
- uscore = PatternVariable.new(:_)
642
- class << uscore
643
- def [](*args)
644
- Array.call(*args)
645
- end
646
-
647
- def vars
648
- []
649
- end
650
-
651
- private
652
-
653
- def bind(val)
654
- end
655
- end
656
- uscore
657
- when 1
658
- PatternValue.new(vals[0])
659
- when 2
660
- PatternValue.new(vals[0], vals[1])
661
- else
662
- raise MalformedPatternError
663
- end
664
- end
665
-
666
- alias __ _
667
- alias _l _
668
-
669
- def Seq(*subpatterns)
670
- PatternSequence.new(*subpatterns)
671
- end
672
-
673
- def And(*subpatterns)
674
- PatternAnd.new(*subpatterns)
675
- end
676
-
677
- def Or(*subpatterns)
678
- PatternOr.new(*subpatterns)
679
- end
680
-
681
- def Not(*subpatterns)
682
- PatternNot.new(*subpatterns)
683
- end
684
-
685
-
686
- class TmpBindingModule < ::Module
687
- end
688
-
689
- def with_tmpbinding(obj, binding, &block)
690
- tmpbinding_module(obj).instance_eval do
691
- begin
692
- binding.each do |name, val|
693
- stack = @stacks[name]
694
- if stack.empty?
695
- define_method(name) { stack[-1] }
696
- private name
697
- end
698
- stack.push(val)
699
- end
700
- obj.instance_eval(&block)
701
- ensure
702
- binding.each do |name, _|
703
- @stacks[name].pop
704
- if @stacks[name].empty?
705
- remove_method(name)
706
- end
707
- end
708
- end
709
- end
710
- end
711
-
712
- def tmpbinding_module(obj)
713
- m = obj.singleton_class.ancestors.find {|i| i.kind_of?(TmpBindingModule) }
714
- unless m
715
- m = TmpBindingModule.new
716
- m.instance_eval do
717
- @stacks = ::Hash.new {|h, k| h[k] = [] }
718
- end
719
- obj.singleton_class.class_eval do
720
- if respond_to?(:prepend, true)
721
- prepend m
722
- else
723
- include m
724
- end
725
- end
726
- end
727
- m
728
- end
729
- end
730
-
731
- class PatternNotMatch < Exception; end
732
- class PatternMatchError < StandardError; end
733
- class NoMatchingPatternError < PatternMatchError; end
734
- class MalformedPatternError < PatternMatchError; end
735
-
736
- # Make Pattern and its subclasses/Env private.
737
- if respond_to?(:private_constant)
738
- constants.each do |c|
739
- klass = const_get(c)
740
- next unless klass.kind_of?(Class)
741
- if klass <= Pattern
742
- private_constant c
743
- end
744
- end
745
- private_constant :Env
746
- end
747
- end
748
-
749
- module Kernel
750
- private
751
-
752
- def match(*vals, &block)
753
- do_match = Proc.new do |val|
754
- env = PatternMatch.const_get(:Env).new(self, val)
755
- catch(:exit_match) do
756
- env.instance_eval(&block)
757
- raise ::PatternMatch::NoMatchingPatternError
758
- end
759
- end
760
- case vals.length
761
- when 0
762
- do_match
763
- when 1
764
- do_match.(vals[0])
765
- else
766
- raise ArgumentError, "wrong number of arguments (#{vals.length} for 0..1)"
767
- end
768
- end
769
- end
770
-
771
- class Class
772
- include PatternMatch::Deconstructable
773
-
774
- def deconstruct(val)
775
- raise NotImplementedError, "need to define `#{__method__}'"
776
- end
777
-
778
- private
779
-
780
- def accept_self_instance_only(val)
781
- raise PatternMatch::PatternNotMatch unless val.kind_of?(self)
782
- end
783
- end
784
-
785
- class Hash
786
- include PatternMatch::KeyMatcher
787
- end
788
-
789
- class << Array
790
- def deconstruct(val)
791
- accept_self_instance_only(val)
792
- val
793
- end
794
- end
795
-
796
- class << Struct
797
- def deconstruct(val)
798
- accept_self_instance_only(val)
799
- val.values
800
- end
801
- end
802
-
803
- class << Complex
804
- def deconstruct(val)
805
- accept_self_instance_only(val)
806
- val.rect
807
- end
808
- end
809
-
810
- class << Rational
811
- def deconstruct(val)
812
- accept_self_instance_only(val)
813
- [val.numerator, val.denominator]
814
- end
815
- end
816
-
817
- class << MatchData
818
- def deconstruct(val)
819
- accept_self_instance_only(val)
820
- val.captures.empty? ? [val[0]] : val.captures
821
- end
822
- end
823
-
824
- class Regexp
825
- include PatternMatch::Deconstructable
826
-
827
- def deconstruct(val)
828
- m = Regexp.new("\\A#{source}\\z", options).match(val.to_s)
829
- raise PatternMatch::PatternNotMatch unless m
830
- m.captures.empty? ? [m[0]] : m.captures
831
- end
832
- end
6
+ require 'pattern-match/core'
7
+ require 'pattern-match/deconstructor'