actionpack 4.2.11.3 → 5.0.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 +5 -5
- data/CHANGELOG.md +379 -462
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -3
- data/lib/abstract_controller.rb +0 -2
- data/lib/abstract_controller/base.rb +17 -32
- data/lib/abstract_controller/callbacks.rb +52 -19
- data/lib/abstract_controller/collector.rb +4 -9
- data/lib/abstract_controller/helpers.rb +2 -2
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
- data/lib/abstract_controller/rendering.rb +27 -22
- data/lib/abstract_controller/translation.rb +8 -7
- data/lib/action_controller.rb +4 -3
- data/lib/action_controller/api.rb +146 -0
- data/lib/action_controller/base.rb +6 -10
- data/lib/action_controller/caching.rb +1 -3
- data/lib/action_controller/caching/fragments.rb +48 -3
- data/lib/action_controller/form_builder.rb +48 -0
- data/lib/action_controller/log_subscriber.rb +1 -10
- data/lib/action_controller/metal.rb +89 -62
- data/lib/action_controller/metal/basic_implicit_render.rb +11 -0
- data/lib/action_controller/metal/conditional_get.rb +65 -24
- data/lib/action_controller/metal/cookies.rb +0 -2
- data/lib/action_controller/metal/data_streaming.rb +2 -22
- data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
- data/lib/action_controller/metal/exceptions.rb +11 -6
- data/lib/action_controller/metal/force_ssl.rb +6 -6
- data/lib/action_controller/metal/head.rb +14 -7
- data/lib/action_controller/metal/helpers.rb +9 -5
- data/lib/action_controller/metal/http_authentication.rb +37 -38
- data/lib/action_controller/metal/implicit_render.rb +23 -6
- data/lib/action_controller/metal/instrumentation.rb +0 -1
- data/lib/action_controller/metal/live.rb +17 -55
- data/lib/action_controller/metal/mime_responds.rb +17 -37
- data/lib/action_controller/metal/params_wrapper.rb +8 -8
- data/lib/action_controller/metal/redirecting.rb +32 -9
- data/lib/action_controller/metal/renderers.rb +10 -8
- data/lib/action_controller/metal/rendering.rb +38 -6
- data/lib/action_controller/metal/request_forgery_protection.rb +67 -35
- data/lib/action_controller/metal/rescue.rb +2 -4
- data/lib/action_controller/metal/streaming.rb +4 -4
- data/lib/action_controller/metal/strong_parameters.rb +231 -78
- data/lib/action_controller/metal/testing.rb +1 -12
- data/lib/action_controller/metal/url_for.rb +12 -5
- data/lib/action_controller/renderer.rb +111 -0
- data/lib/action_controller/template_assertions.rb +9 -0
- data/lib/action_controller/test_case.rb +267 -363
- data/lib/action_dispatch.rb +2 -1
- data/lib/action_dispatch/http/cache.rb +23 -26
- data/lib/action_dispatch/http/filter_parameters.rb +6 -8
- data/lib/action_dispatch/http/filter_redirect.rb +7 -8
- data/lib/action_dispatch/http/headers.rb +28 -11
- data/lib/action_dispatch/http/mime_negotiation.rb +40 -26
- data/lib/action_dispatch/http/mime_type.rb +92 -61
- data/lib/action_dispatch/http/mime_types.rb +1 -4
- data/lib/action_dispatch/http/parameter_filter.rb +18 -8
- data/lib/action_dispatch/http/parameters.rb +45 -41
- data/lib/action_dispatch/http/request.rb +146 -82
- data/lib/action_dispatch/http/response.rb +180 -99
- data/lib/action_dispatch/http/url.rb +117 -8
- data/lib/action_dispatch/journey/formatter.rb +34 -28
- data/lib/action_dispatch/journey/gtg/transition_table.rb +1 -1
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -2
- data/lib/action_dispatch/journey/nfa/transition_table.rb +1 -46
- data/lib/action_dispatch/journey/nodes/node.rb +14 -4
- data/lib/action_dispatch/journey/parser_extras.rb +4 -0
- data/lib/action_dispatch/journey/path/pattern.rb +37 -41
- data/lib/action_dispatch/journey/route.rb +71 -17
- data/lib/action_dispatch/journey/router.rb +5 -6
- data/lib/action_dispatch/journey/router/utils.rb +5 -5
- data/lib/action_dispatch/journey/routes.rb +14 -15
- data/lib/action_dispatch/journey/visitors.rb +86 -43
- data/lib/action_dispatch/middleware/cookies.rb +184 -135
- data/lib/action_dispatch/middleware/debug_exceptions.rb +115 -45
- data/lib/action_dispatch/middleware/exception_wrapper.rb +21 -20
- data/lib/action_dispatch/middleware/flash.rb +61 -45
- data/lib/action_dispatch/middleware/load_interlock.rb +21 -0
- data/lib/action_dispatch/middleware/params_parser.rb +30 -46
- data/lib/action_dispatch/middleware/public_exceptions.rb +2 -2
- data/lib/action_dispatch/middleware/reloader.rb +2 -4
- data/lib/action_dispatch/middleware/remote_ip.rb +29 -19
- data/lib/action_dispatch/middleware/request_id.rb +11 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +23 -11
- data/lib/action_dispatch/middleware/session/cache_store.rb +9 -6
- data/lib/action_dispatch/middleware/session/cookie_store.rb +29 -23
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +4 -0
- data/lib/action_dispatch/middleware/show_exceptions.rb +11 -9
- data/lib/action_dispatch/middleware/ssl.rb +93 -36
- data/lib/action_dispatch/middleware/stack.rb +43 -48
- data/lib/action_dispatch/middleware/static.rb +52 -40
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +59 -63
- data/lib/action_dispatch/railtie.rb +0 -2
- data/lib/action_dispatch/request/session.rb +66 -34
- data/lib/action_dispatch/request/utils.rb +51 -19
- data/lib/action_dispatch/routing.rb +3 -8
- data/lib/action_dispatch/routing/inspector.rb +6 -30
- data/lib/action_dispatch/routing/mapper.rb +447 -322
- data/lib/action_dispatch/routing/polymorphic_routes.rb +8 -14
- data/lib/action_dispatch/routing/redirection.rb +3 -3
- data/lib/action_dispatch/routing/route_set.rb +124 -227
- data/lib/action_dispatch/routing/url_for.rb +27 -10
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +27 -9
- data/lib/action_dispatch/testing/assertions/routing.rb +9 -9
- data/lib/action_dispatch/testing/integration.rb +237 -76
- data/lib/action_dispatch/testing/test_process.rb +5 -5
- data/lib/action_dispatch/testing/test_request.rb +12 -21
- data/lib/action_dispatch/testing/test_response.rb +1 -4
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/gem_version.rb +4 -4
- metadata +26 -25
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'action_dispatch/journey/router/strexp'
|
2
|
-
|
3
1
|
module ActionDispatch
|
4
2
|
module Journey # :nodoc:
|
5
3
|
module Path # :nodoc:
|
@@ -7,14 +5,20 @@ module ActionDispatch
|
|
7
5
|
attr_reader :spec, :requirements, :anchored
|
8
6
|
|
9
7
|
def self.from_string string
|
10
|
-
|
8
|
+
build(string, {}, "/.?", true)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.build(path, requirements, separators, anchored)
|
12
|
+
parser = Journey::Parser.new
|
13
|
+
ast = parser.parse path
|
14
|
+
new ast, requirements, separators, anchored
|
11
15
|
end
|
12
16
|
|
13
|
-
def initialize(
|
14
|
-
@spec =
|
15
|
-
@requirements =
|
16
|
-
@separators =
|
17
|
-
@anchored =
|
17
|
+
def initialize(ast, requirements, separators, anchored)
|
18
|
+
@spec = ast
|
19
|
+
@requirements = requirements
|
20
|
+
@separators = separators
|
21
|
+
@anchored = anchored
|
18
22
|
|
19
23
|
@names = nil
|
20
24
|
@optional_names = nil
|
@@ -28,12 +32,12 @@ module ActionDispatch
|
|
28
32
|
end
|
29
33
|
|
30
34
|
def ast
|
31
|
-
@spec.
|
35
|
+
@spec.find_all(&:symbol?).each do |node|
|
32
36
|
re = @requirements[node.to_sym]
|
33
37
|
node.regexp = re if re
|
34
38
|
end
|
35
39
|
|
36
|
-
@spec.
|
40
|
+
@spec.find_all(&:star?).each do |node|
|
37
41
|
node = node.left
|
38
42
|
node.regexp = @requirements[node.to_sym] || /(.+)/
|
39
43
|
end
|
@@ -42,7 +46,7 @@ module ActionDispatch
|
|
42
46
|
end
|
43
47
|
|
44
48
|
def names
|
45
|
-
@names ||= spec.
|
49
|
+
@names ||= spec.find_all(&:symbol?).map(&:name)
|
46
50
|
end
|
47
51
|
|
48
52
|
def required_names
|
@@ -50,34 +54,9 @@ module ActionDispatch
|
|
50
54
|
end
|
51
55
|
|
52
56
|
def optional_names
|
53
|
-
@optional_names ||= spec.
|
54
|
-
group.
|
55
|
-
}.map
|
56
|
-
end
|
57
|
-
|
58
|
-
class RegexpOffsets < Journey::Visitors::Visitor # :nodoc:
|
59
|
-
attr_reader :offsets
|
60
|
-
|
61
|
-
def initialize(matchers)
|
62
|
-
@matchers = matchers
|
63
|
-
@capture_count = [0]
|
64
|
-
end
|
65
|
-
|
66
|
-
def visit(node)
|
67
|
-
super
|
68
|
-
@capture_count
|
69
|
-
end
|
70
|
-
|
71
|
-
def visit_SYMBOL(node)
|
72
|
-
node = node.to_sym
|
73
|
-
|
74
|
-
if @matchers.key?(node)
|
75
|
-
re = /#{@matchers[node]}|/
|
76
|
-
@capture_count.push((re.match('').length - 1) + (@capture_count.last || 0))
|
77
|
-
else
|
78
|
-
@capture_count << (@capture_count.last || 0)
|
79
|
-
end
|
80
|
-
end
|
57
|
+
@optional_names ||= spec.find_all(&:group?).flat_map { |group|
|
58
|
+
group.find_all(&:symbol?)
|
59
|
+
}.map(&:name).uniq
|
81
60
|
end
|
82
61
|
|
83
62
|
class AnchoredRegexp < Journey::Visitors::Visitor # :nodoc:
|
@@ -122,6 +101,11 @@ module ActionDispatch
|
|
122
101
|
re = @matchers[node.left.to_sym] || '.+'
|
123
102
|
"(#{re})"
|
124
103
|
end
|
104
|
+
|
105
|
+
def visit_OR(node)
|
106
|
+
children = node.children.map { |n| visit n }
|
107
|
+
"(?:#{children.join(?|)})"
|
108
|
+
end
|
125
109
|
end
|
126
110
|
|
127
111
|
class UnanchoredRegexp < AnchoredRegexp # :nodoc:
|
@@ -184,8 +168,20 @@ module ActionDispatch
|
|
184
168
|
def offsets
|
185
169
|
return @offsets if @offsets
|
186
170
|
|
187
|
-
|
188
|
-
|
171
|
+
@offsets = [0]
|
172
|
+
|
173
|
+
spec.find_all(&:symbol?).each do |node|
|
174
|
+
node = node.to_sym
|
175
|
+
|
176
|
+
if @requirements.key?(node)
|
177
|
+
re = /#{@requirements[node]}|/
|
178
|
+
@offsets.push((re.match('').length - 1) + @offsets.last)
|
179
|
+
else
|
180
|
+
@offsets << @offsets.last
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
@offsets
|
189
185
|
end
|
190
186
|
end
|
191
187
|
end
|
@@ -1,35 +1,81 @@
|
|
1
1
|
module ActionDispatch
|
2
2
|
module Journey # :nodoc:
|
3
3
|
class Route # :nodoc:
|
4
|
-
attr_reader :app, :path, :defaults, :name
|
4
|
+
attr_reader :app, :path, :defaults, :name, :precedence
|
5
5
|
|
6
6
|
attr_reader :constraints
|
7
7
|
alias :conditions :constraints
|
8
8
|
|
9
|
-
|
9
|
+
module VerbMatchers
|
10
|
+
VERBS = %w{ DELETE GET HEAD OPTIONS LINK PATCH POST PUT TRACE UNLINK }
|
11
|
+
VERBS.each do |v|
|
12
|
+
class_eval <<-eoc
|
13
|
+
class #{v}
|
14
|
+
def self.verb; name.split("::").last; end
|
15
|
+
def self.call(req); req.#{v.downcase}?; end
|
16
|
+
end
|
17
|
+
eoc
|
18
|
+
end
|
19
|
+
|
20
|
+
class Unknown
|
21
|
+
attr_reader :verb
|
22
|
+
|
23
|
+
def initialize(verb)
|
24
|
+
@verb = verb
|
25
|
+
end
|
26
|
+
|
27
|
+
def call(request); @verb === request.request_method; end
|
28
|
+
end
|
29
|
+
|
30
|
+
class All
|
31
|
+
def self.call(_); true; end
|
32
|
+
def self.verb; ''; end
|
33
|
+
end
|
34
|
+
|
35
|
+
VERB_TO_CLASS = VERBS.each_with_object({ :all => All }) do |verb, hash|
|
36
|
+
klass = const_get verb
|
37
|
+
hash[verb] = klass
|
38
|
+
hash[verb.downcase] = klass
|
39
|
+
hash[verb.downcase.to_sym] = klass
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.verb_matcher(verb)
|
45
|
+
VerbMatchers::VERB_TO_CLASS.fetch(verb) do
|
46
|
+
VerbMatchers::Unknown.new verb.to_s.dasherize.upcase
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.build(name, app, path, constraints, required_defaults, defaults)
|
51
|
+
request_method_match = verb_matcher(constraints.delete(:request_method))
|
52
|
+
new name, app, path, constraints, required_defaults, defaults, request_method_match, 0
|
53
|
+
end
|
10
54
|
|
11
55
|
##
|
12
56
|
# +path+ is a path constraint.
|
13
57
|
# +constraints+ is a hash of constraints to be applied to this route.
|
14
|
-
def initialize(name, app, path, constraints, defaults
|
58
|
+
def initialize(name, app, path, constraints, required_defaults, defaults, request_method_match, precedence)
|
15
59
|
@name = name
|
16
60
|
@app = app
|
17
61
|
@path = path
|
18
62
|
|
63
|
+
@request_method_match = request_method_match
|
19
64
|
@constraints = constraints
|
20
65
|
@defaults = defaults
|
21
66
|
@required_defaults = nil
|
67
|
+
@_required_defaults = required_defaults
|
22
68
|
@required_parts = nil
|
23
69
|
@parts = nil
|
24
70
|
@decorated_ast = nil
|
25
|
-
@precedence =
|
71
|
+
@precedence = precedence
|
26
72
|
@path_formatter = @path.build_formatter
|
27
73
|
end
|
28
74
|
|
29
75
|
def ast
|
30
76
|
@decorated_ast ||= begin
|
31
77
|
decorated_ast = path.ast
|
32
|
-
decorated_ast.
|
78
|
+
decorated_ast.find_all(&:terminal?).each { |n| n.memo = self }
|
33
79
|
decorated_ast
|
34
80
|
end
|
35
81
|
end
|
@@ -60,7 +106,7 @@ module ActionDispatch
|
|
60
106
|
end
|
61
107
|
|
62
108
|
def parts
|
63
|
-
@parts ||= segments.map
|
109
|
+
@parts ||= segments.map(&:to_sym)
|
64
110
|
end
|
65
111
|
alias :segment_keys :parts
|
66
112
|
|
@@ -68,16 +114,12 @@ module ActionDispatch
|
|
68
114
|
@path_formatter.evaluate path_options
|
69
115
|
end
|
70
116
|
|
71
|
-
def optional_parts
|
72
|
-
path.optional_names.map { |n| n.to_sym }
|
73
|
-
end
|
74
|
-
|
75
117
|
def required_parts
|
76
|
-
@required_parts ||= path.required_names.map
|
118
|
+
@required_parts ||= path.required_names.map(&:to_sym)
|
77
119
|
end
|
78
120
|
|
79
121
|
def required_default?(key)
|
80
|
-
|
122
|
+
@_required_defaults.include?(key)
|
81
123
|
end
|
82
124
|
|
83
125
|
def required_defaults
|
@@ -95,9 +137,8 @@ module ActionDispatch
|
|
95
137
|
end
|
96
138
|
|
97
139
|
def matches?(request)
|
98
|
-
|
99
|
-
|
100
|
-
|
140
|
+
match_verb(request) &&
|
141
|
+
constraints.all? { |method, value|
|
101
142
|
case value
|
102
143
|
when Regexp, String
|
103
144
|
value === request.send(method).to_s
|
@@ -110,15 +151,28 @@ module ActionDispatch
|
|
110
151
|
else
|
111
152
|
value === request.send(method)
|
112
153
|
end
|
113
|
-
|
154
|
+
}
|
114
155
|
end
|
115
156
|
|
116
157
|
def ip
|
117
158
|
constraints[:ip] || //
|
118
159
|
end
|
119
160
|
|
161
|
+
def requires_matching_verb?
|
162
|
+
!@request_method_match.all? { |x| x == VerbMatchers::All }
|
163
|
+
end
|
164
|
+
|
120
165
|
def verb
|
121
|
-
|
166
|
+
verbs.join('|')
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
def verbs
|
171
|
+
@request_method_match.map(&:verb)
|
172
|
+
end
|
173
|
+
|
174
|
+
def match_verb(request)
|
175
|
+
@request_method_match.any? { |m| m.call request }
|
122
176
|
end
|
123
177
|
end
|
124
178
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'action_dispatch/journey/router/utils'
|
2
|
-
require 'action_dispatch/journey/router/strexp'
|
3
2
|
require 'action_dispatch/journey/routes'
|
4
3
|
require 'action_dispatch/journey/formatter'
|
5
4
|
|
@@ -68,8 +67,8 @@ module ActionDispatch
|
|
68
67
|
|
69
68
|
def visualizer
|
70
69
|
tt = GTG::Builder.new(ast).transition_table
|
71
|
-
groups = partitioned_routes.first.map(&:ast).group_by
|
72
|
-
asts = groups.values.map
|
70
|
+
groups = partitioned_routes.first.map(&:ast).group_by(&:to_s)
|
71
|
+
asts = groups.values.map(&:first)
|
73
72
|
tt.visualizer(asts)
|
74
73
|
end
|
75
74
|
|
@@ -88,7 +87,7 @@ module ActionDispatch
|
|
88
87
|
end
|
89
88
|
|
90
89
|
def custom_routes
|
91
|
-
|
90
|
+
routes.custom_routes
|
92
91
|
end
|
93
92
|
|
94
93
|
def filter_routes(path)
|
@@ -102,7 +101,7 @@ module ActionDispatch
|
|
102
101
|
}
|
103
102
|
|
104
103
|
routes =
|
105
|
-
if req.
|
104
|
+
if req.head?
|
106
105
|
match_head_routes(routes, req)
|
107
106
|
else
|
108
107
|
match_routes(routes, req)
|
@@ -121,7 +120,7 @@ module ActionDispatch
|
|
121
120
|
end
|
122
121
|
|
123
122
|
def match_head_routes(routes, req)
|
124
|
-
verb_specific_routes = routes.
|
123
|
+
verb_specific_routes = routes.select(&:requires_matching_verb?)
|
125
124
|
head_routes = match_routes(verb_specific_routes, req)
|
126
125
|
|
127
126
|
if head_routes.empty?
|
@@ -13,11 +13,11 @@ module ActionDispatch
|
|
13
13
|
# normalize_path("") # => "/"
|
14
14
|
# normalize_path("/%ab") # => "/%AB"
|
15
15
|
def self.normalize_path(path)
|
16
|
-
path = "/#{path}"
|
17
|
-
path.squeeze!('/')
|
18
|
-
path.sub!(%r{/+\Z}, '')
|
16
|
+
path = "/#{path}"
|
17
|
+
path.squeeze!('/'.freeze)
|
18
|
+
path.sub!(%r{/+\Z}, ''.freeze)
|
19
19
|
path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
|
20
|
-
path = '/' if path == ''
|
20
|
+
path = '/' if path == ''.freeze
|
21
21
|
path
|
22
22
|
end
|
23
23
|
|
@@ -55,7 +55,7 @@ module ActionDispatch
|
|
55
55
|
|
56
56
|
def unescape_uri(uri)
|
57
57
|
encoding = uri.encoding == US_ASCII ? UTF_8 : uri.encoding
|
58
|
-
uri.gsub(ESCAPED) { [
|
58
|
+
uri.gsub(ESCAPED) { |match| [match[1, 2].hex].pack('C') }.force_encoding(encoding)
|
59
59
|
end
|
60
60
|
|
61
61
|
protected
|
@@ -5,13 +5,13 @@ module ActionDispatch
|
|
5
5
|
class Routes # :nodoc:
|
6
6
|
include Enumerable
|
7
7
|
|
8
|
-
attr_reader :routes, :
|
8
|
+
attr_reader :routes, :custom_routes, :anchored_routes
|
9
9
|
|
10
10
|
def initialize
|
11
11
|
@routes = []
|
12
|
-
@named_routes = {}
|
13
12
|
@ast = nil
|
14
|
-
@
|
13
|
+
@anchored_routes = []
|
14
|
+
@custom_routes = []
|
15
15
|
@simulator = nil
|
16
16
|
end
|
17
17
|
|
@@ -34,18 +34,21 @@ module ActionDispatch
|
|
34
34
|
|
35
35
|
def clear
|
36
36
|
routes.clear
|
37
|
-
|
37
|
+
anchored_routes.clear
|
38
|
+
custom_routes.clear
|
38
39
|
end
|
39
40
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
41
|
+
def partition_route(route)
|
42
|
+
if route.path.anchored && route.ast.grep(Nodes::Symbol).all?(&:default_regexp?)
|
43
|
+
anchored_routes << route
|
44
|
+
else
|
45
|
+
custom_routes << route
|
43
46
|
end
|
44
47
|
end
|
45
48
|
|
46
49
|
def ast
|
47
50
|
@ast ||= begin
|
48
|
-
asts =
|
51
|
+
asts = anchored_routes.map(&:ast)
|
49
52
|
Nodes::Or.new(asts) unless asts.empty?
|
50
53
|
end
|
51
54
|
end
|
@@ -57,13 +60,10 @@ module ActionDispatch
|
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
60
|
-
|
61
|
-
|
62
|
-
route = Route.new(name, app, path, conditions, defaults)
|
63
|
-
|
64
|
-
route.precedence = routes.length
|
63
|
+
def add_route(name, mapping)
|
64
|
+
route = mapping.make_route name, routes.length
|
65
65
|
routes << route
|
66
|
-
|
66
|
+
partition_route(route)
|
67
67
|
clear_cache!
|
68
68
|
route
|
69
69
|
end
|
@@ -72,7 +72,6 @@ module ActionDispatch
|
|
72
72
|
|
73
73
|
def clear_cache!
|
74
74
|
@ast = nil
|
75
|
-
@partitioned_routes = nil
|
76
75
|
@simulator = nil
|
77
76
|
end
|
78
77
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module ActionDispatch
|
4
2
|
module Journey # :nodoc:
|
5
3
|
class Format
|
@@ -92,6 +90,45 @@ module ActionDispatch
|
|
92
90
|
end
|
93
91
|
end
|
94
92
|
|
93
|
+
class FunctionalVisitor # :nodoc:
|
94
|
+
DISPATCH_CACHE = {}
|
95
|
+
|
96
|
+
def accept(node, seed)
|
97
|
+
visit(node, seed)
|
98
|
+
end
|
99
|
+
|
100
|
+
def visit node, seed
|
101
|
+
send(DISPATCH_CACHE[node.type], node, seed)
|
102
|
+
end
|
103
|
+
|
104
|
+
def binary(node, seed)
|
105
|
+
visit(node.right, visit(node.left, seed))
|
106
|
+
end
|
107
|
+
def visit_CAT(n, seed); binary(n, seed); end
|
108
|
+
|
109
|
+
def nary(node, seed)
|
110
|
+
node.children.inject(seed) { |s, c| visit(c, s) }
|
111
|
+
end
|
112
|
+
def visit_OR(n, seed); nary(n, seed); end
|
113
|
+
|
114
|
+
def unary(node, seed)
|
115
|
+
visit(node.left, seed)
|
116
|
+
end
|
117
|
+
def visit_GROUP(n, seed); unary(n, seed); end
|
118
|
+
def visit_STAR(n, seed); unary(n, seed); end
|
119
|
+
|
120
|
+
def terminal(node, seed); seed; end
|
121
|
+
def visit_LITERAL(n, seed); terminal(n, seed); end
|
122
|
+
def visit_SYMBOL(n, seed); terminal(n, seed); end
|
123
|
+
def visit_SLASH(n, seed); terminal(n, seed); end
|
124
|
+
def visit_DOT(n, seed); terminal(n, seed); end
|
125
|
+
|
126
|
+
instance_methods(false).each do |pim|
|
127
|
+
next unless pim =~ /^visit_(.*)$/
|
128
|
+
DISPATCH_CACHE[$1.to_sym] = pim
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
95
132
|
class FormatBuilder < Visitor # :nodoc:
|
96
133
|
def accept(node); Journey::Format.new(super); end
|
97
134
|
def terminal(node); [node.left]; end
|
@@ -117,104 +154,110 @@ module ActionDispatch
|
|
117
154
|
end
|
118
155
|
|
119
156
|
# Loop through the requirements AST
|
120
|
-
class Each <
|
121
|
-
|
122
|
-
|
123
|
-
def initialize(block)
|
124
|
-
@block = block
|
125
|
-
end
|
126
|
-
|
127
|
-
def visit(node)
|
157
|
+
class Each < FunctionalVisitor # :nodoc:
|
158
|
+
def visit(node, block)
|
128
159
|
block.call(node)
|
129
160
|
super
|
130
161
|
end
|
162
|
+
|
163
|
+
INSTANCE = new
|
131
164
|
end
|
132
165
|
|
133
|
-
class String <
|
166
|
+
class String < FunctionalVisitor # :nodoc:
|
134
167
|
private
|
135
168
|
|
136
|
-
def binary(node)
|
137
|
-
|
169
|
+
def binary(node, seed)
|
170
|
+
visit(node.right, visit(node.left, seed))
|
138
171
|
end
|
139
172
|
|
140
|
-
def nary(node)
|
141
|
-
node.children.
|
173
|
+
def nary(node, seed)
|
174
|
+
last_child = node.children.last
|
175
|
+
node.children.inject(seed) { |s, c|
|
176
|
+
string = visit(c, s)
|
177
|
+
string << "|".freeze unless last_child == c
|
178
|
+
string
|
179
|
+
}
|
142
180
|
end
|
143
181
|
|
144
|
-
def terminal(node)
|
145
|
-
node.left
|
182
|
+
def terminal(node, seed)
|
183
|
+
seed + node.left
|
146
184
|
end
|
147
185
|
|
148
|
-
def visit_GROUP(node)
|
149
|
-
|
186
|
+
def visit_GROUP(node, seed)
|
187
|
+
visit(node.left, seed << "(".freeze) << ")".freeze
|
150
188
|
end
|
189
|
+
|
190
|
+
INSTANCE = new
|
151
191
|
end
|
152
192
|
|
153
|
-
class Dot <
|
193
|
+
class Dot < FunctionalVisitor # :nodoc:
|
154
194
|
def initialize
|
155
195
|
@nodes = []
|
156
196
|
@edges = []
|
157
197
|
end
|
158
198
|
|
159
|
-
def accept(node)
|
199
|
+
def accept(node, seed = [[], []])
|
160
200
|
super
|
201
|
+
nodes, edges = seed
|
161
202
|
<<-eodot
|
162
203
|
digraph parse_tree {
|
163
204
|
size="8,5"
|
164
205
|
node [shape = none];
|
165
206
|
edge [dir = none];
|
166
|
-
#{
|
167
|
-
#{
|
207
|
+
#{nodes.join "\n"}
|
208
|
+
#{edges.join("\n")}
|
168
209
|
}
|
169
210
|
eodot
|
170
211
|
end
|
171
212
|
|
172
213
|
private
|
173
214
|
|
174
|
-
def binary(node)
|
175
|
-
node.children.
|
176
|
-
|
177
|
-
|
215
|
+
def binary(node, seed)
|
216
|
+
seed.last.concat node.children.map { |c|
|
217
|
+
"#{node.object_id} -> #{c.object_id};"
|
218
|
+
}
|
178
219
|
super
|
179
220
|
end
|
180
221
|
|
181
|
-
def nary(node)
|
182
|
-
node.children.
|
183
|
-
|
184
|
-
|
222
|
+
def nary(node, seed)
|
223
|
+
seed.last.concat node.children.map { |c|
|
224
|
+
"#{node.object_id} -> #{c.object_id};"
|
225
|
+
}
|
185
226
|
super
|
186
227
|
end
|
187
228
|
|
188
|
-
def unary(node)
|
189
|
-
|
229
|
+
def unary(node, seed)
|
230
|
+
seed.last << "#{node.object_id} -> #{node.left.object_id};"
|
190
231
|
super
|
191
232
|
end
|
192
233
|
|
193
|
-
def visit_GROUP(node)
|
194
|
-
|
234
|
+
def visit_GROUP(node, seed)
|
235
|
+
seed.first << "#{node.object_id} [label=\"()\"];"
|
195
236
|
super
|
196
237
|
end
|
197
238
|
|
198
|
-
def visit_CAT(node)
|
199
|
-
|
239
|
+
def visit_CAT(node, seed)
|
240
|
+
seed.first << "#{node.object_id} [label=\"○\"];"
|
200
241
|
super
|
201
242
|
end
|
202
243
|
|
203
|
-
def visit_STAR(node)
|
204
|
-
|
244
|
+
def visit_STAR(node, seed)
|
245
|
+
seed.first << "#{node.object_id} [label=\"*\"];"
|
205
246
|
super
|
206
247
|
end
|
207
248
|
|
208
|
-
def visit_OR(node)
|
209
|
-
|
249
|
+
def visit_OR(node, seed)
|
250
|
+
seed.first << "#{node.object_id} [label=\"|\"];"
|
210
251
|
super
|
211
252
|
end
|
212
253
|
|
213
|
-
def terminal(node)
|
254
|
+
def terminal(node, seed)
|
214
255
|
value = node.left
|
215
256
|
|
216
|
-
|
257
|
+
seed.first << "#{node.object_id} [label=\"#{value}\"];"
|
258
|
+
seed
|
217
259
|
end
|
260
|
+
INSTANCE = new
|
218
261
|
end
|
219
262
|
end
|
220
263
|
end
|