pattern-match 0.5.0 → 0.5.1

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 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'