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.
- data/LICENSE +20 -0
- data/README.rdoc +36 -0
- data/lib/rack/mount.rb +32 -0
- data/lib/rack/mount/analysis/frequency.rb +60 -0
- data/lib/rack/mount/analysis/histogram.rb +74 -0
- data/lib/rack/mount/analysis/splitting.rb +159 -0
- data/lib/rack/mount/code_generation.rb +117 -0
- data/lib/rack/mount/generatable_regexp.rb +210 -0
- data/lib/rack/mount/multimap.rb +53 -0
- data/lib/rack/mount/prefix.rb +36 -0
- data/lib/rack/mount/regexp_with_named_groups.rb +69 -0
- data/lib/rack/mount/route.rb +130 -0
- data/lib/rack/mount/route_set.rb +420 -0
- data/lib/rack/mount/strexp.rb +68 -0
- data/lib/rack/mount/strexp/parser.rb +160 -0
- data/lib/rack/mount/strexp/parser.y +34 -0
- data/lib/rack/mount/strexp/tokenizer.rb +83 -0
- data/lib/rack/mount/strexp/tokenizer.rex +12 -0
- data/lib/rack/mount/utils.rb +162 -0
- data/lib/rack/mount/vendor/multimap/multimap.rb +569 -0
- data/lib/rack/mount/vendor/multimap/multiset.rb +185 -0
- data/lib/rack/mount/vendor/multimap/nested_multimap.rb +158 -0
- data/lib/rack/mount/vendor/regin/regin.rb +75 -0
- data/lib/rack/mount/vendor/regin/regin/alternation.rb +40 -0
- data/lib/rack/mount/vendor/regin/regin/anchor.rb +4 -0
- data/lib/rack/mount/vendor/regin/regin/atom.rb +54 -0
- data/lib/rack/mount/vendor/regin/regin/character.rb +51 -0
- data/lib/rack/mount/vendor/regin/regin/character_class.rb +50 -0
- data/lib/rack/mount/vendor/regin/regin/collection.rb +77 -0
- data/lib/rack/mount/vendor/regin/regin/expression.rb +126 -0
- data/lib/rack/mount/vendor/regin/regin/group.rb +85 -0
- data/lib/rack/mount/vendor/regin/regin/options.rb +55 -0
- data/lib/rack/mount/vendor/regin/regin/parser.rb +520 -0
- data/lib/rack/mount/vendor/regin/regin/tokenizer.rb +246 -0
- data/lib/rack/mount/vendor/regin/regin/version.rb +3 -0
- data/lib/rack/mount/version.rb +3 -0
- metadata +140 -0
@@ -0,0 +1,160 @@
|
|
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/utils'
|
10
|
+
require 'rack/mount/strexp/tokenizer'
|
11
|
+
|
12
|
+
module Rack
|
13
|
+
module Mount
|
14
|
+
class StrexpParser < Racc::Parser
|
15
|
+
|
16
|
+
|
17
|
+
if Regin.regexp_supports_named_captures?
|
18
|
+
REGEXP_NAMED_CAPTURE = '(?<%s>%s)'.freeze
|
19
|
+
else
|
20
|
+
REGEXP_NAMED_CAPTURE = '(?:<%s>%s)'.freeze
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_accessor :anchor, :requirements
|
24
|
+
##### State transition tables begin ###
|
25
|
+
|
26
|
+
racc_action_table = [
|
27
|
+
1, 2, 3, 9, 4, 1, 2, 3, 12, 4,
|
28
|
+
1, 2, 3, 11, 4, 1, 2, 3, nil, 4 ]
|
29
|
+
|
30
|
+
racc_action_check = [
|
31
|
+
0, 0, 0, 5, 0, 3, 3, 3, 9, 3,
|
32
|
+
8, 8, 8, 8, 8, 6, 6, 6, nil, 6 ]
|
33
|
+
|
34
|
+
racc_action_pointer = [
|
35
|
+
-2, nil, nil, 3, nil, 3, 13, nil, 8, 8,
|
36
|
+
nil, nil, nil ]
|
37
|
+
|
38
|
+
racc_action_default = [
|
39
|
+
-8, -4, -5, -8, -7, -8, -1, -3, -8, -8,
|
40
|
+
-2, -6, 13 ]
|
41
|
+
|
42
|
+
racc_goto_table = [
|
43
|
+
6, 5, 10, 8, 10 ]
|
44
|
+
|
45
|
+
racc_goto_check = [
|
46
|
+
2, 1, 3, 2, 3 ]
|
47
|
+
|
48
|
+
racc_goto_pointer = [
|
49
|
+
nil, 1, 0, -4 ]
|
50
|
+
|
51
|
+
racc_goto_default = [
|
52
|
+
nil, nil, nil, 7 ]
|
53
|
+
|
54
|
+
racc_reduce_table = [
|
55
|
+
0, 0, :racc_error,
|
56
|
+
1, 8, :_reduce_1,
|
57
|
+
2, 9, :_reduce_2,
|
58
|
+
1, 9, :_reduce_none,
|
59
|
+
1, 10, :_reduce_4,
|
60
|
+
1, 10, :_reduce_5,
|
61
|
+
3, 10, :_reduce_6,
|
62
|
+
1, 10, :_reduce_7 ]
|
63
|
+
|
64
|
+
racc_reduce_n = 8
|
65
|
+
|
66
|
+
racc_shift_n = 13
|
67
|
+
|
68
|
+
racc_token_table = {
|
69
|
+
false => 0,
|
70
|
+
:error => 1,
|
71
|
+
:PARAM => 2,
|
72
|
+
:GLOB => 3,
|
73
|
+
:LPAREN => 4,
|
74
|
+
:RPAREN => 5,
|
75
|
+
:CHAR => 6 }
|
76
|
+
|
77
|
+
racc_nt_base = 7
|
78
|
+
|
79
|
+
racc_use_result_var = true
|
80
|
+
|
81
|
+
Racc_arg = [
|
82
|
+
racc_action_table,
|
83
|
+
racc_action_check,
|
84
|
+
racc_action_default,
|
85
|
+
racc_action_pointer,
|
86
|
+
racc_goto_table,
|
87
|
+
racc_goto_check,
|
88
|
+
racc_goto_default,
|
89
|
+
racc_goto_pointer,
|
90
|
+
racc_nt_base,
|
91
|
+
racc_reduce_table,
|
92
|
+
racc_token_table,
|
93
|
+
racc_shift_n,
|
94
|
+
racc_reduce_n,
|
95
|
+
racc_use_result_var ]
|
96
|
+
|
97
|
+
Racc_token_to_s_table = [
|
98
|
+
"$end",
|
99
|
+
"error",
|
100
|
+
"PARAM",
|
101
|
+
"GLOB",
|
102
|
+
"LPAREN",
|
103
|
+
"RPAREN",
|
104
|
+
"CHAR",
|
105
|
+
"$start",
|
106
|
+
"target",
|
107
|
+
"expr",
|
108
|
+
"token" ]
|
109
|
+
|
110
|
+
Racc_debug_parser = false
|
111
|
+
|
112
|
+
##### State transition tables end #####
|
113
|
+
|
114
|
+
# reduce 0 omitted
|
115
|
+
|
116
|
+
def _reduce_1(val, _values, result)
|
117
|
+
result = anchor ? "\\A#{val.join}\\Z" : "\\A#{val.join}"
|
118
|
+
result
|
119
|
+
end
|
120
|
+
|
121
|
+
def _reduce_2(val, _values, result)
|
122
|
+
result = val.join
|
123
|
+
result
|
124
|
+
end
|
125
|
+
|
126
|
+
# reduce 3 omitted
|
127
|
+
|
128
|
+
def _reduce_4(val, _values, result)
|
129
|
+
name = val[0].to_sym
|
130
|
+
requirement = requirements[name]
|
131
|
+
result = REGEXP_NAMED_CAPTURE % [name, requirement]
|
132
|
+
|
133
|
+
result
|
134
|
+
end
|
135
|
+
|
136
|
+
def _reduce_5(val, _values, result)
|
137
|
+
name = val[0].to_sym
|
138
|
+
requirement = requirements[name]
|
139
|
+
result = REGEXP_NAMED_CAPTURE % [name, '.+' || requirement]
|
140
|
+
|
141
|
+
result
|
142
|
+
end
|
143
|
+
|
144
|
+
def _reduce_6(val, _values, result)
|
145
|
+
result = "(?:#{val[1]})?"
|
146
|
+
result
|
147
|
+
end
|
148
|
+
|
149
|
+
def _reduce_7(val, _values, result)
|
150
|
+
result = Regexp.escape(val[0])
|
151
|
+
result
|
152
|
+
end
|
153
|
+
|
154
|
+
def _reduce_none(val, _values, result)
|
155
|
+
val[0]
|
156
|
+
end
|
157
|
+
|
158
|
+
end # class StrexpParser
|
159
|
+
end # module Mount
|
160
|
+
end # module Rack
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Rack::Mount::StrexpParser
|
2
|
+
rule
|
3
|
+
target: expr { result = anchor ? "\\A#{val.join}\\Z" : "\\A#{val.join}" }
|
4
|
+
|
5
|
+
expr: expr token { result = val.join }
|
6
|
+
| token
|
7
|
+
|
8
|
+
token: PARAM {
|
9
|
+
name = val[0].to_sym
|
10
|
+
requirement = requirements[name]
|
11
|
+
result = REGEXP_NAMED_CAPTURE % [name, requirement]
|
12
|
+
}
|
13
|
+
| GLOB {
|
14
|
+
name = val[0].to_sym
|
15
|
+
requirement = requirements[name]
|
16
|
+
result = REGEXP_NAMED_CAPTURE % [name, '.+' || requirement]
|
17
|
+
}
|
18
|
+
| LPAREN expr RPAREN { result = "(?:#{val[1]})?" }
|
19
|
+
| CHAR { result = Regexp.escape(val[0]) }
|
20
|
+
end
|
21
|
+
|
22
|
+
---- header ----
|
23
|
+
require 'rack/mount/utils'
|
24
|
+
require 'rack/mount/strexp/tokenizer'
|
25
|
+
|
26
|
+
---- inner
|
27
|
+
|
28
|
+
if Regin.regexp_supports_named_captures?
|
29
|
+
REGEXP_NAMED_CAPTURE = '(?<%s>%s)'.freeze
|
30
|
+
else
|
31
|
+
REGEXP_NAMED_CAPTURE = '(?:<%s>%s)'.freeze
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_accessor :anchor, :requirements
|
@@ -0,0 +1,83 @@
|
|
1
|
+
#--
|
2
|
+
# DO NOT MODIFY!!!!
|
3
|
+
# This file is automatically generated by rex 1.0.5.beta1
|
4
|
+
# from lexical definition file "lib/rack/mount/strexp/tokenizer.rex".
|
5
|
+
#++
|
6
|
+
|
7
|
+
require 'racc/parser'
|
8
|
+
class Rack::Mount::StrexpParser < Racc::Parser
|
9
|
+
require 'strscan'
|
10
|
+
|
11
|
+
class ScanError < StandardError ; end
|
12
|
+
|
13
|
+
attr_reader :lineno
|
14
|
+
attr_reader :filename
|
15
|
+
attr_accessor :state
|
16
|
+
|
17
|
+
def scan_setup(str)
|
18
|
+
@ss = StringScanner.new(str)
|
19
|
+
@lineno = 1
|
20
|
+
@state = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def action
|
24
|
+
yield
|
25
|
+
end
|
26
|
+
|
27
|
+
def scan_str(str)
|
28
|
+
scan_setup(str)
|
29
|
+
do_parse
|
30
|
+
end
|
31
|
+
alias :scan :scan_str
|
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
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Rack::Mount::StrexpParser
|
2
|
+
macro
|
3
|
+
RESERVED \(|\)|:|\*
|
4
|
+
ALPHA_U [a-zA-Z_]
|
5
|
+
rule
|
6
|
+
\\({RESERVED}) { [:CHAR, @ss[1]] }
|
7
|
+
\:({ALPHA_U}\w*) { [:PARAM, @ss[1]] }
|
8
|
+
\*({ALPHA_U}\w*) { [:GLOB, @ss[1]] }
|
9
|
+
\( { [:LPAREN, text] }
|
10
|
+
\) { [:RPAREN, text] }
|
11
|
+
. { [:CHAR, text] }
|
12
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
begin
|
2
|
+
require 'regin'
|
3
|
+
rescue LoadError
|
4
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__), 'vendor/regin'))
|
5
|
+
require 'regin'
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'uri'
|
9
|
+
|
10
|
+
module Rack::Mount
|
11
|
+
# Private utility methods used throughout Rack::Mount.
|
12
|
+
#--
|
13
|
+
# This module is a trash can. Try to move these functions into
|
14
|
+
# more appropriate contexts.
|
15
|
+
#++
|
16
|
+
module Utils
|
17
|
+
def silence_debug
|
18
|
+
old_debug, $DEBUG = $DEBUG, nil
|
19
|
+
yield
|
20
|
+
ensure
|
21
|
+
$DEBUG = old_debug
|
22
|
+
end
|
23
|
+
module_function :silence_debug
|
24
|
+
|
25
|
+
def debug(msg)
|
26
|
+
warn "Rack::Mount #{msg}" if $DEBUG
|
27
|
+
end
|
28
|
+
module_function :debug
|
29
|
+
|
30
|
+
# Normalizes URI path.
|
31
|
+
#
|
32
|
+
# Strips off trailing slash and ensures there is a leading slash.
|
33
|
+
#
|
34
|
+
# normalize_path("/foo") # => "/foo"
|
35
|
+
# normalize_path("/foo/") # => "/foo"
|
36
|
+
# normalize_path("foo") # => "/foo"
|
37
|
+
# normalize_path("") # => "/"
|
38
|
+
def normalize_path(path)
|
39
|
+
path = "/#{path}"
|
40
|
+
path.squeeze!('/')
|
41
|
+
path.sub!(%r{/+\Z}, '')
|
42
|
+
path = '/' if path == ''
|
43
|
+
path
|
44
|
+
end
|
45
|
+
module_function :normalize_path
|
46
|
+
|
47
|
+
# Removes trailing nils from array.
|
48
|
+
#
|
49
|
+
# pop_trailing_blanks!([1, 2, 3]) # => [1, 2, 3]
|
50
|
+
# pop_trailing_blanks!([1, 2, 3, nil, ""]) # => [1, 2, 3]
|
51
|
+
# pop_trailing_blanks!([nil]) # => []
|
52
|
+
# pop_trailing_blanks!([""]) # => []
|
53
|
+
def pop_trailing_blanks!(ary)
|
54
|
+
while ary.length > 0 && (ary.last.nil? || ary.last == '')
|
55
|
+
ary.pop
|
56
|
+
end
|
57
|
+
ary
|
58
|
+
end
|
59
|
+
module_function :pop_trailing_blanks!
|
60
|
+
|
61
|
+
RESERVED_PCHAR = ':@&=+$,;%'
|
62
|
+
SAFE_PCHAR = "#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}"
|
63
|
+
if RUBY_VERSION >= '1.9'
|
64
|
+
UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false).freeze
|
65
|
+
else
|
66
|
+
UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false, 'N').freeze
|
67
|
+
end
|
68
|
+
|
69
|
+
Parser = URI.const_defined?(:Parser) ? URI::Parser.new : URI
|
70
|
+
|
71
|
+
def escape_uri(uri)
|
72
|
+
Parser.escape(uri.to_s, UNSAFE_PCHAR)
|
73
|
+
end
|
74
|
+
module_function :escape_uri
|
75
|
+
|
76
|
+
if ''.respond_to?(:force_encoding)
|
77
|
+
def unescape_uri(uri)
|
78
|
+
Parser.unescape(uri).force_encoding('utf-8')
|
79
|
+
end
|
80
|
+
else
|
81
|
+
def unescape_uri(uri)
|
82
|
+
URI.unescape(uri)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
module_function :unescape_uri
|
86
|
+
|
87
|
+
# Taken from Rack 1.1.x to build nested query strings
|
88
|
+
def build_nested_query(value, prefix = nil) #:nodoc:
|
89
|
+
case value
|
90
|
+
when Array
|
91
|
+
value.map { |v|
|
92
|
+
build_nested_query(v, "#{prefix}[]")
|
93
|
+
}.join("&")
|
94
|
+
when Hash
|
95
|
+
value.map { |k, v|
|
96
|
+
build_nested_query(v, prefix ? "#{prefix}[#{Rack::Utils.escape(k)}]" : Rack::Utils.escape(k))
|
97
|
+
}.join("&")
|
98
|
+
when String
|
99
|
+
raise ArgumentError, "value must be a Hash" if prefix.nil?
|
100
|
+
"#{prefix}=#{Rack::Utils.escape(value)}"
|
101
|
+
else
|
102
|
+
prefix
|
103
|
+
end
|
104
|
+
end
|
105
|
+
module_function :build_nested_query
|
106
|
+
|
107
|
+
# Determines whether the regexp must match the entire string.
|
108
|
+
#
|
109
|
+
# regexp_anchored?(/^foo$/) # => true
|
110
|
+
# regexp_anchored?(/foo/) # => false
|
111
|
+
# regexp_anchored?(/^foo/) # => false
|
112
|
+
# regexp_anchored?(/foo$/) # => false
|
113
|
+
def regexp_anchored?(regexp)
|
114
|
+
regexp.source =~ /\A(\\A|\^).*(\\Z|\$)\Z/m ? true : false
|
115
|
+
end
|
116
|
+
module_function :regexp_anchored?
|
117
|
+
|
118
|
+
def normalize_extended_expression(regexp)
|
119
|
+
return regexp unless regexp.options & Regexp::EXTENDED != 0
|
120
|
+
source = regexp.source
|
121
|
+
source.gsub!(/#.+$/, '')
|
122
|
+
source.gsub!(/\s+/, '')
|
123
|
+
source.gsub!(/\\\//, '/')
|
124
|
+
Regexp.compile(source)
|
125
|
+
end
|
126
|
+
module_function :normalize_extended_expression
|
127
|
+
|
128
|
+
def parse_regexp(regexp)
|
129
|
+
cache = @@_parse_regexp_cache ||= {}
|
130
|
+
|
131
|
+
if expression = cache[regexp]
|
132
|
+
return expression
|
133
|
+
end
|
134
|
+
|
135
|
+
unless regexp.is_a?(RegexpWithNamedGroups)
|
136
|
+
regexp = RegexpWithNamedGroups.new(regexp)
|
137
|
+
end
|
138
|
+
|
139
|
+
expression = Regin.parse(regexp)
|
140
|
+
|
141
|
+
unless Regin.regexp_supports_named_captures?
|
142
|
+
tag_captures = Proc.new do |group|
|
143
|
+
case group
|
144
|
+
when Regin::Group
|
145
|
+
# TODO: dup instead of mutating
|
146
|
+
group.instance_variable_set('@name', regexp.names[group.index]) if group.index
|
147
|
+
tag_captures.call(group.expression)
|
148
|
+
when Regin::Expression
|
149
|
+
group.each { |child| tag_captures.call(child) }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
tag_captures.call(expression)
|
153
|
+
end
|
154
|
+
|
155
|
+
cache[regexp] = expression.freeze
|
156
|
+
expression
|
157
|
+
rescue Racc::ParseError, Regin::Parser::ScanError
|
158
|
+
[]
|
159
|
+
end
|
160
|
+
module_function :parse_regexp
|
161
|
+
end
|
162
|
+
end
|