lgierth-rack-mount 0.6.13

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.
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,185 @@
1
+ require 'set'
2
+
3
+ # Multiset implements a collection of unordered values and
4
+ # allows duplicates.
5
+ #
6
+ # == Example
7
+ #
8
+ # require 'multiset'
9
+ # s1 = Multiset.new [1, 2] # -> #<Multiset: {1, 2}>
10
+ # s1.add(2) # -> #<Multiset: {1, 2, 2}>
11
+ # s1.merge([2, 6]) # -> #<Multiset: {1, 2, 2, 2, 3}>
12
+ # s1.multiplicity(2) # -> 3
13
+ # s1.multiplicity(3) # -> 1
14
+ class Multiset < Set
15
+ def initialize(*args, &block) #:nodoc:
16
+ @hash = Hash.new(0)
17
+ super
18
+ end
19
+
20
+ # Returns the number of times an element belongs to the multiset.
21
+ def multiplicity(e)
22
+ @hash[e]
23
+ end
24
+
25
+ # Returns the total number of elements in a multiset, including
26
+ # repeated memberships
27
+ def cardinality
28
+ @hash.inject(0) { |s, (e, m)| s += m }
29
+ end
30
+ alias_method :size, :cardinality
31
+ alias_method :length, :cardinality
32
+
33
+ # Converts the set to an array. The order of elements is uncertain.
34
+ def to_a
35
+ inject([]) { |ary, (key, _)| ary << key }
36
+ end
37
+
38
+ # Returns true if the set is a superset of the given set.
39
+ def superset?(set)
40
+ set.is_a?(self.class) or raise ArgumentError, "value must be a set"
41
+ return false if cardinality < set.cardinality
42
+ set.all? { |o| set.multiplicity(o) <= multiplicity(o) }
43
+ end
44
+
45
+ # Returns true if the set is a proper superset of the given set.
46
+ def proper_superset?(set)
47
+ set.is_a?(self.class) or raise ArgumentError, "value must be a set"
48
+ return false if cardinality <= set.cardinality
49
+ set.all? { |o| set.multiplicity(o) <= multiplicity(o) }
50
+ end
51
+
52
+ # Returns true if the set is a subset of the given set.
53
+ def subset?(set)
54
+ set.is_a?(self.class) or raise ArgumentError, "value must be a set"
55
+ return false if set.cardinality < cardinality
56
+ all? { |o| multiplicity(o) <= set.multiplicity(o) }
57
+ end
58
+
59
+ # Returns true if the set is a proper subset of the given set.
60
+ def proper_subset?(set)
61
+ set.is_a?(self.class) or raise ArgumentError, "value must be a set"
62
+ return false if set.cardinality <= cardinality
63
+ all? { |o| multiplicity(o) <= set.multiplicity(o) }
64
+ end
65
+
66
+ # Calls the given block once for each element in the set, passing
67
+ # the element as parameter. Returns an enumerator if no block is
68
+ # given.
69
+ def each
70
+ @hash.each_pair do |key, multiplicity|
71
+ multiplicity.times do
72
+ yield(key)
73
+ end
74
+ end
75
+ self
76
+ end
77
+
78
+ # Adds the given object to the set and returns self. Use +merge+ to
79
+ # add many elements at once.
80
+ def add(o)
81
+ @hash[o] ||= 0
82
+ @hash[o] += 1
83
+ self
84
+ end
85
+ alias << add
86
+
87
+ undef :add?
88
+
89
+ # Deletes all the identical object from the set and returns self.
90
+ # If +n+ is given, it will remove that amount of identical objects
91
+ # from the set. Use +subtract+ to delete many different items at
92
+ # once.
93
+ def delete(o, n = nil)
94
+ if n
95
+ @hash[o] ||= 0
96
+ @hash[o] -= n if @hash[o] > 0
97
+ @hash.delete(o) if @hash[o] == 0
98
+ else
99
+ @hash.delete(o)
100
+ end
101
+ self
102
+ end
103
+
104
+ undef :delete?
105
+
106
+ # Deletes every element of the set for which block evaluates to
107
+ # true, and returns self.
108
+ def delete_if
109
+ each { |o| delete(o) if yield(o) }
110
+ self
111
+ end
112
+
113
+ # Merges the elements of the given enumerable object to the set and
114
+ # returns self.
115
+ def merge(enum)
116
+ enum.each { |o| add(o) }
117
+ self
118
+ end
119
+
120
+ # Deletes every element that appears in the given enumerable object
121
+ # and returns self.
122
+ def subtract(enum)
123
+ enum.each { |o| delete(o, 1) }
124
+ self
125
+ end
126
+
127
+ # Returns a new set containing elements common to the set and the
128
+ # given enumerable object.
129
+ def &(enum)
130
+ s = dup
131
+ n = self.class.new
132
+ enum.each { |o|
133
+ if s.include?(o)
134
+ s.delete(o, 1)
135
+ n.add(o)
136
+ end
137
+ }
138
+ n
139
+ end
140
+ alias intersection &
141
+
142
+ # Returns a new set containing elements exclusive between the set
143
+ # and the given enumerable object. (set ^ enum) is equivalent to
144
+ # ((set | enum) - (set & enum)).
145
+ def ^(enum)
146
+ n = self.class.new(enum)
147
+ each { |o| n.include?(o) ? n.delete(o, 1) : n.add(o) }
148
+ n
149
+ end
150
+
151
+ # Returns true if two sets are equal. Two multisets are equal if
152
+ # they have the same cardinalities and each element has the same
153
+ # multiplicity in both sets. The equality of each element inside
154
+ # the multiset is defined according to Object#eql?.
155
+ def eql?(set)
156
+ return true if equal?(set)
157
+ set = self.class.new(set) unless set.is_a?(self.class)
158
+ return false unless cardinality == set.cardinality
159
+ superset?(set) && subset?(set)
160
+ end
161
+ alias_method :==, :eql?
162
+
163
+ def marshal_dump #:nodoc:
164
+ @hash
165
+ end
166
+
167
+ def marshal_load(hash) #:nodoc:
168
+ @hash = hash
169
+ end
170
+
171
+ def to_yaml(opts = {}) #:nodoc:
172
+ YAML::quick_emit(self, opts) do |out|
173
+ out.map(taguri, to_yaml_style) do |map|
174
+ @hash.each do |k, v|
175
+ map.add(k, v)
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+ def yaml_initialize(tag, val) #:nodoc:
182
+ @hash = val
183
+ self
184
+ end
185
+ end
@@ -0,0 +1,158 @@
1
+ require 'multimap'
2
+
3
+ # NestedMultimap allows values to be assoicated with a nested
4
+ # set of keys.
5
+ class NestedMultimap < Multimap
6
+ # call-seq:
7
+ # multimap[*keys] = value => value
8
+ # multimap.store(*keys, value) => value
9
+ #
10
+ # Associates the value given by <i>value</i> with multiple key
11
+ # given by <i>keys</i>.
12
+ #
13
+ # map = NestedMultimap.new
14
+ # map["a"] = 100
15
+ # map["a", "b"] = 101
16
+ # map["a"] = 102
17
+ # map #=> {"a"=>{"b"=>[100, 101, 102], default => [100, 102]}}
18
+ def store(*args)
19
+ keys = args
20
+ value = args.pop
21
+
22
+ raise ArgumentError, 'wrong number of arguments (1 for 2)' unless value
23
+
24
+ if keys.length > 1
25
+ update_container(keys.shift) do |container|
26
+ container = self.class.new(container) unless container.is_a?(self.class)
27
+ container[*keys] = value
28
+ container
29
+ end
30
+ elsif keys.length == 1
31
+ super(keys.first, value)
32
+ else
33
+ self << value
34
+ end
35
+ end
36
+ alias_method :[]=, :store
37
+
38
+ # call-seq:
39
+ # multimap << obj => multimap
40
+ #
41
+ # Pushes the given object on to the end of all the containers.
42
+ #
43
+ # map = NestedMultimap["a" => [100], "b" => [200, 300]]
44
+ # map << 300
45
+ # map["a"] #=> [100, 300]
46
+ # map["c"] #=> [300]
47
+ def <<(value)
48
+ @hash.each_value { |container| container << value }
49
+ self.default << value
50
+ self
51
+ end
52
+
53
+ # call-seq:
54
+ # multimap[*keys] => value
55
+ # multimap[key1, key2, key3] => value
56
+ #
57
+ # Retrieves the <i>value</i> object corresponding to the
58
+ # <i>*keys</i> object.
59
+ def [](*keys)
60
+ i, l, r, k = 0, keys.length, self, self.class
61
+ while r.is_a?(k)
62
+ r = i < l ? r._internal_hash[keys[i]] : r.default
63
+ i += 1
64
+ end
65
+ r
66
+ end
67
+
68
+ # call-seq:
69
+ # multimap.each_association { |key, container| block } => multimap
70
+ #
71
+ # Calls <i>block</i> once for each key/container in <i>map</i>, passing
72
+ # the key and container to the block as parameters.
73
+ #
74
+ # map = NestedMultimap.new
75
+ # map["a"] = 100
76
+ # map["a", "b"] = 101
77
+ # map["a"] = 102
78
+ # map["c"] = 200
79
+ # map.each_association { |key, container| puts "#{key} is #{container}" }
80
+ #
81
+ # <em>produces:</em>
82
+ #
83
+ # ["a", "b"] is [100, 101, 102]
84
+ # "c" is [200]
85
+ def each_association
86
+ super() do |key, container|
87
+ if container.respond_to?(:each_association)
88
+ container.each_association do |nested_key, value|
89
+ yield [key, nested_key].flatten, value
90
+ end
91
+ else
92
+ yield key, container
93
+ end
94
+ end
95
+ end
96
+
97
+ # call-seq:
98
+ # multimap.each_container_with_default { |container| block } => map
99
+ #
100
+ # Calls <i>block</i> for every container in <i>map</i> including
101
+ # the default, passing the container as a parameter.
102
+ #
103
+ # map = NestedMultimap.new
104
+ # map["a"] = 100
105
+ # map["a", "b"] = 101
106
+ # map["a"] = 102
107
+ # map.each_container_with_default { |container| puts container }
108
+ #
109
+ # <em>produces:</em>
110
+ #
111
+ # [100, 101, 102]
112
+ # [100, 102]
113
+ # []
114
+ def each_container_with_default(&block)
115
+ @hash.each_value do |container|
116
+ iterate_over_container(container, &block)
117
+ end
118
+ iterate_over_container(default, &block)
119
+ self
120
+ end
121
+
122
+ # call-seq:
123
+ # multimap.containers_with_default => array
124
+ #
125
+ # Returns a new array populated with all the containers from
126
+ # <i>map</i> including the default.
127
+ #
128
+ # map = NestedMultimap.new
129
+ # map["a"] = 100
130
+ # map["a", "b"] = 101
131
+ # map["a"] = 102
132
+ # map.containers_with_default #=> [[100, 101, 102], [100, 102], []]
133
+ def containers_with_default
134
+ containers = []
135
+ each_container_with_default { |container| containers << container }
136
+ containers
137
+ end
138
+
139
+ def inspect #:nodoc:
140
+ super.gsub(/\}$/, ", default => #{default.inspect}}")
141
+ end
142
+
143
+ private
144
+ def iterate_over_container(container)
145
+ if container.respond_to?(:each_container_with_default)
146
+ container.each_container_with_default do |value|
147
+ yield value
148
+ end
149
+ else
150
+ yield container
151
+ end
152
+ end
153
+ end
154
+
155
+ begin
156
+ require 'nested_multimap_ext'
157
+ rescue LoadError
158
+ end
@@ -0,0 +1,75 @@
1
+ module Regin
2
+ autoload :Alternation, 'regin/alternation'
3
+ autoload :Anchor, 'regin/anchor'
4
+ autoload :Atom, 'regin/atom'
5
+ autoload :Character, 'regin/character'
6
+ autoload :CharacterClass, 'regin/character_class'
7
+ autoload :Collection, 'regin/collection'
8
+ autoload :Expression, 'regin/expression'
9
+ autoload :Group, 'regin/group'
10
+ autoload :Options, 'regin/options'
11
+ autoload :Parser, 'regin/parser'
12
+
13
+ # Detect named capture support
14
+ begin
15
+ old_debug, $DEBUG = $DEBUG, nil
16
+ eval('foo = /(?<foo>.*)/').named_captures
17
+
18
+ # Returns true if the interpreter is using the Oniguruma Regexp lib
19
+ # and supports named captures.
20
+ #
21
+ # /(?<foo>bar)/
22
+ def self.regexp_supports_named_captures?
23
+ true
24
+ end
25
+ rescue SyntaxError, NoMethodError
26
+ def self.regexp_supports_named_captures? #:nodoc:
27
+ false
28
+ end
29
+ ensure
30
+ $DEBUG = old_debug
31
+ end
32
+
33
+
34
+ POSIX_BRACKET_TYPES = %w(
35
+ alnum alpha ascii blank cntrl digit graph
36
+ lower print punct space upper word xdigit
37
+ foo
38
+ )
39
+
40
+ # Returns array of supported POSX bracket types
41
+ def self.supported_posix_bracket_types
42
+ @supported_posix_bracket_types ||= []
43
+ end
44
+
45
+ # Detect supported posix bracket types
46
+ begin
47
+ old_debug, $DEBUG = $DEBUG, nil
48
+
49
+ POSIX_BRACKET_TYPES.each do |type|
50
+ begin
51
+ eval("foo = /[[:#{type}:]]/")
52
+ supported_posix_bracket_types << type
53
+ rescue SyntaxError, RegexpError
54
+ end
55
+ end
56
+ ensure
57
+ $DEBUG = old_debug
58
+ end
59
+
60
+
61
+ # Parses Regexp and returns a Expression data structure.
62
+ def self.parse(regexp)
63
+ Parser.parse_regexp(regexp)
64
+ end
65
+
66
+ # Recompiles Regexp by parsing it and turning it back into a Regexp.
67
+ #
68
+ # (In the future Regin will perform some Regexp optimizations
69
+ # such as removing unnecessary captures and options)
70
+ def self.compile(source)
71
+ regexp = Regexp.compile(source)
72
+ expression = parse(regexp)
73
+ Regexp.compile(expression.to_s(true), expression.flags)
74
+ end
75
+ end
@@ -0,0 +1,40 @@
1
+ module Regin
2
+ class Alternation < Collection
3
+ def initialize(*args)
4
+ args, options = extract_options(args)
5
+
6
+ if args.length == 1 && args.first.instance_of?(Array)
7
+ super(args.first)
8
+ else
9
+ super(args)
10
+ end
11
+
12
+ if options.key?(:ignorecase)
13
+ @array.map! { |e| e.dup(:ignorecase => options[:ignorecase]) }
14
+ end
15
+ end
16
+
17
+ # Returns true if expression could be treated as a literal string.
18
+ #
19
+ # Alternation groups are never literal.
20
+ def literal?
21
+ false
22
+ end
23
+
24
+ def flags
25
+ 0
26
+ end
27
+
28
+ def dup(options = {})
29
+ self.class.new(to_a, options)
30
+ end
31
+
32
+ def to_s(parent = false)
33
+ map { |e| e.to_s(parent) }.join('|')
34
+ end
35
+
36
+ def inspect #:nodoc:
37
+ to_s.inspect
38
+ end
39
+ end
40
+ end