actionpack 6.0.3 → 6.1.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 +4 -4
- data/CHANGELOG.md +246 -217
- data/MIT-LICENSE +1 -1
- data/lib/abstract_controller.rb +1 -0
- data/lib/abstract_controller/base.rb +35 -2
- data/lib/abstract_controller/callbacks.rb +2 -2
- data/lib/abstract_controller/helpers.rb +105 -90
- data/lib/abstract_controller/rendering.rb +9 -9
- data/lib/abstract_controller/translation.rb +8 -2
- data/lib/action_controller.rb +2 -3
- data/lib/action_controller/api.rb +2 -2
- data/lib/action_controller/base.rb +4 -2
- data/lib/action_controller/caching.rb +0 -1
- data/lib/action_controller/log_subscriber.rb +3 -3
- data/lib/action_controller/metal.rb +2 -2
- data/lib/action_controller/metal/conditional_get.rb +10 -2
- data/lib/action_controller/metal/content_security_policy.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +1 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +2 -4
- data/lib/action_controller/metal/exceptions.rb +33 -0
- data/lib/action_controller/metal/feature_policy.rb +46 -0
- data/lib/action_controller/metal/head.rb +7 -4
- data/lib/action_controller/metal/helpers.rb +11 -1
- data/lib/action_controller/metal/http_authentication.rb +4 -2
- data/lib/action_controller/metal/implicit_render.rb +1 -1
- data/lib/action_controller/metal/instrumentation.rb +11 -9
- data/lib/action_controller/metal/live.rb +1 -1
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +6 -2
- data/lib/action_controller/metal/parameter_encoding.rb +35 -4
- data/lib/action_controller/metal/params_wrapper.rb +14 -8
- data/lib/action_controller/metal/redirecting.rb +1 -1
- data/lib/action_controller/metal/rendering.rb +6 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +74 -30
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/strong_parameters.rb +107 -15
- data/lib/action_controller/renderer.rb +24 -13
- data/lib/action_controller/test_case.rb +62 -56
- data/lib/action_dispatch.rb +3 -2
- data/lib/action_dispatch/http/cache.rb +12 -10
- data/lib/action_dispatch/http/content_disposition.rb +2 -2
- data/lib/action_dispatch/http/content_security_policy.rb +5 -1
- data/lib/action_dispatch/http/feature_policy.rb +168 -0
- data/lib/action_dispatch/http/filter_parameters.rb +1 -1
- data/lib/action_dispatch/http/filter_redirect.rb +1 -1
- data/lib/action_dispatch/http/headers.rb +3 -2
- data/lib/action_dispatch/http/mime_negotiation.rb +20 -8
- data/lib/action_dispatch/http/mime_type.rb +28 -15
- data/lib/action_dispatch/http/parameters.rb +1 -19
- data/lib/action_dispatch/http/request.rb +26 -8
- data/lib/action_dispatch/http/response.rb +17 -16
- data/lib/action_dispatch/http/url.rb +3 -2
- data/lib/action_dispatch/journey.rb +0 -2
- data/lib/action_dispatch/journey/formatter.rb +53 -28
- data/lib/action_dispatch/journey/gtg/builder.rb +22 -36
- data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -4
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
- data/lib/action_dispatch/journey/nodes/node.rb +4 -3
- data/lib/action_dispatch/journey/parser.rb +13 -13
- data/lib/action_dispatch/journey/parser.y +1 -1
- data/lib/action_dispatch/journey/path/pattern.rb +13 -18
- data/lib/action_dispatch/journey/route.rb +7 -18
- data/lib/action_dispatch/journey/router.rb +26 -30
- data/lib/action_dispatch/journey/router/utils.rb +6 -4
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +9 -2
- data/lib/action_dispatch/middleware/cookies.rb +74 -33
- data/lib/action_dispatch/middleware/debug_exceptions.rb +10 -17
- data/lib/action_dispatch/middleware/debug_view.rb +1 -1
- data/lib/action_dispatch/middleware/exception_wrapper.rb +29 -17
- data/lib/action_dispatch/middleware/host_authorization.rb +23 -3
- data/lib/action_dispatch/middleware/public_exceptions.rb +1 -1
- data/lib/action_dispatch/middleware/remote_ip.rb +5 -4
- data/lib/action_dispatch/middleware/request_id.rb +4 -5
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -2
- data/lib/action_dispatch/middleware/session/cookie_store.rb +2 -2
- data/lib/action_dispatch/middleware/ssl.rb +9 -6
- data/lib/action_dispatch/middleware/stack.rb +18 -0
- data/lib/action_dispatch/middleware/static.rb +154 -93
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +18 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +2 -5
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +88 -8
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +12 -1
- data/lib/action_dispatch/railtie.rb +3 -2
- data/lib/action_dispatch/request/session.rb +2 -8
- data/lib/action_dispatch/request/utils.rb +26 -2
- data/lib/action_dispatch/routing/inspector.rb +8 -7
- data/lib/action_dispatch/routing/mapper.rb +102 -71
- data/lib/action_dispatch/routing/polymorphic_routes.rb +12 -11
- data/lib/action_dispatch/routing/redirection.rb +3 -3
- data/lib/action_dispatch/routing/route_set.rb +49 -41
- data/lib/action_dispatch/routing/url_for.rb +1 -0
- data/lib/action_dispatch/system_test_case.rb +29 -24
- data/lib/action_dispatch/system_testing/browser.rb +33 -27
- data/lib/action_dispatch/system_testing/driver.rb +6 -7
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +47 -6
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +4 -7
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +2 -4
- data/lib/action_dispatch/testing/assertions/routing.rb +5 -5
- data/lib/action_dispatch/testing/integration.rb +38 -27
- data/lib/action_dispatch/testing/test_process.rb +29 -4
- data/lib/action_dispatch/testing/test_request.rb +3 -3
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/gem_version.rb +3 -3
- metadata +20 -21
- data/lib/action_controller/metal/force_ssl.rb +0 -58
- data/lib/action_dispatch/http/parameter_filter.rb +0 -12
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -119
@@ -15,12 +15,53 @@ module ActionDispatch
|
|
15
15
|
@cache = nil
|
16
16
|
end
|
17
17
|
|
18
|
-
|
18
|
+
class RouteWithParams
|
19
|
+
attr_reader :params
|
20
|
+
|
21
|
+
def initialize(route, parameterized_parts, params)
|
22
|
+
@route = route
|
23
|
+
@parameterized_parts = parameterized_parts
|
24
|
+
@params = params
|
25
|
+
end
|
26
|
+
|
27
|
+
def path(_)
|
28
|
+
@route.format(@parameterized_parts)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class MissingRoute
|
33
|
+
attr_reader :routes, :name, :constraints, :missing_keys, :unmatched_keys
|
34
|
+
|
35
|
+
def initialize(constraints, missing_keys, unmatched_keys, routes, name)
|
36
|
+
@constraints = constraints
|
37
|
+
@missing_keys = missing_keys
|
38
|
+
@unmatched_keys = unmatched_keys
|
39
|
+
@routes = routes
|
40
|
+
@name = name
|
41
|
+
end
|
42
|
+
|
43
|
+
def path(method_name)
|
44
|
+
raise ActionController::UrlGenerationError.new(message, routes, name, method_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def params
|
48
|
+
path("unknown")
|
49
|
+
end
|
50
|
+
|
51
|
+
def message
|
52
|
+
message = +"No route matches #{Hash[constraints.sort_by { |k, v| k.to_s }].inspect}"
|
53
|
+
message << ", missing required keys: #{missing_keys.sort.inspect}" if missing_keys && !missing_keys.empty?
|
54
|
+
message << ", possible unmatched constraints: #{unmatched_keys.sort.inspect}" if unmatched_keys && !unmatched_keys.empty?
|
55
|
+
message
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def generate(name, options, path_parameters)
|
19
60
|
constraints = path_parameters.merge(options)
|
20
61
|
missing_keys = nil
|
21
62
|
|
22
63
|
match_route(name, constraints) do |route|
|
23
|
-
parameterized_parts = extract_parameterized_parts(route, options, path_parameters
|
64
|
+
parameterized_parts = extract_parameterized_parts(route, options, path_parameters)
|
24
65
|
|
25
66
|
# Skip this route unless a name has been provided or it is a
|
26
67
|
# standard Rails route since we can't determine whether an options
|
@@ -44,17 +85,13 @@ module ActionDispatch
|
|
44
85
|
parameterized_parts.delete(key)
|
45
86
|
end
|
46
87
|
|
47
|
-
return
|
88
|
+
return RouteWithParams.new(route, parameterized_parts, params)
|
48
89
|
end
|
49
90
|
|
50
91
|
unmatched_keys = (missing_keys || []) & constraints.keys
|
51
92
|
missing_keys = (missing_keys || []) - unmatched_keys
|
52
93
|
|
53
|
-
|
54
|
-
message << ", missing required keys: #{missing_keys.sort.inspect}" if missing_keys && !missing_keys.empty?
|
55
|
-
message << ", possible unmatched constraints: #{unmatched_keys.sort.inspect}" if unmatched_keys && !unmatched_keys.empty?
|
56
|
-
|
57
|
-
raise ActionController::UrlGenerationError, message
|
94
|
+
MissingRoute.new(constraints, missing_keys, unmatched_keys, routes, name)
|
58
95
|
end
|
59
96
|
|
60
97
|
def clear
|
@@ -62,7 +99,7 @@ module ActionDispatch
|
|
62
99
|
end
|
63
100
|
|
64
101
|
private
|
65
|
-
def extract_parameterized_parts(route, options, recall
|
102
|
+
def extract_parameterized_parts(route, options, recall)
|
66
103
|
parameterized_parts = recall.merge(options)
|
67
104
|
|
68
105
|
keys_to_keep = route.parts.reverse_each.drop_while { |part|
|
@@ -73,9 +110,11 @@ module ActionDispatch
|
|
73
110
|
!keys_to_keep.include?(bad_key)
|
74
111
|
end
|
75
112
|
|
76
|
-
|
77
|
-
|
78
|
-
parameterized_parts[k] =
|
113
|
+
parameterized_parts.each do |k, v|
|
114
|
+
if k == :controller
|
115
|
+
parameterized_parts[k] = v
|
116
|
+
else
|
117
|
+
parameterized_parts[k] = v.to_param
|
79
118
|
end
|
80
119
|
end
|
81
120
|
|
@@ -125,19 +164,10 @@ module ActionDispatch
|
|
125
164
|
routes
|
126
165
|
end
|
127
166
|
|
128
|
-
module RegexCaseComparator
|
129
|
-
DEFAULT_INPUT = /[-_.a-zA-Z0-9]+\/[-_.a-zA-Z0-9]+/
|
130
|
-
DEFAULT_REGEX = /\A#{DEFAULT_INPUT}\Z/
|
131
|
-
|
132
|
-
def self.===(regex)
|
133
|
-
DEFAULT_INPUT == regex
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
167
|
# Returns an array populated with missing keys if any are present.
|
138
168
|
def missing_keys(route, parts)
|
139
169
|
missing_keys = nil
|
140
|
-
tests = route.path.
|
170
|
+
tests = route.path.requirements_for_missing_keys_check
|
141
171
|
route.required_parts.each { |key|
|
142
172
|
case tests[key]
|
143
173
|
when nil
|
@@ -145,13 +175,8 @@ module ActionDispatch
|
|
145
175
|
missing_keys ||= []
|
146
176
|
missing_keys << key
|
147
177
|
end
|
148
|
-
when RegexCaseComparator
|
149
|
-
unless RegexCaseComparator::DEFAULT_REGEX === parts[key]
|
150
|
-
missing_keys ||= []
|
151
|
-
missing_keys << key
|
152
|
-
end
|
153
178
|
else
|
154
|
-
unless
|
179
|
+
unless tests[key].match?(parts[key])
|
155
180
|
missing_keys ||= []
|
156
181
|
missing_keys << key
|
157
182
|
end
|
@@ -13,45 +13,44 @@ module ActionDispatch
|
|
13
13
|
def initialize(root)
|
14
14
|
@root = root
|
15
15
|
@ast = Nodes::Cat.new root, DUMMY
|
16
|
-
@followpos =
|
16
|
+
@followpos = build_followpos
|
17
17
|
end
|
18
18
|
|
19
19
|
def transition_table
|
20
20
|
dtrans = TransitionTable.new
|
21
|
-
marked = {}
|
22
|
-
state_id = Hash.new { |h, k| h[k] = h.length }
|
21
|
+
marked = {}.compare_by_identity
|
22
|
+
state_id = Hash.new { |h, k| h[k] = h.length }.compare_by_identity
|
23
|
+
dstates = [firstpos(root)]
|
23
24
|
|
24
|
-
start = firstpos(root)
|
25
|
-
dstates = [start]
|
26
25
|
until dstates.empty?
|
27
26
|
s = dstates.shift
|
28
27
|
next if marked[s]
|
29
28
|
marked[s] = true # mark s
|
30
29
|
|
31
30
|
s.group_by { |state| symbol(state) }.each do |sym, ps|
|
32
|
-
u = ps.flat_map { |l| followpos
|
31
|
+
u = ps.flat_map { |l| @followpos[l] }
|
33
32
|
next if u.empty?
|
34
33
|
|
35
|
-
|
36
|
-
from = state_id[s]
|
37
|
-
to = state_id[Object.new]
|
38
|
-
dtrans[from, to] = sym
|
34
|
+
from = state_id[s]
|
39
35
|
|
36
|
+
if u.all? { |pos| pos == DUMMY }
|
37
|
+
to = state_id[Object.new]
|
38
|
+
dtrans[from, to] = sym
|
40
39
|
dtrans.add_accepting(to)
|
40
|
+
|
41
41
|
ps.each { |state| dtrans.add_memo(to, state.memo) }
|
42
42
|
else
|
43
|
-
|
43
|
+
to = state_id[u]
|
44
|
+
dtrans[from, to] = sym
|
44
45
|
|
45
46
|
if u.include?(DUMMY)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
dtrans.add_memo(to, accepting_state.memo)
|
52
|
-
}
|
47
|
+
ps.each do |state|
|
48
|
+
if @followpos[state].include?(DUMMY)
|
49
|
+
dtrans.add_memo(to, state.memo)
|
50
|
+
end
|
51
|
+
end
|
53
52
|
|
54
|
-
dtrans.add_accepting(
|
53
|
+
dtrans.add_accepting(to)
|
55
54
|
end
|
56
55
|
end
|
57
56
|
|
@@ -92,7 +91,7 @@ module ActionDispatch
|
|
92
91
|
firstpos(node.left)
|
93
92
|
end
|
94
93
|
when Nodes::Or
|
95
|
-
node.children.flat_map { |c| firstpos(c) }.uniq
|
94
|
+
node.children.flat_map { |c| firstpos(c) }.tap(&:uniq!)
|
96
95
|
when Nodes::Unary
|
97
96
|
firstpos(node.left)
|
98
97
|
when Nodes::Terminal
|
@@ -107,7 +106,7 @@ module ActionDispatch
|
|
107
106
|
when Nodes::Star
|
108
107
|
firstpos(node.left)
|
109
108
|
when Nodes::Or
|
110
|
-
node.children.flat_map { |c| lastpos(c) }.uniq
|
109
|
+
node.children.flat_map { |c| lastpos(c) }.tap(&:uniq!)
|
111
110
|
when Nodes::Cat
|
112
111
|
if nullable?(node.right)
|
113
112
|
lastpos(node.left) | lastpos(node.right)
|
@@ -123,17 +122,9 @@ module ActionDispatch
|
|
123
122
|
end
|
124
123
|
end
|
125
124
|
|
126
|
-
def followpos(node)
|
127
|
-
followpos_table[node]
|
128
|
-
end
|
129
|
-
|
130
125
|
private
|
131
|
-
def followpos_table
|
132
|
-
@followpos ||= build_followpos
|
133
|
-
end
|
134
|
-
|
135
126
|
def build_followpos
|
136
|
-
table = Hash.new { |h, k| h[k] = [] }
|
127
|
+
table = Hash.new { |h, k| h[k] = [] }.compare_by_identity
|
137
128
|
@ast.each do |n|
|
138
129
|
case n
|
139
130
|
when Nodes::Cat
|
@@ -150,12 +141,7 @@ module ActionDispatch
|
|
150
141
|
end
|
151
142
|
|
152
143
|
def symbol(edge)
|
153
|
-
|
154
|
-
when Journey::Nodes::Symbol
|
155
|
-
edge.regexp
|
156
|
-
else
|
157
|
-
edge.left
|
158
|
-
end
|
144
|
+
edge.symbol? ? edge.regexp : edge.left
|
159
145
|
end
|
160
146
|
end
|
161
147
|
end
|
@@ -14,6 +14,8 @@ module ActionDispatch
|
|
14
14
|
end
|
15
15
|
|
16
16
|
class Simulator # :nodoc:
|
17
|
+
INITIAL_STATE = [0].freeze
|
18
|
+
|
17
19
|
attr_reader :tt
|
18
20
|
|
19
21
|
def initialize(transition_table)
|
@@ -22,18 +24,17 @@ module ActionDispatch
|
|
22
24
|
|
23
25
|
def memos(string)
|
24
26
|
input = StringScanner.new(string)
|
25
|
-
state =
|
27
|
+
state = INITIAL_STATE
|
28
|
+
|
26
29
|
while sym = input.scan(%r([/.?]|[^/.?]+))
|
27
30
|
state = tt.move(state, sym)
|
28
31
|
end
|
29
32
|
|
30
|
-
acceptance_states = state.
|
31
|
-
tt.accepting?
|
32
|
-
|
33
|
-
|
34
|
-
return yield if acceptance_states.empty?
|
33
|
+
acceptance_states = state.each_with_object([]) do |s, memos|
|
34
|
+
memos.concat(tt.memo(s)) if tt.accepting?(s)
|
35
|
+
end
|
35
36
|
|
36
|
-
acceptance_states.
|
37
|
+
acceptance_states.empty? ? yield : acceptance_states
|
37
38
|
end
|
38
39
|
end
|
39
40
|
end
|
@@ -45,16 +45,18 @@ module ActionDispatch
|
|
45
45
|
return [] if t.empty?
|
46
46
|
|
47
47
|
regexps = []
|
48
|
+
strings = []
|
48
49
|
|
49
|
-
t.
|
50
|
+
t.each { |s|
|
50
51
|
if states = @regexp_states[s]
|
51
|
-
|
52
|
+
states.each { |re, v| regexps << v if re.match?(a) && !v.nil? }
|
52
53
|
end
|
53
54
|
|
54
55
|
if states = @string_states[s]
|
55
|
-
states[a]
|
56
|
+
strings << states[a] unless states[a].nil?
|
56
57
|
end
|
57
|
-
}
|
58
|
+
}
|
59
|
+
strings.concat regexps
|
58
60
|
end
|
59
61
|
|
60
62
|
def as_json(options = nil)
|
@@ -9,17 +9,6 @@ module ActionDispatch
|
|
9
9
|
" #{from} -> #{to} [label=\"#{sym || 'ε'}\"];"
|
10
10
|
}
|
11
11
|
|
12
|
-
# memo_nodes = memos.values.flatten.map { |n|
|
13
|
-
# label = n
|
14
|
-
# if Journey::Route === n
|
15
|
-
# label = "#{n.verb.source} #{n.path.spec}"
|
16
|
-
# end
|
17
|
-
# " #{n.object_id} [label=\"#{label}\", shape=box];"
|
18
|
-
# }
|
19
|
-
# memo_edges = memos.flat_map { |k, memos|
|
20
|
-
# (memos || []).map { |v| " #{k} -> #{v.object_id};" }
|
21
|
-
# }.uniq
|
22
|
-
|
23
12
|
<<-eodot
|
24
13
|
digraph nfa {
|
25
14
|
rankdir=LR;
|
@@ -79,9 +79,10 @@ module ActionDispatch
|
|
79
79
|
attr_reader :name
|
80
80
|
|
81
81
|
DEFAULT_EXP = /[^\.\/\?]+/
|
82
|
-
|
83
|
-
|
84
|
-
|
82
|
+
GREEDY_EXP = /(.+)/
|
83
|
+
def initialize(left, regexp = DEFAULT_EXP)
|
84
|
+
super(left)
|
85
|
+
@regexp = regexp
|
85
86
|
@name = -left.tr("*:", "")
|
86
87
|
end
|
87
88
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# DO NOT MODIFY!!!!
|
3
|
-
# This file is automatically generated by Racc 1.4.
|
3
|
+
# This file is automatically generated by Racc 1.4.16
|
4
4
|
# from Racc grammar file "".
|
5
5
|
#
|
6
6
|
|
@@ -135,11 +135,11 @@ Racc_debug_parser = false
|
|
135
135
|
# reduce 0 omitted
|
136
136
|
|
137
137
|
def _reduce_1(val, _values)
|
138
|
-
Cat.new(val.first, val.last)
|
138
|
+
Cat.new(val.first, val.last)
|
139
139
|
end
|
140
140
|
|
141
141
|
def _reduce_2(val, _values)
|
142
|
-
val.first
|
142
|
+
val.first
|
143
143
|
end
|
144
144
|
|
145
145
|
# reduce 3 omitted
|
@@ -151,19 +151,19 @@ end
|
|
151
151
|
# reduce 6 omitted
|
152
152
|
|
153
153
|
def _reduce_7(val, _values)
|
154
|
-
Group.new(val[1])
|
154
|
+
Group.new(val[1])
|
155
155
|
end
|
156
156
|
|
157
157
|
def _reduce_8(val, _values)
|
158
|
-
Or.new([val.first, val.last])
|
158
|
+
Or.new([val.first, val.last])
|
159
159
|
end
|
160
160
|
|
161
161
|
def _reduce_9(val, _values)
|
162
|
-
Or.new([val.first, val.last])
|
162
|
+
Or.new([val.first, val.last])
|
163
163
|
end
|
164
164
|
|
165
165
|
def _reduce_10(val, _values)
|
166
|
-
Star.new(Symbol.new(val.last))
|
166
|
+
Star.new(Symbol.new(val.last, Symbol::GREEDY_EXP))
|
167
167
|
end
|
168
168
|
|
169
169
|
# reduce 11 omitted
|
@@ -175,19 +175,19 @@ end
|
|
175
175
|
# reduce 14 omitted
|
176
176
|
|
177
177
|
def _reduce_15(val, _values)
|
178
|
-
Slash.new(val.first)
|
178
|
+
Slash.new(val.first)
|
179
179
|
end
|
180
180
|
|
181
181
|
def _reduce_16(val, _values)
|
182
|
-
Symbol.new(val.first)
|
182
|
+
Symbol.new(val.first)
|
183
183
|
end
|
184
184
|
|
185
185
|
def _reduce_17(val, _values)
|
186
|
-
Literal.new(val.first)
|
186
|
+
Literal.new(val.first)
|
187
187
|
end
|
188
188
|
|
189
189
|
def _reduce_18(val, _values)
|
190
|
-
Dot.new(val.first)
|
190
|
+
Dot.new(val.first)
|
191
191
|
end
|
192
192
|
|
193
193
|
def _reduce_none(val, _values)
|
@@ -195,5 +195,5 @@ def _reduce_none(val, _values)
|
|
195
195
|
end
|
196
196
|
|
197
197
|
end # class Parser
|
198
|
-
|
199
|
-
|
198
|
+
end # module Journey
|
199
|
+
end # module ActionDispatch
|
@@ -6,16 +6,6 @@ module ActionDispatch
|
|
6
6
|
class Pattern # :nodoc:
|
7
7
|
attr_reader :spec, :requirements, :anchored
|
8
8
|
|
9
|
-
def self.from_string(string)
|
10
|
-
build(string, {}, "/.?", true)
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.build(path, requirements, separators, anchored)
|
14
|
-
parser = Journey::Parser.new
|
15
|
-
ast = parser.parse path
|
16
|
-
new ast, requirements, separators, anchored
|
17
|
-
end
|
18
|
-
|
19
9
|
def initialize(ast, requirements, separators, anchored)
|
20
10
|
@spec = ast
|
21
11
|
@requirements = requirements
|
@@ -46,11 +36,6 @@ module ActionDispatch
|
|
46
36
|
node.regexp = re if re
|
47
37
|
end
|
48
38
|
|
49
|
-
@spec.find_all(&:star?).each do |node|
|
50
|
-
node = node.left
|
51
|
-
node.regexp = @requirements[node.to_sym] || /(.+)/
|
52
|
-
end
|
53
|
-
|
54
39
|
@spec
|
55
40
|
end
|
56
41
|
|
@@ -81,7 +66,7 @@ module ActionDispatch
|
|
81
66
|
end
|
82
67
|
|
83
68
|
def visit_CAT(node)
|
84
|
-
|
69
|
+
"#{visit(node.left)}#{visit(node.right)}"
|
85
70
|
end
|
86
71
|
|
87
72
|
def visit_SYMBOL(node)
|
@@ -107,8 +92,8 @@ module ActionDispatch
|
|
107
92
|
end
|
108
93
|
|
109
94
|
def visit_STAR(node)
|
110
|
-
re = @matchers[node.left.to_sym]
|
111
|
-
"(#{re})"
|
95
|
+
re = @matchers[node.left.to_sym]
|
96
|
+
re ? "(#{re})" : "(.+)"
|
112
97
|
end
|
113
98
|
|
114
99
|
def visit_OR(node)
|
@@ -165,6 +150,10 @@ module ActionDispatch
|
|
165
150
|
end
|
166
151
|
alias :=~ :match
|
167
152
|
|
153
|
+
def match?(other)
|
154
|
+
to_regexp.match?(other)
|
155
|
+
end
|
156
|
+
|
168
157
|
def source
|
169
158
|
to_regexp.source
|
170
159
|
end
|
@@ -173,6 +162,12 @@ module ActionDispatch
|
|
173
162
|
@re ||= regexp_visitor.new(@separators, @requirements).accept spec
|
174
163
|
end
|
175
164
|
|
165
|
+
def requirements_for_missing_keys_check
|
166
|
+
@requirements_for_missing_keys_check ||= requirements.transform_values do |regex|
|
167
|
+
/\A#{regex}\Z/
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
176
171
|
private
|
177
172
|
def regexp_visitor
|
178
173
|
@anchored ? AnchoredRegexp : UnanchoredRegexp
|