actionpack 4.2.10 → 7.2.0.rc1
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 +86 -600
- data/MIT-LICENSE +1 -1
- data/README.rdoc +13 -14
- data/lib/abstract_controller/asset_paths.rb +5 -1
- data/lib/abstract_controller/base.rb +166 -136
- data/lib/abstract_controller/caching/fragments.rb +149 -0
- data/lib/abstract_controller/caching.rb +68 -0
- data/lib/abstract_controller/callbacks.rb +126 -57
- data/lib/abstract_controller/collector.rb +13 -15
- data/lib/abstract_controller/deprecator.rb +9 -0
- data/lib/abstract_controller/error.rb +8 -0
- data/lib/abstract_controller/helpers.rb +181 -132
- data/lib/abstract_controller/logger.rb +5 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +10 -3
- data/lib/abstract_controller/rendering.rb +56 -56
- data/lib/abstract_controller/translation.rb +29 -15
- data/lib/abstract_controller/url_for.rb +15 -11
- data/lib/abstract_controller.rb +21 -5
- data/lib/action_controller/api/api_rendering.rb +18 -0
- data/lib/action_controller/api.rb +154 -0
- data/lib/action_controller/base.rb +219 -155
- data/lib/action_controller/caching.rb +28 -68
- data/lib/action_controller/deprecator.rb +9 -0
- data/lib/action_controller/form_builder.rb +55 -0
- data/lib/action_controller/log_subscriber.rb +35 -22
- data/lib/action_controller/metal/allow_browser.rb +119 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
- data/lib/action_controller/metal/conditional_get.rb +259 -122
- data/lib/action_controller/metal/content_security_policy.rb +86 -0
- data/lib/action_controller/metal/cookies.rb +9 -5
- data/lib/action_controller/metal/data_streaming.rb +87 -104
- data/lib/action_controller/metal/default_headers.rb +21 -0
- data/lib/action_controller/metal/etag_with_flash.rb +22 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +35 -26
- data/lib/action_controller/metal/exceptions.rb +71 -24
- data/lib/action_controller/metal/flash.rb +26 -19
- data/lib/action_controller/metal/head.rb +45 -36
- data/lib/action_controller/metal/helpers.rb +80 -64
- data/lib/action_controller/metal/http_authentication.rb +297 -244
- data/lib/action_controller/metal/implicit_render.rb +57 -9
- data/lib/action_controller/metal/instrumentation.rb +76 -64
- data/lib/action_controller/metal/live.rb +238 -176
- data/lib/action_controller/metal/logging.rb +22 -0
- data/lib/action_controller/metal/mime_responds.rb +177 -166
- data/lib/action_controller/metal/parameter_encoding.rb +84 -0
- data/lib/action_controller/metal/params_wrapper.rb +145 -118
- data/lib/action_controller/metal/permissions_policy.rb +38 -0
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +203 -64
- data/lib/action_controller/metal/renderers.rb +108 -65
- data/lib/action_controller/metal/rendering.rb +216 -56
- data/lib/action_controller/metal/request_forgery_protection.rb +496 -163
- data/lib/action_controller/metal/rescue.rb +19 -21
- data/lib/action_controller/metal/streaming.rb +179 -138
- data/lib/action_controller/metal/strong_parameters.rb +1058 -382
- data/lib/action_controller/metal/testing.rb +11 -17
- data/lib/action_controller/metal/url_for.rb +37 -21
- data/lib/action_controller/metal.rb +236 -138
- data/lib/action_controller/railtie.rb +89 -11
- data/lib/action_controller/railties/helpers.rb +5 -1
- data/lib/action_controller/renderer.rb +161 -0
- data/lib/action_controller/template_assertions.rb +13 -0
- data/lib/action_controller/test_case.rb +425 -497
- data/lib/action_controller.rb +44 -22
- data/lib/action_dispatch/constants.rb +34 -0
- data/lib/action_dispatch/deprecator.rb +9 -0
- data/lib/action_dispatch/http/cache.rb +119 -63
- data/lib/action_dispatch/http/content_disposition.rb +47 -0
- data/lib/action_dispatch/http/content_security_policy.rb +364 -0
- data/lib/action_dispatch/http/filter_parameters.rb +36 -34
- data/lib/action_dispatch/http/filter_redirect.rb +24 -12
- data/lib/action_dispatch/http/headers.rb +66 -31
- data/lib/action_dispatch/http/mime_negotiation.rb +106 -75
- data/lib/action_dispatch/http/mime_type.rb +196 -136
- data/lib/action_dispatch/http/mime_types.rb +25 -7
- data/lib/action_dispatch/http/parameters.rb +97 -45
- data/lib/action_dispatch/http/permissions_policy.rb +187 -0
- data/lib/action_dispatch/http/rack_cache.rb +6 -0
- data/lib/action_dispatch/http/request.rb +299 -170
- data/lib/action_dispatch/http/response.rb +311 -160
- data/lib/action_dispatch/http/upload.rb +52 -23
- data/lib/action_dispatch/http/url.rb +201 -125
- data/lib/action_dispatch/journey/formatter.rb +110 -50
- data/lib/action_dispatch/journey/gtg/builder.rb +37 -50
- data/lib/action_dispatch/journey/gtg/simulator.rb +20 -17
- data/lib/action_dispatch/journey/gtg/transition_table.rb +96 -36
- data/lib/action_dispatch/journey/nfa/dot.rb +5 -14
- data/lib/action_dispatch/journey/nodes/node.rb +100 -20
- data/lib/action_dispatch/journey/parser.rb +19 -17
- data/lib/action_dispatch/journey/parser.y +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +14 -4
- data/lib/action_dispatch/journey/path/pattern.rb +79 -63
- data/lib/action_dispatch/journey/route.rb +108 -44
- data/lib/action_dispatch/journey/router/utils.rb +41 -29
- data/lib/action_dispatch/journey/router.rb +64 -57
- data/lib/action_dispatch/journey/routes.rb +23 -21
- data/lib/action_dispatch/journey/scanner.rb +28 -17
- data/lib/action_dispatch/journey/visitors.rb +100 -54
- data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
- data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
- data/lib/action_dispatch/journey.rb +7 -5
- data/lib/action_dispatch/log_subscriber.rb +25 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
- data/lib/action_dispatch/middleware/callbacks.rb +7 -6
- data/lib/action_dispatch/middleware/cookies.rb +471 -328
- data/lib/action_dispatch/middleware/debug_exceptions.rb +149 -66
- data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
- data/lib/action_dispatch/middleware/debug_view.rb +73 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +275 -73
- data/lib/action_dispatch/middleware/executor.rb +32 -0
- data/lib/action_dispatch/middleware/flash.rb +143 -101
- data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +36 -27
- data/lib/action_dispatch/middleware/reloader.rb +10 -92
- data/lib/action_dispatch/middleware/remote_ip.rb +133 -107
- data/lib/action_dispatch/middleware/request_id.rb +29 -15
- data/lib/action_dispatch/middleware/server_timing.rb +78 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +49 -27
- data/lib/action_dispatch/middleware/session/cache_store.rb +33 -16
- data/lib/action_dispatch/middleware/session/cookie_store.rb +86 -80
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +66 -36
- data/lib/action_dispatch/middleware/ssl.rb +134 -36
- data/lib/action_dispatch/middleware/stack.rb +109 -44
- data/lib/action_dispatch/middleware/static.rb +159 -90
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +7 -24
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +46 -36
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -7
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +139 -15
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +6 -6
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +9 -9
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +7 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +125 -93
- data/lib/action_dispatch/railtie.rb +44 -16
- data/lib/action_dispatch/request/session.rb +159 -69
- data/lib/action_dispatch/request/utils.rb +97 -23
- data/lib/action_dispatch/routing/endpoint.rb +11 -2
- data/lib/action_dispatch/routing/inspector.rb +195 -106
- data/lib/action_dispatch/routing/mapper.rb +1338 -955
- data/lib/action_dispatch/routing/polymorphic_routes.rb +234 -201
- data/lib/action_dispatch/routing/redirection.rb +78 -51
- data/lib/action_dispatch/routing/route_set.rb +460 -374
- data/lib/action_dispatch/routing/routes_proxy.rb +36 -12
- data/lib/action_dispatch/routing/url_for.rb +172 -124
- data/lib/action_dispatch/routing.rb +159 -158
- data/lib/action_dispatch/system_test_case.rb +206 -0
- data/lib/action_dispatch/system_testing/browser.rb +84 -0
- data/lib/action_dispatch/system_testing/driver.rb +85 -0
- data/lib/action_dispatch/system_testing/server.rb +33 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
- data/lib/action_dispatch/testing/assertion_response.rb +48 -0
- data/lib/action_dispatch/testing/assertions/response.rb +71 -39
- data/lib/action_dispatch/testing/assertions/routing.rb +228 -103
- data/lib/action_dispatch/testing/assertions.rb +9 -6
- data/lib/action_dispatch/testing/integration.rb +486 -306
- data/lib/action_dispatch/testing/request_encoder.rb +60 -0
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +35 -22
- data/lib/action_dispatch/testing/test_request.rb +29 -34
- data/lib/action_dispatch/testing/test_response.rb +48 -15
- data/lib/action_dispatch.rb +82 -40
- data/lib/action_pack/gem_version.rb +8 -4
- data/lib/action_pack/version.rb +6 -2
- data/lib/action_pack.rb +21 -18
- metadata +146 -56
- data/lib/action_controller/caching/fragments.rb +0 -103
- data/lib/action_controller/metal/force_ssl.rb +0 -97
- 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/http/parameter_filter.rb +0 -72
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +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,82 +1,95 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
4
|
+
|
5
|
+
require "action_dispatch/journey/router/utils"
|
6
|
+
require "action_dispatch/journey/routes"
|
7
|
+
require "action_dispatch/journey/formatter"
|
5
8
|
|
6
9
|
before = $-w
|
7
10
|
$-w = false
|
8
|
-
require
|
11
|
+
require "action_dispatch/journey/parser"
|
9
12
|
$-w = before
|
10
13
|
|
11
|
-
require
|
12
|
-
require
|
14
|
+
require "action_dispatch/journey/route"
|
15
|
+
require "action_dispatch/journey/path/pattern"
|
13
16
|
|
14
17
|
module ActionDispatch
|
15
18
|
module Journey # :nodoc:
|
16
19
|
class Router # :nodoc:
|
17
|
-
class RoutingError < ::StandardError # :nodoc:
|
18
|
-
end
|
19
|
-
|
20
|
-
# :nodoc:
|
21
|
-
VERSION = '2.0.0'
|
22
|
-
|
23
20
|
attr_accessor :routes
|
24
21
|
|
25
22
|
def initialize(routes)
|
26
23
|
@routes = routes
|
27
24
|
end
|
28
25
|
|
26
|
+
def eager_load!
|
27
|
+
# Eagerly trigger the simulator's initialization so it doesn't happen during a
|
28
|
+
# request cycle.
|
29
|
+
simulator
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
29
33
|
def serve(req)
|
30
|
-
find_routes(req)
|
34
|
+
find_routes(req) do |match, parameters, route|
|
31
35
|
set_params = req.path_parameters
|
32
36
|
path_info = req.path_info
|
33
37
|
script_name = req.script_name
|
34
38
|
|
35
39
|
unless route.path.anchored
|
36
|
-
req.script_name = (script_name.to_s + match.to_s).chomp(
|
40
|
+
req.script_name = (script_name.to_s + match.to_s).chomp("/")
|
37
41
|
req.path_info = match.post_match
|
38
42
|
req.path_info = "/" + req.path_info unless req.path_info.start_with? "/"
|
39
43
|
end
|
40
44
|
|
41
|
-
|
45
|
+
tmp_params = set_params.merge route.defaults
|
46
|
+
parameters.each_pair { |key, val|
|
47
|
+
tmp_params[key] = val.force_encoding(::Encoding::UTF_8)
|
48
|
+
}
|
49
|
+
|
50
|
+
req.path_parameters = tmp_params
|
51
|
+
req.route_uri_pattern = route.path.spec.to_s
|
42
52
|
|
43
|
-
|
53
|
+
_, headers, _ = response = route.app.serve(req)
|
44
54
|
|
45
|
-
if
|
55
|
+
if "pass" == headers[Constants::X_CASCADE]
|
46
56
|
req.script_name = script_name
|
47
57
|
req.path_info = path_info
|
48
58
|
req.path_parameters = set_params
|
49
59
|
next
|
50
60
|
end
|
51
61
|
|
52
|
-
return
|
62
|
+
return response
|
53
63
|
end
|
54
64
|
|
55
|
-
|
65
|
+
[404, { Constants::X_CASCADE => "pass" }, ["Not Found"]]
|
56
66
|
end
|
57
67
|
|
58
68
|
def recognize(rails_req)
|
59
|
-
find_routes(rails_req)
|
69
|
+
find_routes(rails_req) do |match, parameters, route|
|
60
70
|
unless route.path.anchored
|
61
71
|
rails_req.script_name = match.to_s
|
62
|
-
rails_req.path_info = match.post_match
|
72
|
+
rails_req.path_info = match.post_match
|
73
|
+
rails_req.path_info = "/" + rails_req.path_info unless rails_req.path_info.start_with? "/"
|
63
74
|
end
|
64
75
|
|
76
|
+
parameters = route.defaults.merge parameters
|
65
77
|
yield(route, parameters)
|
66
78
|
end
|
67
79
|
end
|
68
80
|
|
69
81
|
def visualizer
|
70
82
|
tt = GTG::Builder.new(ast).transition_table
|
71
|
-
groups = partitioned_routes.first.map(&:ast).group_by
|
72
|
-
asts = groups.values.map
|
83
|
+
groups = partitioned_routes.first.map(&:ast).group_by(&:to_s)
|
84
|
+
asts = groups.values.map(&:first)
|
73
85
|
tt.visualizer(asts)
|
74
86
|
end
|
75
87
|
|
76
88
|
private
|
77
|
-
|
78
89
|
def partitioned_routes
|
79
|
-
routes.
|
90
|
+
routes.partition { |r|
|
91
|
+
r.path.anchored && r.path.requirements_anchored?
|
92
|
+
}
|
80
93
|
end
|
81
94
|
|
82
95
|
def ast
|
@@ -88,7 +101,7 @@ module ActionDispatch
|
|
88
101
|
end
|
89
102
|
|
90
103
|
def custom_routes
|
91
|
-
|
104
|
+
routes.custom_routes
|
92
105
|
end
|
93
106
|
|
94
107
|
def filter_routes(path)
|
@@ -96,49 +109,43 @@ module ActionDispatch
|
|
96
109
|
simulator.memos(path) { [] }
|
97
110
|
end
|
98
111
|
|
99
|
-
def find_routes
|
100
|
-
|
101
|
-
|
112
|
+
def find_routes(req)
|
113
|
+
path_info = req.path_info
|
114
|
+
routes = filter_routes(path_info).concat custom_routes.find_all { |r|
|
115
|
+
r.path.match?(path_info)
|
102
116
|
}
|
103
117
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
118
|
+
if req.head?
|
119
|
+
routes = match_head_routes(routes, req)
|
120
|
+
else
|
121
|
+
routes.select! { |r| r.matches?(req) }
|
122
|
+
end
|
110
123
|
|
111
124
|
routes.sort_by!(&:precedence)
|
112
125
|
|
113
|
-
routes.
|
114
|
-
match_data
|
115
|
-
path_parameters =
|
116
|
-
match_data.names.
|
126
|
+
routes.each { |r|
|
127
|
+
match_data = r.path.match(path_info)
|
128
|
+
path_parameters = {}
|
129
|
+
match_data.names.each_with_index { |name, i|
|
130
|
+
val = match_data[i + 1]
|
117
131
|
path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
|
118
132
|
}
|
119
|
-
[match_data, path_parameters, r]
|
133
|
+
yield [match_data, path_parameters, r]
|
120
134
|
}
|
121
135
|
end
|
122
136
|
|
123
137
|
def match_head_routes(routes, req)
|
124
|
-
|
125
|
-
head_routes
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
end
|
134
|
-
else
|
135
|
-
head_routes
|
138
|
+
head_routes = routes.select { |r| r.requires_matching_verb? && r.matches?(req) }
|
139
|
+
return head_routes unless head_routes.empty?
|
140
|
+
|
141
|
+
begin
|
142
|
+
req.request_method = "GET"
|
143
|
+
routes.select! { |r| r.matches?(req) }
|
144
|
+
routes
|
145
|
+
ensure
|
146
|
+
req.request_method = "HEAD"
|
136
147
|
end
|
137
148
|
end
|
138
|
-
|
139
|
-
def match_routes(routes, req)
|
140
|
-
routes.select { |r| r.matches?(req) }
|
141
|
-
end
|
142
149
|
end
|
143
150
|
end
|
144
151
|
end
|
@@ -1,17 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
4
|
+
|
1
5
|
module ActionDispatch
|
2
6
|
module Journey # :nodoc:
|
3
|
-
# The Routing table. Contains all routes for a system. Routes can be
|
4
|
-
#
|
7
|
+
# The Routing table. Contains all routes for a system. Routes can be added to
|
8
|
+
# the table by calling Routes#add_route.
|
5
9
|
class Routes # :nodoc:
|
6
10
|
include Enumerable
|
7
11
|
|
8
|
-
attr_reader :routes, :
|
12
|
+
attr_reader :routes, :custom_routes, :anchored_routes
|
9
13
|
|
10
|
-
def initialize
|
11
|
-
@routes =
|
12
|
-
@named_routes = {}
|
14
|
+
def initialize(routes = [])
|
15
|
+
@routes = routes
|
13
16
|
@ast = nil
|
14
|
-
@
|
17
|
+
@anchored_routes = []
|
18
|
+
@custom_routes = []
|
15
19
|
@simulator = nil
|
16
20
|
end
|
17
21
|
|
@@ -34,19 +38,22 @@ module ActionDispatch
|
|
34
38
|
|
35
39
|
def clear
|
36
40
|
routes.clear
|
37
|
-
|
41
|
+
anchored_routes.clear
|
42
|
+
custom_routes.clear
|
38
43
|
end
|
39
44
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
45
|
+
def partition_route(route)
|
46
|
+
if route.path.anchored && route.path.requirements_anchored?
|
47
|
+
anchored_routes << route
|
48
|
+
else
|
49
|
+
custom_routes << route
|
43
50
|
end
|
44
51
|
end
|
45
52
|
|
46
53
|
def ast
|
47
54
|
@ast ||= begin
|
48
|
-
|
49
|
-
Nodes::Or.new(
|
55
|
+
nodes = anchored_routes.map(&:ast)
|
56
|
+
Nodes::Or.new(nodes)
|
50
57
|
end
|
51
58
|
end
|
52
59
|
|
@@ -57,22 +64,17 @@ module ActionDispatch
|
|
57
64
|
end
|
58
65
|
end
|
59
66
|
|
60
|
-
|
61
|
-
|
62
|
-
route = Route.new(name, app, path, conditions, defaults)
|
63
|
-
|
64
|
-
route.precedence = routes.length
|
67
|
+
def add_route(name, mapping)
|
68
|
+
route = mapping.make_route name, routes.length
|
65
69
|
routes << route
|
66
|
-
|
70
|
+
partition_route(route)
|
67
71
|
clear_cache!
|
68
72
|
route
|
69
73
|
end
|
70
74
|
|
71
75
|
private
|
72
|
-
|
73
76
|
def clear_cache!
|
74
77
|
@ast = nil
|
75
|
-
@partitioned_routes = nil
|
76
78
|
@simulator = nil
|
77
79
|
end
|
78
80
|
end
|
@@ -1,4 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
4
|
+
|
5
|
+
require "strscan"
|
2
6
|
|
3
7
|
module ActionDispatch
|
4
8
|
module Journey # :nodoc:
|
@@ -31,28 +35,35 @@ module ActionDispatch
|
|
31
35
|
end
|
32
36
|
|
33
37
|
private
|
38
|
+
# takes advantage of String @- deduping capabilities in Ruby 2.5 upwards see:
|
39
|
+
# https://bugs.ruby-lang.org/issues/13077
|
40
|
+
def dedup_scan(regex)
|
41
|
+
r = @ss.scan(regex)
|
42
|
+
r ? -r : nil
|
43
|
+
end
|
34
44
|
|
35
45
|
def scan
|
36
46
|
case
|
37
47
|
# /
|
38
|
-
when
|
39
|
-
[:SLASH,
|
40
|
-
when
|
41
|
-
[:
|
42
|
-
when
|
43
|
-
[:
|
44
|
-
when
|
45
|
-
[:
|
46
|
-
when
|
47
|
-
[:
|
48
|
-
when text =
|
49
|
-
[:DOT, text]
|
50
|
-
when text = @ss.scan(/(?<!\\):\w+/)
|
48
|
+
when @ss.skip(/\//)
|
49
|
+
[:SLASH, "/"]
|
50
|
+
when @ss.skip(/\(/)
|
51
|
+
[:LPAREN, "("]
|
52
|
+
when @ss.skip(/\)/)
|
53
|
+
[:RPAREN, ")"]
|
54
|
+
when @ss.skip(/\|/)
|
55
|
+
[:OR, "|"]
|
56
|
+
when @ss.skip(/\./)
|
57
|
+
[:DOT, "."]
|
58
|
+
when text = dedup_scan(/:\w+/)
|
51
59
|
[:SYMBOL, text]
|
52
|
-
when text =
|
53
|
-
[:
|
60
|
+
when text = dedup_scan(/\*\w+/)
|
61
|
+
[:STAR, text]
|
62
|
+
when text = @ss.scan(/(?:[\w%\-~!$&'*+,;=@]|\\[:()])+/)
|
63
|
+
text.tr! "\\", ""
|
64
|
+
[:LITERAL, -text]
|
54
65
|
# any char
|
55
|
-
when text =
|
66
|
+
when text = dedup_scan(/./)
|
56
67
|
[:LITERAL, text]
|
57
68
|
end
|
58
69
|
end
|
@@ -1,12 +1,15 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
2
4
|
|
3
5
|
module ActionDispatch
|
4
|
-
|
6
|
+
# :stopdoc:
|
7
|
+
module Journey
|
5
8
|
class Format
|
6
9
|
ESCAPE_PATH = ->(value) { Router::Utils.escape_path(value) }
|
7
10
|
ESCAPE_SEGMENT = ->(value) { Router::Utils.escape_segment(value) }
|
8
11
|
|
9
|
-
|
12
|
+
Parameter = Struct.new(:name, :escaper) do
|
10
13
|
def escape(value); escaper.call value; end
|
11
14
|
end
|
12
15
|
|
@@ -23,7 +26,7 @@ module ActionDispatch
|
|
23
26
|
@children = []
|
24
27
|
@parameters = []
|
25
28
|
|
26
|
-
parts.each_with_index do |object,i|
|
29
|
+
parts.each_with_index do |object, i|
|
27
30
|
case object
|
28
31
|
when Journey::Format
|
29
32
|
@children << i
|
@@ -39,7 +42,7 @@ module ActionDispatch
|
|
39
42
|
@parameters.each do |index|
|
40
43
|
param = parts[index]
|
41
44
|
value = hash[param.name]
|
42
|
-
return
|
45
|
+
return "" if value.nil?
|
43
46
|
parts[index] = param.escape value
|
44
47
|
end
|
45
48
|
|
@@ -58,8 +61,7 @@ module ActionDispatch
|
|
58
61
|
end
|
59
62
|
|
60
63
|
private
|
61
|
-
|
62
|
-
def visit node
|
64
|
+
def visit(node)
|
63
65
|
send(DISPATCH_CACHE[node.type], node)
|
64
66
|
end
|
65
67
|
|
@@ -92,6 +94,45 @@ module ActionDispatch
|
|
92
94
|
end
|
93
95
|
end
|
94
96
|
|
97
|
+
class FunctionalVisitor # :nodoc:
|
98
|
+
DISPATCH_CACHE = {}
|
99
|
+
|
100
|
+
def accept(node, seed)
|
101
|
+
visit(node, seed)
|
102
|
+
end
|
103
|
+
|
104
|
+
def visit(node, seed)
|
105
|
+
send(DISPATCH_CACHE[node.type], node, seed)
|
106
|
+
end
|
107
|
+
|
108
|
+
def binary(node, seed)
|
109
|
+
visit(node.right, visit(node.left, seed))
|
110
|
+
end
|
111
|
+
def visit_CAT(n, seed); binary(n, seed); end
|
112
|
+
|
113
|
+
def nary(node, seed)
|
114
|
+
node.children.inject(seed) { |s, c| visit(c, s) }
|
115
|
+
end
|
116
|
+
def visit_OR(n, seed); nary(n, seed); end
|
117
|
+
|
118
|
+
def unary(node, seed)
|
119
|
+
visit(node.left, seed)
|
120
|
+
end
|
121
|
+
def visit_GROUP(n, seed); unary(n, seed); end
|
122
|
+
def visit_STAR(n, seed); unary(n, seed); end
|
123
|
+
|
124
|
+
def terminal(node, seed); seed; end
|
125
|
+
def visit_LITERAL(n, seed); terminal(n, seed); end
|
126
|
+
def visit_SYMBOL(n, seed); terminal(n, seed); end
|
127
|
+
def visit_SLASH(n, seed); terminal(n, seed); end
|
128
|
+
def visit_DOT(n, seed); terminal(n, seed); end
|
129
|
+
|
130
|
+
instance_methods(false).each do |pim|
|
131
|
+
next unless pim =~ /^visit_(.*)$/
|
132
|
+
DISPATCH_CACHE[$1.to_sym] = pim
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
95
136
|
class FormatBuilder < Visitor # :nodoc:
|
96
137
|
def accept(node); Journey::Format.new(super); end
|
97
138
|
def terminal(node); [node.left]; end
|
@@ -116,106 +157,111 @@ module ActionDispatch
|
|
116
157
|
end
|
117
158
|
end
|
118
159
|
|
119
|
-
# Loop through the requirements AST
|
120
|
-
class Each <
|
121
|
-
|
122
|
-
|
123
|
-
def initialize(block)
|
124
|
-
@block = block
|
125
|
-
end
|
126
|
-
|
127
|
-
def visit(node)
|
160
|
+
# Loop through the requirements AST.
|
161
|
+
class Each < FunctionalVisitor # :nodoc:
|
162
|
+
def visit(node, block)
|
128
163
|
block.call(node)
|
129
164
|
super
|
130
165
|
end
|
166
|
+
|
167
|
+
INSTANCE = new
|
131
168
|
end
|
132
169
|
|
133
|
-
class String <
|
170
|
+
class String < FunctionalVisitor # :nodoc:
|
134
171
|
private
|
172
|
+
def binary(node, seed)
|
173
|
+
visit(node.right, visit(node.left, seed))
|
174
|
+
end
|
135
175
|
|
136
|
-
|
137
|
-
|
138
|
-
|
176
|
+
def nary(node, seed)
|
177
|
+
last_child = node.children.last
|
178
|
+
node.children.inject(seed) { |s, c|
|
179
|
+
string = visit(c, s)
|
180
|
+
string << "|" unless last_child == c
|
181
|
+
string
|
182
|
+
}
|
183
|
+
end
|
139
184
|
|
140
|
-
|
141
|
-
|
142
|
-
|
185
|
+
def terminal(node, seed)
|
186
|
+
seed + node.left
|
187
|
+
end
|
143
188
|
|
144
|
-
|
145
|
-
|
146
|
-
|
189
|
+
def visit_GROUP(node, seed)
|
190
|
+
visit(node.left, seed.dup << "(") << ")"
|
191
|
+
end
|
147
192
|
|
148
|
-
|
149
|
-
"(#{visit(node.left)})"
|
150
|
-
end
|
193
|
+
INSTANCE = new
|
151
194
|
end
|
152
195
|
|
153
|
-
class Dot <
|
196
|
+
class Dot < FunctionalVisitor # :nodoc:
|
154
197
|
def initialize
|
155
198
|
@nodes = []
|
156
199
|
@edges = []
|
157
200
|
end
|
158
201
|
|
159
|
-
def accept(node)
|
202
|
+
def accept(node, seed = [[], []])
|
160
203
|
super
|
204
|
+
nodes, edges = seed
|
161
205
|
<<-eodot
|
162
206
|
digraph parse_tree {
|
163
207
|
size="8,5"
|
164
208
|
node [shape = none];
|
165
209
|
edge [dir = none];
|
166
|
-
#{
|
167
|
-
#{
|
210
|
+
#{nodes.join "\n"}
|
211
|
+
#{edges.join("\n")}
|
168
212
|
}
|
169
213
|
eodot
|
170
214
|
end
|
171
215
|
|
172
216
|
private
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
end
|
217
|
+
def binary(node, seed)
|
218
|
+
seed.last.concat node.children.map { |c|
|
219
|
+
"#{node.object_id} -> #{c.object_id};"
|
220
|
+
}
|
178
221
|
super
|
179
222
|
end
|
180
223
|
|
181
|
-
def nary(node)
|
182
|
-
node.children.
|
183
|
-
|
184
|
-
|
224
|
+
def nary(node, seed)
|
225
|
+
seed.last.concat node.children.map { |c|
|
226
|
+
"#{node.object_id} -> #{c.object_id};"
|
227
|
+
}
|
185
228
|
super
|
186
229
|
end
|
187
230
|
|
188
|
-
def unary(node)
|
189
|
-
|
231
|
+
def unary(node, seed)
|
232
|
+
seed.last << "#{node.object_id} -> #{node.left.object_id};"
|
190
233
|
super
|
191
234
|
end
|
192
235
|
|
193
|
-
def visit_GROUP(node)
|
194
|
-
|
236
|
+
def visit_GROUP(node, seed)
|
237
|
+
seed.first << "#{node.object_id} [label=\"()\"];"
|
195
238
|
super
|
196
239
|
end
|
197
240
|
|
198
|
-
def visit_CAT(node)
|
199
|
-
|
241
|
+
def visit_CAT(node, seed)
|
242
|
+
seed.first << "#{node.object_id} [label=\"○\"];"
|
200
243
|
super
|
201
244
|
end
|
202
245
|
|
203
|
-
def visit_STAR(node)
|
204
|
-
|
246
|
+
def visit_STAR(node, seed)
|
247
|
+
seed.first << "#{node.object_id} [label=\"*\"];"
|
205
248
|
super
|
206
249
|
end
|
207
250
|
|
208
|
-
def visit_OR(node)
|
209
|
-
|
251
|
+
def visit_OR(node, seed)
|
252
|
+
seed.first << "#{node.object_id} [label=\"|\"];"
|
210
253
|
super
|
211
254
|
end
|
212
255
|
|
213
|
-
def terminal(node)
|
256
|
+
def terminal(node, seed)
|
214
257
|
value = node.left
|
215
258
|
|
216
|
-
|
259
|
+
seed.first << "#{node.object_id} [label=\"#{value}\"];"
|
260
|
+
seed
|
217
261
|
end
|
262
|
+
INSTANCE = new
|
218
263
|
end
|
219
264
|
end
|
220
265
|
end
|
266
|
+
# :startdoc:
|
221
267
|
end
|