lgierth-rack-mount 0.6.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +36 -0
  3. data/lib/rack/mount.rb +32 -0
  4. data/lib/rack/mount/analysis/frequency.rb +60 -0
  5. data/lib/rack/mount/analysis/histogram.rb +74 -0
  6. data/lib/rack/mount/analysis/splitting.rb +159 -0
  7. data/lib/rack/mount/code_generation.rb +117 -0
  8. data/lib/rack/mount/generatable_regexp.rb +210 -0
  9. data/lib/rack/mount/multimap.rb +53 -0
  10. data/lib/rack/mount/prefix.rb +36 -0
  11. data/lib/rack/mount/regexp_with_named_groups.rb +69 -0
  12. data/lib/rack/mount/route.rb +130 -0
  13. data/lib/rack/mount/route_set.rb +420 -0
  14. data/lib/rack/mount/strexp.rb +68 -0
  15. data/lib/rack/mount/strexp/parser.rb +160 -0
  16. data/lib/rack/mount/strexp/parser.y +34 -0
  17. data/lib/rack/mount/strexp/tokenizer.rb +83 -0
  18. data/lib/rack/mount/strexp/tokenizer.rex +12 -0
  19. data/lib/rack/mount/utils.rb +162 -0
  20. data/lib/rack/mount/vendor/multimap/multimap.rb +569 -0
  21. data/lib/rack/mount/vendor/multimap/multiset.rb +185 -0
  22. data/lib/rack/mount/vendor/multimap/nested_multimap.rb +158 -0
  23. data/lib/rack/mount/vendor/regin/regin.rb +75 -0
  24. data/lib/rack/mount/vendor/regin/regin/alternation.rb +40 -0
  25. data/lib/rack/mount/vendor/regin/regin/anchor.rb +4 -0
  26. data/lib/rack/mount/vendor/regin/regin/atom.rb +54 -0
  27. data/lib/rack/mount/vendor/regin/regin/character.rb +51 -0
  28. data/lib/rack/mount/vendor/regin/regin/character_class.rb +50 -0
  29. data/lib/rack/mount/vendor/regin/regin/collection.rb +77 -0
  30. data/lib/rack/mount/vendor/regin/regin/expression.rb +126 -0
  31. data/lib/rack/mount/vendor/regin/regin/group.rb +85 -0
  32. data/lib/rack/mount/vendor/regin/regin/options.rb +55 -0
  33. data/lib/rack/mount/vendor/regin/regin/parser.rb +520 -0
  34. data/lib/rack/mount/vendor/regin/regin/tokenizer.rb +246 -0
  35. data/lib/rack/mount/vendor/regin/regin/version.rb +3 -0
  36. data/lib/rack/mount/version.rb +3 -0
  37. metadata +140 -0
@@ -0,0 +1,569 @@
1
+ require 'forwardable'
2
+ require 'multiset'
3
+
4
+ # Multimap is a generalization of a map or associative array
5
+ # abstract data type in which more than one value may be associated
6
+ # with and returned for a given key.
7
+ #
8
+ # == Example
9
+ #
10
+ # require 'multimap'
11
+ # map = Multimap.new
12
+ # map["a"] = 100
13
+ # map["b"] = 200
14
+ # map["a"] = 300
15
+ # map["a"] # -> [100, 300]
16
+ # map["b"] # -> [200]
17
+ # map.keys # -> #<Multiset: {a, a, b}>
18
+ class Multimap
19
+ extend Forwardable
20
+
21
+ include Enumerable
22
+
23
+ # call-seq:
24
+ # Multimap[ [key =>|, value]* ] => multimap
25
+ #
26
+ # Creates a new multimap populated with the given objects.
27
+ #
28
+ # Multimap["a", 100, "b", 200] #=> {"a"=>[100], "b"=>[200]}
29
+ # Multimap["a" => 100, "b" => 200] #=> {"a"=>[100], "b"=>[200]}
30
+ def self.[](*args)
31
+ default = []
32
+
33
+ if args.size == 2 && args.last.is_a?(Hash)
34
+ default = args.shift
35
+ elsif !args.first.is_a?(Hash) && args.size % 2 == 1
36
+ default = args.shift
37
+ end
38
+
39
+ if args.size == 1 && args.first.is_a?(Hash)
40
+ args[0] = args.first.inject({}) { |hash, (key, value)|
41
+ unless value.is_a?(default.class)
42
+ value = (default.dup << value)
43
+ end
44
+ hash[key] = value
45
+ hash
46
+ }
47
+ else
48
+ index = 0
49
+ args.map! { |value|
50
+ unless index % 2 == 0 || value.is_a?(default.class)
51
+ value = (default.dup << value)
52
+ end
53
+ index += 1
54
+ value
55
+ }
56
+ end
57
+
58
+ map = new
59
+ map.instance_variable_set(:@hash, Hash[*args])
60
+ map.default = default
61
+ map
62
+ end
63
+
64
+ # call-seq:
65
+ # Multimap.new => multimap
66
+ # Multimap.new(default) => multimap
67
+ #
68
+ # Returns a new, empty multimap.
69
+ #
70
+ # map = Multimap.new(Set.new)
71
+ # h["a"] = 100
72
+ # h["b"] = 200
73
+ # h["a"] #=> [100].to_set
74
+ # h["c"] #=> [].to_set
75
+ def initialize(default = [])
76
+ @hash = Hash.new(default)
77
+ end
78
+
79
+ def initialize_copy(original) #:nodoc:
80
+ @hash = Hash.new(original.default.dup)
81
+ original._internal_hash.each_pair do |key, container|
82
+ @hash[key] = container.dup
83
+ end
84
+ end
85
+
86
+ def_delegators :@hash, :clear, :default, :default=, :empty?,
87
+ :fetch, :has_key?, :key?
88
+
89
+ # Retrieves the <i>value</i> object corresponding to the
90
+ # <i>*keys</i> object.
91
+ def [](key)
92
+ @hash[key]
93
+ end
94
+
95
+ # call-seq:
96
+ # map[key] = value => value
97
+ # map.store(key, value) => value
98
+ #
99
+ # Associates the value given by <i>value</i> with the key
100
+ # given by <i>key</i>. Unlike a regular hash, multiple can be
101
+ # assoicated with the same value.
102
+ #
103
+ # map = Multimap["a" => 100, "b" => 200]
104
+ # map["a"] = 9
105
+ # map["c"] = 4
106
+ # map #=> {"a" => [100, 9], "b" => [200], "c" => [4]}
107
+ def store(key, value)
108
+ update_container(key) do |container|
109
+ container << value
110
+ container
111
+ end
112
+ end
113
+ alias_method :[]=, :store
114
+
115
+ # call-seq:
116
+ # map.delete(key, value) => value
117
+ # map.delete(key) => value
118
+ #
119
+ # Deletes and returns a key-value pair from <i>map</i>. If only
120
+ # <i>key</i> is given, all the values matching that key will be
121
+ # deleted.
122
+ #
123
+ # map = Multimap["a" => 100, "b" => [200, 300]]
124
+ # map.delete("b", 300) #=> 300
125
+ # map.delete("a") #=> [100]
126
+ def delete(key, value = nil)
127
+ if value
128
+ @hash[key].delete(value)
129
+ else
130
+ @hash.delete(key)
131
+ end
132
+ end
133
+
134
+ # call-seq:
135
+ # map.each { |key, value| block } => map
136
+ #
137
+ # Calls <i>block</i> for each key/value pair in <i>map</i>, passing
138
+ # the key and value to the block as a two-element array.
139
+ #
140
+ # map = Multimap["a" => 100, "b" => [200, 300]]
141
+ # map.each { |key, value| puts "#{key} is #{value}" }
142
+ #
143
+ # <em>produces:</em>
144
+ #
145
+ # a is 100
146
+ # b is 200
147
+ # b is 300
148
+ def each
149
+ each_pair do |key, value|
150
+ yield [key, value]
151
+ end
152
+ end
153
+
154
+ # call-seq:
155
+ # map.each_association { |key, container| block } => map
156
+ #
157
+ # Calls <i>block</i> once for each key/container in <i>map</i>, passing
158
+ # the key and container to the block as parameters.
159
+ #
160
+ # map = Multimap["a" => 100, "b" => [200, 300]]
161
+ # map.each_association { |key, container| puts "#{key} is #{container}" }
162
+ #
163
+ # <em>produces:</em>
164
+ #
165
+ # a is [100]
166
+ # b is [200, 300]
167
+ def each_association(&block)
168
+ @hash.each_pair(&block)
169
+ end
170
+
171
+ # call-seq:
172
+ # map.each_container { |container| block } => map
173
+ #
174
+ # Calls <i>block</i> for each container in <i>map</i>, passing the
175
+ # container as a parameter.
176
+ #
177
+ # map = Multimap["a" => 100, "b" => [200, 300]]
178
+ # map.each_container { |container| puts container }
179
+ #
180
+ # <em>produces:</em>
181
+ #
182
+ # [100]
183
+ # [200, 300]
184
+ def each_container
185
+ each_association do |_, container|
186
+ yield container
187
+ end
188
+ end
189
+
190
+ # call-seq:
191
+ # map.each_key { |key| block } => map
192
+ #
193
+ # Calls <i>block</i> for each key in <i>hsh</i>, passing the key
194
+ # as a parameter.
195
+ #
196
+ # map = Multimap["a" => 100, "b" => [200, 300]]
197
+ # map.each_key { |key| puts key }
198
+ #
199
+ # <em>produces:</em>
200
+ #
201
+ # a
202
+ # b
203
+ # b
204
+ def each_key
205
+ each_pair do |key, _|
206
+ yield key
207
+ end
208
+ end
209
+
210
+ # call-seq:
211
+ # map.each_pair { |key_value_array| block } => map
212
+ #
213
+ # Calls <i>block</i> for each key/value pair in <i>map</i>,
214
+ # passing the key and value as parameters.
215
+ #
216
+ # map = Multimap["a" => 100, "b" => [200, 300]]
217
+ # map.each_pair { |key, value| puts "#{key} is #{value}" }
218
+ #
219
+ # <em>produces:</em>
220
+ #
221
+ # a is 100
222
+ # b is 200
223
+ # b is 300
224
+ def each_pair
225
+ each_association do |key, values|
226
+ values.each do |value|
227
+ yield key, value
228
+ end
229
+ end
230
+ end
231
+
232
+ # call-seq:
233
+ # map.each_value { |value| block } => map
234
+ #
235
+ # Calls <i>block</i> for each key in <i>map</i>, passing the
236
+ # value as a parameter.
237
+ #
238
+ # map = Multimap["a" => 100, "b" => [200, 300]]
239
+ # map.each_value { |value| puts value }
240
+ #
241
+ # <em>produces:</em>
242
+ #
243
+ # 100
244
+ # 200
245
+ # 300
246
+ def each_value
247
+ each_pair do |_, value|
248
+ yield value
249
+ end
250
+ end
251
+
252
+ def ==(other) #:nodoc:
253
+ case other
254
+ when Multimap
255
+ @hash == other._internal_hash
256
+ else
257
+ @hash == other
258
+ end
259
+ end
260
+
261
+ def eql?(other) #:nodoc:
262
+ case other
263
+ when Multimap
264
+ @hash.eql?(other._internal_hash)
265
+ else
266
+ @hash.eql?(other)
267
+ end
268
+ end
269
+
270
+ def freeze #:nodoc:
271
+ each_container { |container| container.freeze }
272
+ default.freeze
273
+ super
274
+ end
275
+
276
+ # call-seq:
277
+ # map.has_value?(value) => true or false
278
+ # map.value?(value) => true or false
279
+ #
280
+ # Returns <tt>true</tt> if the given value is present for any key
281
+ # in <i>map</i>.
282
+ #
283
+ # map = Multimap["a" => 100, "b" => [200, 300]]
284
+ # map.has_value?(300) #=> true
285
+ # map.has_value?(999) #=> false
286
+ def has_value?(value)
287
+ values.include?(value)
288
+ end
289
+ alias_method :value?, :has_value?
290
+
291
+ # call-seq:
292
+ # map.index(value) => key
293
+ #
294
+ # Returns the key for a given value. If not found, returns
295
+ # <tt>nil</tt>.
296
+ #
297
+ # map = Multimap["a" => 100, "b" => [200, 300]]
298
+ # map.index(100) #=> "a"
299
+ # map.index(200) #=> "b"
300
+ # map.index(999) #=> nil
301
+ def index(value)
302
+ invert[value]
303
+ end
304
+
305
+ # call-seq:
306
+ # map.delete_if {| key, value | block } -> map
307
+ #
308
+ # Deletes every key-value pair from <i>map</i> for which <i>block</i>
309
+ # evaluates to <code>true</code>.
310
+ #
311
+ # map = Multimap["a" => 100, "b" => [200, 300]]
312
+ # map.delete_if {|key, value| value >= 300 }
313
+ # #=> Multimap["a" => 100, "b" => 200]
314
+ #
315
+ def delete_if
316
+ each_association do |key, container|
317
+ container.delete_if do |value|
318
+ yield [key, value]
319
+ end
320
+ end
321
+ self
322
+ end
323
+
324
+ # call-seq:
325
+ # map.reject {| key, value | block } -> map
326
+ #
327
+ # Same as <code>Multimap#delete_if</code>, but works on (and returns) a
328
+ # copy of the <i>map</i>. Equivalent to
329
+ # <code><i>map</i>.dup.delete_if</code>.
330
+ #
331
+ def reject(&block)
332
+ dup.delete_if(&block)
333
+ end
334
+
335
+ # call-seq:
336
+ # map.reject! {| key, value | block } -> map or nil
337
+ #
338
+ # Equivalent to <code>Multimap#delete_if</code>, but returns
339
+ # <code>nil</code> if no changes were made.
340
+ #
341
+ def reject!(&block)
342
+ old_size = size
343
+ delete_if(&block)
344
+ old_size == size ? nil : self
345
+ end
346
+
347
+ # call-seq:
348
+ # map.replace(other_map) => map
349
+ #
350
+ # Replaces the contents of <i>map</i> with the contents of
351
+ # <i>other_map</i>.
352
+ #
353
+ # map = Multimap["a" => 100, "b" => 200]
354
+ # map.replace({ "c" => 300, "d" => 400 })
355
+ # #=> Multimap["c" => 300, "d" => 400]
356
+ def replace(other)
357
+ case other
358
+ when Array
359
+ @hash.replace(self.class[self.default, *other])
360
+ when Hash
361
+ @hash.replace(self.class[self.default, other])
362
+ when self.class
363
+ @hash.replace(other)
364
+ else
365
+ raise ArgumentError
366
+ end
367
+ end
368
+
369
+ # call-seq:
370
+ # map.invert => multimap
371
+ #
372
+ # Returns a new multimap created by using <i>map</i>'s values as keys,
373
+ # and the keys as values.
374
+ #
375
+ # map = Multimap["n" => 100, "m" => 100, "d" => [200, 300]]
376
+ # map.invert #=> Multimap[100 => ["n", "m"], 200 => "d", 300 => "d"]
377
+ def invert
378
+ h = self.class.new(default.dup)
379
+ each_pair { |key, value| h[value] = key }
380
+ h
381
+ end
382
+
383
+ # call-seq:
384
+ # map.keys => multiset
385
+ #
386
+ # Returns a new +Multiset+ populated with the keys from this hash. See also
387
+ # <tt>Multimap#values</tt> and <tt>Multimap#containers</tt>.
388
+ #
389
+ # map = Multimap["a" => 100, "b" => [200, 300], "c" => 400]
390
+ # map.keys #=> Multiset.new(["a", "b", "b", "c"])
391
+ def keys
392
+ keys = Multiset.new
393
+ each_key { |key| keys << key }
394
+ keys
395
+ end
396
+
397
+ # Returns true if the given key is present in Multimap.
398
+ def include?(key)
399
+ keys.include?(key)
400
+ end
401
+ alias_method :member?, :include?
402
+
403
+ # call-seq:
404
+ # map.length => fixnum
405
+ # map.size => fixnum
406
+ #
407
+ # Returns the number of key-value pairs in the map.
408
+ #
409
+ # map = Multimap["a" => 100, "b" => [200, 300], "c" => 400]
410
+ # map.length #=> 4
411
+ # map.delete("a") #=> 100
412
+ # map.length #=> 3
413
+ def size
414
+ values.size
415
+ end
416
+ alias_method :length, :size
417
+
418
+ # call-seq:
419
+ # map.merge(other_map) => multimap
420
+ #
421
+ # Returns a new multimap containing the contents of <i>other_map</i> and
422
+ # the contents of <i>map</i>.
423
+ #
424
+ # map1 = Multimap["a" => 100, "b" => 200]
425
+ # map2 = Multimap["a" => 254, "c" => 300]
426
+ # map2.merge(map2) #=> Multimap["a" => 100, "b" => [200, 254], "c" => 300]
427
+ # map1 #=> Multimap["a" => 100, "b" => 200]
428
+ def merge(other)
429
+ dup.update(other)
430
+ end
431
+
432
+ # call-seq:
433
+ # map.merge!(other_map) => multimap
434
+ # map.update(other_map) => multimap
435
+ #
436
+ # Adds each pair from <i>other_map</i> to <i>map</i>.
437
+ #
438
+ # map1 = Multimap["a" => 100, "b" => 200]
439
+ # map2 = Multimap["b" => 254, "c" => 300]
440
+ #
441
+ # map1.merge!(map2)
442
+ # #=> Multimap["a" => 100, "b" => [200, 254], "c" => 300]
443
+ def update(other)
444
+ case other
445
+ when self.class
446
+ other.each_pair { |key, value| store(key, value) }
447
+ when Hash
448
+ update(self.class[self.default, other])
449
+ else
450
+ raise ArgumentError
451
+ end
452
+ self
453
+ end
454
+ alias_method :merge!, :update
455
+
456
+ # call-seq:
457
+ # map.select { |key, value| block } => multimap
458
+ #
459
+ # Returns a new Multimap consisting of the pairs for which the
460
+ # block returns true.
461
+ #
462
+ # map = Multimap["a" => 100, "b" => 200, "c" => 300]
463
+ # map.select { |k,v| k > "a" } #=> Multimap["b" => 200, "c" => 300]
464
+ # map.select { |k,v| v < 200 } #=> Multimap["a" => 100]
465
+ def select
466
+ inject(self.class.new) { |map, (key, value)|
467
+ map[key] = value if yield([key, value])
468
+ map
469
+ }
470
+ end
471
+
472
+ # call-seq:
473
+ # map.to_a => array
474
+ #
475
+ # Converts <i>map</i> to a nested array of [<i>key,
476
+ # value</i>] arrays.
477
+ #
478
+ # map = Multimap["a" => 100, "b" => [200, 300], "c" => 400]
479
+ # map.to_a #=> [["a", 100], ["b", 200], ["b", 300], ["c", 400]]
480
+ def to_a
481
+ ary = []
482
+ each_pair do |key, value|
483
+ ary << [key, value]
484
+ end
485
+ ary
486
+ end
487
+
488
+ # call-seq:
489
+ # map.to_hash => hash
490
+ #
491
+ # Converts <i>map</i> to a basic hash.
492
+ #
493
+ # map = Multimap["a" => 100, "b" => [200, 300]]
494
+ # map.to_hash #=> { "a" => [100], "b" => [200, 300] }
495
+ def to_hash
496
+ @hash.dup
497
+ end
498
+
499
+ # call-seq:
500
+ # map.containers => array
501
+ #
502
+ # Returns a new array populated with the containers from <i>map</i>. See
503
+ # also <tt>Multimap#keys</tt> and <tt>Multimap#values</tt>.
504
+ #
505
+ # map = Multimap["a" => 100, "b" => [200, 300]]
506
+ # map.containers #=> [[100], [200, 300]]
507
+ def containers
508
+ containers = []
509
+ each_container { |container| containers << container }
510
+ containers
511
+ end
512
+
513
+ # call-seq:
514
+ # map.values => array
515
+ #
516
+ # Returns a new array populated with the values from <i>map</i>. See
517
+ # also <tt>Multimap#keys</tt> and <tt>Multimap#containers</tt>.
518
+ #
519
+ # map = Multimap["a" => 100, "b" => [200, 300]]
520
+ # map.values #=> [100, 200, 300]
521
+ def values
522
+ values = []
523
+ each_value { |value| values << value }
524
+ values
525
+ end
526
+
527
+ # Return an array containing the values associated with the given keys.
528
+ def values_at(*keys)
529
+ @hash.values_at(*keys)
530
+ end
531
+
532
+ def marshal_dump #:nodoc:
533
+ @hash
534
+ end
535
+
536
+ def marshal_load(hash) #:nodoc:
537
+ @hash = hash
538
+ end
539
+
540
+ def to_yaml(opts = {}) #:nodoc:
541
+ YAML::quick_emit(self, opts) do |out|
542
+ out.map(taguri, to_yaml_style) do |map|
543
+ @hash.each do |k, v|
544
+ map.add(k, v)
545
+ end
546
+ map.add('__default__', @hash.default)
547
+ end
548
+ end
549
+ end
550
+
551
+ def yaml_initialize(tag, val) #:nodoc:
552
+ default = val.delete('__default__')
553
+ @hash = val
554
+ @hash.default = default
555
+ self
556
+ end
557
+
558
+ protected
559
+ def _internal_hash #:nodoc:
560
+ @hash
561
+ end
562
+
563
+ def update_container(key) #:nodoc:
564
+ container = @hash[key]
565
+ container = container.dup if container.equal?(default)
566
+ container = yield(container)
567
+ @hash[key] = container
568
+ end
569
+ end