rack-mount 0.0.1 → 0.0.2

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 (30) hide show
  1. data/README.rdoc +1 -1
  2. data/lib/rack/mount.rb +0 -2
  3. data/lib/rack/mount/analysis/frequency.rb +10 -3
  4. data/lib/rack/mount/analysis/splitting.rb +79 -62
  5. data/lib/rack/mount/generatable_regexp.rb +48 -45
  6. data/lib/rack/mount/generation/route.rb +10 -5
  7. data/lib/rack/mount/generation/route_set.rb +23 -31
  8. data/lib/rack/mount/prefix.rb +14 -15
  9. data/lib/rack/mount/recognition/code_generation.rb +51 -61
  10. data/lib/rack/mount/recognition/route.rb +7 -22
  11. data/lib/rack/mount/recognition/route_set.rb +40 -16
  12. data/lib/rack/mount/regexp_with_named_groups.rb +33 -7
  13. data/lib/rack/mount/route_set.rb +7 -5
  14. data/lib/rack/mount/strexp.rb +11 -40
  15. data/lib/rack/mount/strexp/parser.rb +158 -0
  16. data/lib/rack/mount/strexp/tokenizer.rb +84 -0
  17. data/lib/rack/mount/utils.rb +26 -163
  18. data/lib/rack/mount/vendor/multimap/multimap.rb +1 -0
  19. data/lib/rack/mount/vendor/reginald/reginald.rb +55 -0
  20. data/lib/rack/mount/vendor/reginald/reginald/alternation.rb +50 -0
  21. data/lib/rack/mount/vendor/reginald/reginald/anchor.rb +20 -0
  22. data/lib/rack/mount/vendor/reginald/reginald/character.rb +53 -0
  23. data/lib/rack/mount/vendor/reginald/reginald/character_class.rb +61 -0
  24. data/lib/rack/mount/vendor/reginald/reginald/expression.rb +75 -0
  25. data/lib/rack/mount/vendor/reginald/reginald/group.rb +61 -0
  26. data/lib/rack/mount/vendor/reginald/reginald/parser.rb +306 -0
  27. data/lib/rack/mount/vendor/reginald/reginald/tokenizer.rb +141 -0
  28. metadata +14 -15
  29. data/lib/rack/mount/const.rb +0 -45
  30. data/lib/rack/mount/meta_method.rb +0 -104
@@ -0,0 +1,158 @@
1
+ #
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by Racc 1.4.6
4
+ # from Racc grammer file "".
5
+ #
6
+
7
+ require 'racc/parser.rb'
8
+
9
+ require 'rack/mount/strexp/tokenizer'
10
+
11
+ module Rack
12
+ module Mount
13
+ class StrexpParser < Racc::Parser
14
+
15
+
16
+ if RegexpWithNamedGroups.supports_named_captures?
17
+ REGEXP_NAMED_CAPTURE = '(?<%s>%s)'.freeze
18
+ else
19
+ REGEXP_NAMED_CAPTURE = '(?:<%s>%s)'.freeze
20
+ end
21
+
22
+ attr_accessor :requirements
23
+ ##### State transition tables begin ###
24
+
25
+ racc_action_table = [
26
+ 4, 5, 6, 11, 7, 4, 5, 6, 12, 7,
27
+ 4, 5, 6, 8, 7, 4, 5, 6, nil, 7 ]
28
+
29
+ racc_action_check = [
30
+ 0, 0, 0, 8, 0, 10, 10, 10, 10, 10,
31
+ 2, 2, 2, 1, 2, 6, 6, 6, nil, 6 ]
32
+
33
+ racc_action_pointer = [
34
+ -2, 13, 8, nil, nil, nil, 13, nil, 3, nil,
35
+ 3, nil, nil ]
36
+
37
+ racc_action_default = [
38
+ -8, -8, -1, -3, -4, -5, -8, -7, -8, -2,
39
+ -8, 13, -6 ]
40
+
41
+ racc_goto_table = [
42
+ 9, 2, 1, nil, nil, nil, nil, 10, 9 ]
43
+
44
+ racc_goto_check = [
45
+ 3, 2, 1, nil, nil, nil, nil, 2, 3 ]
46
+
47
+ racc_goto_pointer = [
48
+ nil, 2, 1, -2 ]
49
+
50
+ racc_goto_default = [
51
+ nil, nil, nil, 3 ]
52
+
53
+ racc_reduce_table = [
54
+ 0, 0, :racc_error,
55
+ 1, 8, :_reduce_1,
56
+ 2, 9, :_reduce_2,
57
+ 1, 9, :_reduce_none,
58
+ 1, 10, :_reduce_4,
59
+ 1, 10, :_reduce_5,
60
+ 3, 10, :_reduce_6,
61
+ 1, 10, :_reduce_7 ]
62
+
63
+ racc_reduce_n = 8
64
+
65
+ racc_shift_n = 13
66
+
67
+ racc_token_table = {
68
+ false => 0,
69
+ :error => 1,
70
+ :PARAM => 2,
71
+ :GLOB => 3,
72
+ :LPAREN => 4,
73
+ :RPAREN => 5,
74
+ :CHAR => 6 }
75
+
76
+ racc_nt_base = 7
77
+
78
+ racc_use_result_var = true
79
+
80
+ Racc_arg = [
81
+ racc_action_table,
82
+ racc_action_check,
83
+ racc_action_default,
84
+ racc_action_pointer,
85
+ racc_goto_table,
86
+ racc_goto_check,
87
+ racc_goto_default,
88
+ racc_goto_pointer,
89
+ racc_nt_base,
90
+ racc_reduce_table,
91
+ racc_token_table,
92
+ racc_shift_n,
93
+ racc_reduce_n,
94
+ racc_use_result_var ]
95
+
96
+ Racc_token_to_s_table = [
97
+ "$end",
98
+ "error",
99
+ "PARAM",
100
+ "GLOB",
101
+ "LPAREN",
102
+ "RPAREN",
103
+ "CHAR",
104
+ "$start",
105
+ "target",
106
+ "expr",
107
+ "token" ]
108
+
109
+ Racc_debug_parser = false
110
+
111
+ ##### State transition tables end #####
112
+
113
+ # reduce 0 omitted
114
+
115
+ def _reduce_1(val, _values, result)
116
+ result = "\\A#{val.join}\\Z"
117
+ result
118
+ end
119
+
120
+ def _reduce_2(val, _values, result)
121
+ result = val.join
122
+ result
123
+ end
124
+
125
+ # reduce 3 omitted
126
+
127
+ def _reduce_4(val, _values, result)
128
+ name = val[0].to_sym
129
+ requirement = requirements[name]
130
+ result = REGEXP_NAMED_CAPTURE % [name, requirement]
131
+
132
+ result
133
+ end
134
+
135
+ def _reduce_5(val, _values, result)
136
+ name = val[0].to_sym
137
+ result = REGEXP_NAMED_CAPTURE % [name, '.+']
138
+
139
+ result
140
+ end
141
+
142
+ def _reduce_6(val, _values, result)
143
+ result = "(?:#{val[1]})?"
144
+ result
145
+ end
146
+
147
+ def _reduce_7(val, _values, result)
148
+ result = Regexp.escape(val[0])
149
+ result
150
+ end
151
+
152
+ def _reduce_none(val, _values, result)
153
+ val[0]
154
+ end
155
+
156
+ end # class StrexpParser
157
+ end # module Mount
158
+ end # module Rack
@@ -0,0 +1,84 @@
1
+ #--
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by rex 1.0.4
4
+ # from lexical definition file "lib/rack/mount/strexp/tokenizer.rex".
5
+ #++
6
+
7
+ require 'racc/parser'
8
+ module Rack::Mount
9
+ class StrexpParser < Racc::Parser
10
+ require 'strscan'
11
+
12
+ class ScanError < StandardError ; end
13
+
14
+ attr_reader :lineno
15
+ attr_reader :filename
16
+ attr_accessor :state
17
+
18
+ def scan_setup(str)
19
+ @ss = StringScanner.new(str)
20
+ @lineno = 1
21
+ @state = nil
22
+ end
23
+
24
+ def action(&block)
25
+ yield
26
+ end
27
+
28
+ def scan_str(str)
29
+ scan_setup(str)
30
+ do_parse
31
+ end
32
+
33
+ def load_file( filename )
34
+ @filename = filename
35
+ open(filename, "r") do |f|
36
+ scan_setup(f.read)
37
+ end
38
+ end
39
+
40
+ def scan_file( filename )
41
+ load_file(filename)
42
+ do_parse
43
+ end
44
+
45
+
46
+ def next_token
47
+ return if @ss.eos?
48
+
49
+ text = @ss.peek(1)
50
+ @lineno += 1 if text == "\n"
51
+ token = case @state
52
+ when nil
53
+ case
54
+ when (text = @ss.scan(/\\(\(|\)|:|\*)/))
55
+ action { [:CHAR, @ss[1]] }
56
+
57
+ when (text = @ss.scan(/\:([a-zA-Z_]\w*)/))
58
+ action { [:PARAM, @ss[1]] }
59
+
60
+ when (text = @ss.scan(/\*([a-zA-Z_]\w*)/))
61
+ action { [:GLOB, @ss[1]] }
62
+
63
+ when (text = @ss.scan(/\(/))
64
+ action { [:LPAREN, text] }
65
+
66
+ when (text = @ss.scan(/\)/))
67
+ action { [:RPAREN, text] }
68
+
69
+ when (text = @ss.scan(/./))
70
+ action { [:CHAR, text] }
71
+
72
+ else
73
+ text = @ss.string[@ss.pos .. -1]
74
+ raise ScanError, "can not match: '" + text + "'"
75
+ end # if
76
+
77
+ else
78
+ raise ScanError, "undefined state: '" + state.to_s + "'"
79
+ end # case state
80
+ token
81
+ end # def next_token
82
+
83
+ end # class
84
+ end # module
@@ -1,5 +1,10 @@
1
- require 'rack/mount/regexp_with_named_groups'
2
- require 'strscan'
1
+ begin
2
+ require 'reginald'
3
+ rescue LoadError
4
+ $: << File.expand_path(File.join(File.dirname(__FILE__), 'vendor/reginald'))
5
+ require 'reginald'
6
+ end
7
+
3
8
  require 'uri'
4
9
 
5
10
  module Rack::Mount
@@ -19,9 +24,9 @@ module Rack::Mount
19
24
  # normalize_path("") # => "/"
20
25
  def normalize_path(path)
21
26
  path = "/#{path}"
22
- path.squeeze!(Const::SLASH)
23
- path.sub!(%r{/+\Z}, Const::EMPTY_STRING)
24
- path = Const::SLASH if path == Const::EMPTY_STRING
27
+ path.squeeze!('/')
28
+ path.sub!(%r{/+\Z}, '')
29
+ path = '/' if path == ''
25
30
  path
26
31
  end
27
32
  module_function :normalize_path
@@ -99,173 +104,31 @@ module Rack::Mount
99
104
  end
100
105
  module_function :normalize_extended_expression
101
106
 
102
- # Determines whether the regexp must match the entire string.
103
- #
104
- # regexp_anchored?(/^foo$/) # => true
105
- # regexp_anchored?(/foo/) # => false
106
- # regexp_anchored?(/^foo/) # => false
107
- # regexp_anchored?(/foo$/) # => false
108
- def regexp_anchored?(regexp)
109
- regexp.source =~ /\A(\\A|\^).*(\\Z|\$)\Z/ ? true : false
110
- end
111
- module_function :regexp_anchored?
112
-
113
- # Returns static string source of Regexp if it only includes static
114
- # characters and no metacharacters. Otherwise the original Regexp is
115
- # returned.
116
- #
117
- # extract_static_regexp(/^foo$/) # => "foo"
118
- # extract_static_regexp(/^foo\.bar$/) # => "foo.bar"
119
- # extract_static_regexp(/^foo|bar$/) # => /^foo|bar$/
120
- def extract_static_regexp(regexp, options = nil)
121
- if regexp.is_a?(String)
122
- regexp = Regexp.compile("\\A#{regexp}\\Z", options)
123
- end
124
-
125
- # Just return if regexp is case-insensitive
126
- return regexp if regexp.casefold?
127
-
128
- source = regexp.source
129
- if regexp_anchored?(regexp)
130
- source.sub!(/^(\\A|\^)(.*)(\\Z|\$)$/, '\2')
131
- unescaped_source = source.gsub(/\\/, Const::EMPTY_STRING)
132
- if source == Regexp.escape(unescaped_source) &&
133
- Regexp.compile("\\A(#{source})\\Z") =~ unescaped_source
134
- return unescaped_source
135
- end
136
- end
137
- regexp
138
- end
139
- module_function :extract_static_regexp
140
-
141
- if Const::SUPPORTS_NAMED_CAPTURES
142
- NAMED_CAPTURE_REGEXP = /\?<([^>]+)>/
143
- else
144
- NAMED_CAPTURE_REGEXP = /\?:<([^>]+)>/
145
- end
146
-
147
- # Strips shim named capture syntax and returns a clean Regexp and
148
- # an ordered array of the named captures.
149
- #
150
- # extract_named_captures(/[a-z]+/) # => /[a-z]+/, []
151
- # extract_named_captures(/(?:<foo>[a-z]+)/) # => /([a-z]+)/, ['foo']
152
- # extract_named_captures(/([a-z]+)(?:<foo>[a-z]+)/)
153
- # # => /([a-z]+)([a-z]+)/, [nil, 'foo']
154
- def extract_named_captures(regexp)
155
- options = regexp.is_a?(Regexp) ? regexp.options : nil
156
- source = Regexp.compile(regexp).source
157
- names, scanner = [], StringScanner.new(source)
158
-
159
- while scanner.skip_until(/\(/)
160
- if scanner.scan(NAMED_CAPTURE_REGEXP)
161
- names << scanner[1]
162
- else
163
- names << nil
164
- end
165
- end
166
-
167
- names = [] unless names.any?
168
- source.gsub!(NAMED_CAPTURE_REGEXP, Const::EMPTY_STRING)
169
- return Regexp.compile(source, options), names
170
- end
171
- module_function :extract_named_captures
172
-
173
- class Capture < Array #:nodoc:
174
- attr_reader :name, :optional
175
- alias_method :optional?, :optional
176
-
177
- def initialize(*args)
178
- options = args.last.is_a?(Hash) ? args.pop : {}
179
-
180
- @name = options.delete(:name)
181
- @name = @name.to_s if @name
182
-
183
- @optional = options.delete(:optional) || false
184
-
185
- super(args)
186
- end
187
-
188
- def ==(obj)
189
- obj.is_a?(Capture) && @name == obj.name && @optional == obj.optional && super
190
- end
191
-
192
- def optionalize!
193
- @optional = true
194
- self
195
- end
196
-
197
- def named?
198
- name && name != Const::EMPTY_STRING
199
- end
200
-
201
- def to_s
202
- source = "(#{join})"
203
- source << '?' if optional?
204
- source
205
- end
206
-
207
- def first_part
208
- first.is_a?(Capture) ? first.first_part : first
209
- end
210
-
211
- def last_part
212
- last.is_a?(Capture) ? last.last_part : last
213
- end
214
- end
215
-
216
- def extract_regexp_parts(regexp) #:nodoc:
107
+ def parse_regexp(regexp)
217
108
  unless regexp.is_a?(RegexpWithNamedGroups)
218
109
  regexp = RegexpWithNamedGroups.new(regexp)
219
110
  end
220
111
 
221
- if regexp.source =~ /\?<([^>]+)>/
222
- regexp, names = extract_named_captures(regexp)
223
- else
224
- names = regexp.names
225
- end
226
- source = regexp.source
227
-
228
- source =~ /^(\\A|\^)/ ? source.gsub!(/^(\\A|\^)/, Const::EMPTY_STRING) :
229
- raise(ArgumentError, "#{source} needs to match the start of the string")
230
-
231
- scanner = StringScanner.new(source)
232
- stack = [[]]
112
+ expression = Reginald.parse(regexp)
233
113
 
234
- capture_index = 0
235
- until scanner.eos?
236
- char = scanner.getch
237
- cur = stack.last
238
-
239
- escaped = cur.last.is_a?(String) && cur.last[-1, 1] == '\\'
240
-
241
- if char == '\\' && scanner.peek(1) == 'Z'
242
- scanner.pos += 1
243
- cur.push(Const::NULL)
244
- elsif escaped
245
- cur.push('') unless cur.last.is_a?(String)
246
- cur.last << char
247
- elsif char == '('
248
- name = names[capture_index]
249
- capture = Capture.new(:name => name)
250
- capture_index += 1
251
- cur.push(capture)
252
- stack.push(capture)
253
- elsif char == ')'
254
- capture = stack.pop
255
- if scanner.peek(1) == '?'
256
- scanner.pos += 1
257
- capture.optionalize!
114
+ unless RegexpWithNamedGroups.supports_named_captures?
115
+ tag_captures = Proc.new do |group|
116
+ group.each do |child|
117
+ if child.is_a?(Reginald::Group)
118
+ child.name = regexp.names[child.index] if child.index
119
+ tag_captures.call(child)
120
+ elsif child.is_a?(Reginald::Expression)
121
+ tag_captures.call(child)
122
+ end
258
123
  end
259
- elsif char == '$'
260
- cur.push(Const::NULL)
261
- else
262
- cur.push('') unless cur.last.is_a?(String)
263
- cur.last << char
264
124
  end
125
+ tag_captures.call(expression)
265
126
  end
266
127
 
267
- stack.pop
128
+ expression
129
+ rescue Racc::ParseError
130
+ []
268
131
  end
269
- module_function :extract_regexp_parts
132
+ module_function :parse_regexp
270
133
  end
271
134
  end