actionpack 4.1.16 → 4.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +163 -690
- data/README.rdoc +7 -2
- data/lib/abstract_controller/base.rb +16 -6
- data/lib/abstract_controller/callbacks.rb +28 -51
- data/lib/abstract_controller/helpers.rb +0 -3
- data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
- data/lib/abstract_controller/rendering.rb +1 -7
- data/lib/abstract_controller/url_for.rb +1 -1
- data/lib/action_controller.rb +1 -0
- data/lib/action_controller/base.rb +2 -1
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/caching/fragments.rb +7 -1
- data/lib/action_controller/log_subscriber.rb +26 -25
- data/lib/action_controller/metal.rb +11 -7
- data/lib/action_controller/metal/conditional_get.rb +31 -6
- data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
- data/lib/action_controller/metal/force_ssl.rb +1 -1
- data/lib/action_controller/metal/head.rb +2 -0
- data/lib/action_controller/metal/http_authentication.rb +3 -15
- data/lib/action_controller/metal/instrumentation.rb +4 -7
- data/lib/action_controller/metal/live.rb +57 -6
- data/lib/action_controller/metal/mime_responds.rb +17 -227
- data/lib/action_controller/metal/redirecting.rb +14 -8
- data/lib/action_controller/metal/renderers.rb +19 -3
- data/lib/action_controller/metal/rendering.rb +2 -6
- data/lib/action_controller/metal/request_forgery_protection.rb +75 -7
- data/lib/action_controller/metal/streaming.rb +1 -1
- data/lib/action_controller/metal/strong_parameters.rb +111 -11
- data/lib/action_controller/metal/url_for.rb +11 -12
- data/lib/action_controller/model_naming.rb +1 -1
- data/lib/action_controller/railtie.rb +4 -0
- data/lib/action_controller/test_case.rb +87 -75
- data/lib/action_dispatch/http/cache.rb +1 -1
- data/lib/action_dispatch/http/filter_parameters.rb +2 -2
- data/lib/action_dispatch/http/headers.rb +43 -9
- data/lib/action_dispatch/http/mime_negotiation.rb +10 -4
- data/lib/action_dispatch/http/mime_type.rb +2 -16
- data/lib/action_dispatch/http/parameter_filter.rb +1 -1
- data/lib/action_dispatch/http/parameters.rb +11 -26
- data/lib/action_dispatch/http/request.rb +30 -10
- data/lib/action_dispatch/http/response.rb +52 -17
- data/lib/action_dispatch/http/upload.rb +3 -8
- data/lib/action_dispatch/http/url.rb +87 -70
- data/lib/action_dispatch/journey/formatter.rb +18 -17
- data/lib/action_dispatch/journey/gtg/builder.rb +3 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +10 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +18 -26
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
- data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -5
- data/lib/action_dispatch/journey/nodes/node.rb +4 -0
- data/lib/action_dispatch/journey/parser.rb +52 -60
- data/lib/action_dispatch/journey/parser.y +11 -10
- data/lib/action_dispatch/journey/path/pattern.rb +16 -19
- data/lib/action_dispatch/journey/route.rb +3 -18
- data/lib/action_dispatch/journey/router.rb +34 -65
- data/lib/action_dispatch/journey/router/strexp.rb +9 -6
- data/lib/action_dispatch/journey/routes.rb +0 -4
- data/lib/action_dispatch/journey/visitors.rb +81 -92
- data/lib/action_dispatch/journey/visualizer/index.html.erb +2 -2
- data/lib/action_dispatch/middleware/cookies.rb +27 -31
- data/lib/action_dispatch/middleware/debug_exceptions.rb +32 -3
- data/lib/action_dispatch/middleware/exception_wrapper.rb +19 -17
- data/lib/action_dispatch/middleware/flash.rb +7 -4
- data/lib/action_dispatch/middleware/public_exceptions.rb +13 -8
- data/lib/action_dispatch/middleware/remote_ip.rb +3 -3
- data/lib/action_dispatch/middleware/request_id.rb +1 -1
- data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +1 -0
- data/lib/action_dispatch/middleware/static.rb +22 -23
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +22 -18
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +36 -8
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +2 -8
- data/lib/action_dispatch/middleware/templates/rescues/{diagnostics.erb → diagnostics.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -24
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +0 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +119 -63
- data/lib/action_dispatch/routing/endpoint.rb +10 -0
- data/lib/action_dispatch/routing/inspector.rb +4 -11
- data/lib/action_dispatch/routing/mapper.rb +399 -278
- data/lib/action_dispatch/routing/polymorphic_routes.rb +190 -78
- data/lib/action_dispatch/routing/redirection.rb +10 -12
- data/lib/action_dispatch/routing/route_set.rb +224 -177
- data/lib/action_dispatch/routing/url_for.rb +9 -4
- data/lib/action_dispatch/testing/assertions.rb +11 -7
- data/lib/action_dispatch/testing/assertions/dom.rb +2 -26
- data/lib/action_dispatch/testing/assertions/response.rb +2 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +9 -9
- data/lib/action_dispatch/testing/assertions/selector.rb +2 -429
- data/lib/action_dispatch/testing/assertions/tag.rb +2 -134
- data/lib/action_dispatch/testing/integration.rb +15 -18
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +5 -1
- data/lib/action_pack/gem_version.rb +3 -3
- metadata +57 -15
- data/lib/action_controller/metal/responder.rb +0 -297
@@ -1,11 +1,11 @@
|
|
1
1
|
class ActionDispatch::Journey::Parser
|
2
|
-
|
2
|
+
options no_result_var
|
3
3
|
token SLASH LITERAL SYMBOL LPAREN RPAREN DOT STAR OR
|
4
4
|
|
5
5
|
rule
|
6
6
|
expressions
|
7
|
-
: expressions
|
8
|
-
| expression {
|
7
|
+
: expression expressions { Cat.new(val.first, val.last) }
|
8
|
+
| expression { val.first }
|
9
9
|
| or
|
10
10
|
;
|
11
11
|
expression
|
@@ -14,13 +14,14 @@ rule
|
|
14
14
|
| star
|
15
15
|
;
|
16
16
|
group
|
17
|
-
: LPAREN expressions RPAREN {
|
17
|
+
: LPAREN expressions RPAREN { Group.new(val[1]) }
|
18
18
|
;
|
19
19
|
or
|
20
|
-
:
|
20
|
+
: expression OR expression { Or.new([val.first, val.last]) }
|
21
|
+
| expression OR or { Or.new([val.first, val.last]) }
|
21
22
|
;
|
22
23
|
star
|
23
|
-
: STAR {
|
24
|
+
: STAR { Star.new(Symbol.new(val.last)) }
|
24
25
|
;
|
25
26
|
terminal
|
26
27
|
: symbol
|
@@ -29,16 +30,16 @@ rule
|
|
29
30
|
| dot
|
30
31
|
;
|
31
32
|
slash
|
32
|
-
: SLASH {
|
33
|
+
: SLASH { Slash.new('/') }
|
33
34
|
;
|
34
35
|
symbol
|
35
|
-
: SYMBOL {
|
36
|
+
: SYMBOL { Symbol.new(val.first) }
|
36
37
|
;
|
37
38
|
literal
|
38
|
-
: LITERAL {
|
39
|
+
: LITERAL { Literal.new(val.first) }
|
39
40
|
;
|
40
41
|
dot
|
41
|
-
: DOT {
|
42
|
+
: DOT { Dot.new(val.first) }
|
42
43
|
;
|
43
44
|
|
44
45
|
end
|
@@ -1,27 +1,20 @@
|
|
1
|
+
require 'action_dispatch/journey/router/strexp'
|
2
|
+
|
1
3
|
module ActionDispatch
|
2
4
|
module Journey # :nodoc:
|
3
5
|
module Path # :nodoc:
|
4
6
|
class Pattern # :nodoc:
|
5
7
|
attr_reader :spec, :requirements, :anchored
|
6
8
|
|
7
|
-
def
|
8
|
-
|
9
|
-
|
10
|
-
@anchored = true
|
9
|
+
def self.from_string string
|
10
|
+
new Journey::Router::Strexp.build(string, {}, ["/.?"], true)
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
when Router::Strexp
|
18
|
-
@spec = parser.parse(strexp.path)
|
19
|
-
@requirements = strexp.requirements
|
20
|
-
@separators = strexp.separators.join
|
21
|
-
@anchored = strexp.anchor
|
22
|
-
else
|
23
|
-
raise ArgumentError, "Bad expression: #{strexp}"
|
24
|
-
end
|
13
|
+
def initialize(strexp)
|
14
|
+
@spec = strexp.ast
|
15
|
+
@requirements = strexp.requirements
|
16
|
+
@separators = strexp.separators.join
|
17
|
+
@anchored = strexp.anchor
|
25
18
|
|
26
19
|
@names = nil
|
27
20
|
@optional_names = nil
|
@@ -30,6 +23,10 @@ module ActionDispatch
|
|
30
23
|
@offsets = nil
|
31
24
|
end
|
32
25
|
|
26
|
+
def build_formatter
|
27
|
+
Visitors::FormatBuilder.new.accept(spec)
|
28
|
+
end
|
29
|
+
|
33
30
|
def ast
|
34
31
|
@spec.grep(Nodes::Symbol).each do |node|
|
35
32
|
re = @requirements[node.to_sym]
|
@@ -53,9 +50,9 @@ module ActionDispatch
|
|
53
50
|
end
|
54
51
|
|
55
52
|
def optional_names
|
56
|
-
@optional_names ||= spec.grep(Nodes::Group).
|
53
|
+
@optional_names ||= spec.grep(Nodes::Group).flat_map { |group|
|
57
54
|
group.grep(Nodes::Symbol)
|
58
|
-
}.
|
55
|
+
}.map { |n| n.name }.uniq
|
59
56
|
end
|
60
57
|
|
61
58
|
class RegexpOffsets < Journey::Visitors::Visitor # :nodoc:
|
@@ -16,14 +16,6 @@ module ActionDispatch
|
|
16
16
|
@app = app
|
17
17
|
@path = path
|
18
18
|
|
19
|
-
# Unwrap any constraints so we can see what's inside for route generation.
|
20
|
-
# This allows the formatter to skip over any mounted applications or redirects
|
21
|
-
# that shouldn't be matched when using a url_for without a route name.
|
22
|
-
while app.is_a?(Routing::Mapper::Constraints) do
|
23
|
-
app = app.app
|
24
|
-
end
|
25
|
-
@dispatcher = app.is_a?(Routing::RouteSet::Dispatcher)
|
26
|
-
|
27
19
|
@constraints = constraints
|
28
20
|
@defaults = defaults
|
29
21
|
@required_defaults = nil
|
@@ -31,6 +23,7 @@ module ActionDispatch
|
|
31
23
|
@parts = nil
|
32
24
|
@decorated_ast = nil
|
33
25
|
@precedence = 0
|
26
|
+
@path_formatter = @path.build_formatter
|
34
27
|
end
|
35
28
|
|
36
29
|
def ast
|
@@ -72,15 +65,7 @@ module ActionDispatch
|
|
72
65
|
alias :segment_keys :parts
|
73
66
|
|
74
67
|
def format(path_options)
|
75
|
-
|
76
|
-
value.to_s == defaults[key].to_s && !required_parts.include?(key)
|
77
|
-
end
|
78
|
-
|
79
|
-
Visitors::Formatter.new(path_options).accept(path.spec)
|
80
|
-
end
|
81
|
-
|
82
|
-
def optimized_path
|
83
|
-
Visitors::OptimizedPath.new.accept(path.spec)
|
68
|
+
@path_formatter.evaluate path_options
|
84
69
|
end
|
85
70
|
|
86
71
|
def optional_parts
|
@@ -106,7 +91,7 @@ module ActionDispatch
|
|
106
91
|
end
|
107
92
|
|
108
93
|
def dispatcher?
|
109
|
-
@dispatcher
|
94
|
+
@app.dispatcher?
|
110
95
|
end
|
111
96
|
|
112
97
|
def matches?(request)
|
@@ -20,62 +20,32 @@ module ActionDispatch
|
|
20
20
|
# :nodoc:
|
21
21
|
VERSION = '2.0.0'
|
22
22
|
|
23
|
-
class NullReq # :nodoc:
|
24
|
-
attr_reader :env
|
25
|
-
def initialize(env)
|
26
|
-
@env = env
|
27
|
-
end
|
28
|
-
|
29
|
-
def request_method
|
30
|
-
env['REQUEST_METHOD']
|
31
|
-
end
|
32
|
-
|
33
|
-
def path_info
|
34
|
-
env['PATH_INFO']
|
35
|
-
end
|
36
|
-
|
37
|
-
def ip
|
38
|
-
env['REMOTE_ADDR']
|
39
|
-
end
|
40
|
-
|
41
|
-
def [](k)
|
42
|
-
env[k]
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
attr_reader :request_class, :formatter
|
47
23
|
attr_accessor :routes
|
48
24
|
|
49
|
-
def initialize(routes
|
50
|
-
@
|
51
|
-
@params_key = options[:parameters_key]
|
52
|
-
@request_class = options[:request_class] || NullReq
|
53
|
-
@routes = routes
|
25
|
+
def initialize(routes)
|
26
|
+
@routes = routes
|
54
27
|
end
|
55
28
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
script_name
|
61
|
-
'PATH_INFO',
|
62
|
-
@params_key)
|
29
|
+
def serve(req)
|
30
|
+
find_routes(req).each do |match, parameters, route|
|
31
|
+
set_params = req.path_parameters
|
32
|
+
path_info = req.path_info
|
33
|
+
script_name = req.script_name
|
63
34
|
|
64
35
|
unless route.path.anchored
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
env['PATH_INFO'] = "/" + matched_path unless matched_path.start_with? "/"
|
36
|
+
req.script_name = (script_name.to_s + match.to_s).chomp('/')
|
37
|
+
req.path_info = match.post_match
|
38
|
+
req.path_info = "/" + req.path_info unless req.path_info.start_with? "/"
|
69
39
|
end
|
70
40
|
|
71
|
-
|
41
|
+
req.path_parameters = set_params.merge parameters
|
72
42
|
|
73
|
-
status, headers, body = route.app.
|
43
|
+
status, headers, body = route.app.serve(req)
|
74
44
|
|
75
45
|
if 'pass' == headers['X-Cascade']
|
76
|
-
|
77
|
-
|
78
|
-
|
46
|
+
req.script_name = script_name
|
47
|
+
req.path_info = path_info
|
48
|
+
req.path_parameters = set_params
|
79
49
|
next
|
80
50
|
end
|
81
51
|
|
@@ -85,14 +55,14 @@ module ActionDispatch
|
|
85
55
|
return [404, {'X-Cascade' => 'pass'}, ['Not Found']]
|
86
56
|
end
|
87
57
|
|
88
|
-
def recognize(
|
89
|
-
find_routes(
|
58
|
+
def recognize(rails_req)
|
59
|
+
find_routes(rails_req).each do |match, parameters, route|
|
90
60
|
unless route.path.anchored
|
91
|
-
|
92
|
-
|
61
|
+
rails_req.script_name = match.to_s
|
62
|
+
rails_req.path_info = match.post_match.sub(/^([^\/])/, '/\1')
|
93
63
|
end
|
94
64
|
|
95
|
-
yield(route,
|
65
|
+
yield(route, parameters)
|
96
66
|
end
|
97
67
|
end
|
98
68
|
|
@@ -123,33 +93,34 @@ module ActionDispatch
|
|
123
93
|
|
124
94
|
def filter_routes(path)
|
125
95
|
return [] unless ast
|
126
|
-
|
127
|
-
data ? data.memos : []
|
96
|
+
simulator.memos(path) { [] }
|
128
97
|
end
|
129
98
|
|
130
|
-
def find_routes
|
131
|
-
req = request_class.new(env)
|
132
|
-
|
99
|
+
def find_routes req
|
133
100
|
routes = filter_routes(req.path_info).concat custom_routes.find_all { |r|
|
134
101
|
r.path.match(req.path_info)
|
135
102
|
}
|
136
|
-
routes.concat get_routes_as_head(routes)
|
137
103
|
|
138
|
-
|
104
|
+
if req.env["REQUEST_METHOD"] === "HEAD"
|
105
|
+
routes.concat get_routes_as_head(routes)
|
106
|
+
end
|
107
|
+
|
108
|
+
routes.select! { |r| r.matches?(req) }
|
109
|
+
routes.sort_by!(&:precedence)
|
139
110
|
|
140
111
|
routes.map! { |r|
|
141
112
|
match_data = r.path.match(req.path_info)
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
[match_data,
|
113
|
+
path_parameters = r.defaults.dup
|
114
|
+
match_data.names.zip(match_data.captures) { |name,val|
|
115
|
+
path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
|
116
|
+
}
|
117
|
+
[match_data, path_parameters, r]
|
147
118
|
}
|
148
119
|
end
|
149
120
|
|
150
121
|
def get_routes_as_head(routes)
|
151
122
|
precedence = (routes.map(&:precedence).max || 0) + 1
|
152
|
-
routes
|
123
|
+
routes.select { |r|
|
153
124
|
r.verb === "GET" && !(r.verb === "HEAD")
|
154
125
|
}.map! { |r|
|
155
126
|
Route.new(r.name,
|
@@ -160,8 +131,6 @@ module ActionDispatch
|
|
160
131
|
route.precedence = r.precedence + precedence
|
161
132
|
end
|
162
133
|
}
|
163
|
-
routes.flatten!
|
164
|
-
routes
|
165
134
|
end
|
166
135
|
end
|
167
136
|
end
|
@@ -6,18 +6,21 @@ module ActionDispatch
|
|
6
6
|
alias :compile :new
|
7
7
|
end
|
8
8
|
|
9
|
-
attr_reader :path, :requirements, :separators, :anchor
|
9
|
+
attr_reader :path, :requirements, :separators, :anchor, :ast
|
10
10
|
|
11
|
-
def
|
11
|
+
def self.build(path, requirements, separators, anchor = true)
|
12
|
+
parser = Journey::Parser.new
|
13
|
+
ast = parser.parse path
|
14
|
+
new ast, path, requirements, separators, anchor
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(ast, path, requirements, separators, anchor = true)
|
18
|
+
@ast = ast
|
12
19
|
@path = path
|
13
20
|
@requirements = requirements
|
14
21
|
@separators = separators
|
15
22
|
@anchor = anchor
|
16
23
|
end
|
17
|
-
|
18
|
-
def names
|
19
|
-
@path.scan(/:\w+/).map { |s| s.tr(':', '') }
|
20
|
-
end
|
21
24
|
end
|
22
25
|
end
|
23
26
|
end
|
@@ -1,14 +1,57 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require 'thread_safe'
|
4
|
-
|
5
3
|
module ActionDispatch
|
6
4
|
module Journey # :nodoc:
|
5
|
+
class Format
|
6
|
+
ESCAPE_PATH = ->(value) { Router::Utils.escape_path(value) }
|
7
|
+
ESCAPE_SEGMENT = ->(value) { Router::Utils.escape_segment(value) }
|
8
|
+
|
9
|
+
class Parameter < Struct.new(:name, :escaper)
|
10
|
+
def escape(value); escaper.call value; end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.required_path(symbol)
|
14
|
+
Parameter.new symbol, ESCAPE_PATH
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.required_segment(symbol)
|
18
|
+
Parameter.new symbol, ESCAPE_SEGMENT
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(parts)
|
22
|
+
@parts = parts
|
23
|
+
@children = []
|
24
|
+
@parameters = []
|
25
|
+
|
26
|
+
parts.each_with_index do |object,i|
|
27
|
+
case object
|
28
|
+
when Journey::Format
|
29
|
+
@children << i
|
30
|
+
when Parameter
|
31
|
+
@parameters << i
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def evaluate(hash)
|
37
|
+
parts = @parts.dup
|
38
|
+
|
39
|
+
@parameters.each do |index|
|
40
|
+
param = parts[index]
|
41
|
+
value = hash[param.name]
|
42
|
+
return ''.freeze unless value
|
43
|
+
parts[index] = param.escape value
|
44
|
+
end
|
45
|
+
|
46
|
+
@children.each { |index| parts[index] = parts[index].evaluate(hash) }
|
47
|
+
|
48
|
+
parts.join
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
7
52
|
module Visitors # :nodoc:
|
8
53
|
class Visitor # :nodoc:
|
9
|
-
DISPATCH_CACHE =
|
10
|
-
h[k] = :"visit_#{k}"
|
11
|
-
}
|
54
|
+
DISPATCH_CACHE = {}
|
12
55
|
|
13
56
|
def accept(node)
|
14
57
|
visit(node)
|
@@ -38,11 +81,41 @@ module ActionDispatch
|
|
38
81
|
def visit_STAR(n); unary(n); end
|
39
82
|
|
40
83
|
def terminal(node); end
|
41
|
-
|
42
|
-
|
84
|
+
def visit_LITERAL(n); terminal(n); end
|
85
|
+
def visit_SYMBOL(n); terminal(n); end
|
86
|
+
def visit_SLASH(n); terminal(n); end
|
87
|
+
def visit_DOT(n); terminal(n); end
|
88
|
+
|
89
|
+
private_instance_methods(false).each do |pim|
|
90
|
+
next unless pim =~ /^visit_(.*)$/
|
91
|
+
DISPATCH_CACHE[$1.to_sym] = pim
|
43
92
|
end
|
44
93
|
end
|
45
94
|
|
95
|
+
class FormatBuilder < Visitor # :nodoc:
|
96
|
+
def accept(node); Journey::Format.new(super); end
|
97
|
+
def terminal(node); [node.left]; end
|
98
|
+
|
99
|
+
def binary(node)
|
100
|
+
visit(node.left) + visit(node.right)
|
101
|
+
end
|
102
|
+
|
103
|
+
def visit_GROUP(n); [Journey::Format.new(unary(n))]; end
|
104
|
+
|
105
|
+
def visit_STAR(n)
|
106
|
+
[Journey::Format.required_path(n.left.to_sym)]
|
107
|
+
end
|
108
|
+
|
109
|
+
def visit_SYMBOL(n)
|
110
|
+
symbol = n.to_sym
|
111
|
+
if symbol == :controller
|
112
|
+
[Journey::Format.required_path(symbol)]
|
113
|
+
else
|
114
|
+
[Journey::Format.required_segment(symbol)]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
46
119
|
# Loop through the requirements AST
|
47
120
|
class Each < Visitor # :nodoc:
|
48
121
|
attr_reader :block
|
@@ -52,8 +125,8 @@ module ActionDispatch
|
|
52
125
|
end
|
53
126
|
|
54
127
|
def visit(node)
|
55
|
-
super
|
56
128
|
block.call(node)
|
129
|
+
super
|
57
130
|
end
|
58
131
|
end
|
59
132
|
|
@@ -77,90 +150,6 @@ module ActionDispatch
|
|
77
150
|
end
|
78
151
|
end
|
79
152
|
|
80
|
-
class OptimizedPath < Visitor # :nodoc:
|
81
|
-
def accept(node)
|
82
|
-
Array(visit(node))
|
83
|
-
end
|
84
|
-
|
85
|
-
private
|
86
|
-
|
87
|
-
def visit_CAT(node)
|
88
|
-
[visit(node.left), visit(node.right)].flatten
|
89
|
-
end
|
90
|
-
|
91
|
-
def visit_SYMBOL(node)
|
92
|
-
node.left[1..-1].to_sym
|
93
|
-
end
|
94
|
-
|
95
|
-
def visit_STAR(node)
|
96
|
-
visit(node.left)
|
97
|
-
end
|
98
|
-
|
99
|
-
def visit_GROUP(node)
|
100
|
-
[]
|
101
|
-
end
|
102
|
-
|
103
|
-
%w{ LITERAL SLASH DOT }.each do |t|
|
104
|
-
class_eval %{ def visit_#{t}(n); n.left; end }, __FILE__, __LINE__
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# Used for formatting urls (url_for)
|
109
|
-
class Formatter < Visitor # :nodoc:
|
110
|
-
attr_reader :options
|
111
|
-
|
112
|
-
def initialize(options)
|
113
|
-
@options = options
|
114
|
-
end
|
115
|
-
|
116
|
-
private
|
117
|
-
def escape_path(value)
|
118
|
-
Router::Utils.escape_path(value)
|
119
|
-
end
|
120
|
-
|
121
|
-
def escape_segment(value)
|
122
|
-
Router::Utils.escape_segment(value)
|
123
|
-
end
|
124
|
-
|
125
|
-
def visit(node, optional = false)
|
126
|
-
case node.type
|
127
|
-
when :LITERAL, :SLASH, :DOT
|
128
|
-
node.left
|
129
|
-
when :STAR
|
130
|
-
visit_STAR(node.left)
|
131
|
-
when :GROUP
|
132
|
-
visit(node.left, true)
|
133
|
-
when :CAT
|
134
|
-
visit_CAT(node, optional)
|
135
|
-
when :SYMBOL
|
136
|
-
visit_SYMBOL(node, node.to_sym)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
def visit_CAT(node, optional)
|
141
|
-
left = visit(node.left, optional)
|
142
|
-
right = visit(node.right, optional)
|
143
|
-
|
144
|
-
if optional && !(right && left)
|
145
|
-
""
|
146
|
-
else
|
147
|
-
[left, right].join
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
def visit_STAR(node)
|
152
|
-
if value = options[node.to_sym]
|
153
|
-
escape_path(value)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def visit_SYMBOL(node, name)
|
158
|
-
if value = options[name]
|
159
|
-
name == :controller ? escape_path(value) : escape_segment(value)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
153
|
class Dot < Visitor # :nodoc:
|
165
154
|
def initialize
|
166
155
|
@nodes = []
|