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,4 @@
|
|
1
1
|
require 'active_support/core_ext/module/attribute_accessors'
|
2
|
-
require 'active_support/core_ext/hash/slice'
|
3
2
|
|
4
3
|
module ActionDispatch
|
5
4
|
module Http
|
@@ -12,10 +11,22 @@ module ActionDispatch
|
|
12
11
|
self.tld_length = 1
|
13
12
|
|
14
13
|
class << self
|
14
|
+
# Returns the domain part of a host given the domain level.
|
15
|
+
#
|
16
|
+
# # Top-level domain example
|
17
|
+
# extract_domain('www.example.com', 1) # => "example.com"
|
18
|
+
# # Second-level domain example
|
19
|
+
# extract_domain('dev.www.example.co.uk', 2) # => "example.co.uk"
|
15
20
|
def extract_domain(host, tld_length)
|
16
21
|
extract_domain_from(host, tld_length) if named_host?(host)
|
17
22
|
end
|
18
23
|
|
24
|
+
# Returns the subdomains of a host as an Array given the domain level.
|
25
|
+
#
|
26
|
+
# # Top-level domain example
|
27
|
+
# extract_subdomains('www.example.com', 1) # => ["www"]
|
28
|
+
# # Second-level domain example
|
29
|
+
# extract_subdomains('dev.www.example.co.uk', 2) # => ["dev", "www"]
|
19
30
|
def extract_subdomains(host, tld_length)
|
20
31
|
if named_host?(host)
|
21
32
|
extract_subdomains_from(host, tld_length)
|
@@ -24,6 +35,12 @@ module ActionDispatch
|
|
24
35
|
end
|
25
36
|
end
|
26
37
|
|
38
|
+
# Returns the subdomains of a host as a String given the domain level.
|
39
|
+
#
|
40
|
+
# # Top-level domain example
|
41
|
+
# extract_subdomain('www.example.com', 1) # => "www"
|
42
|
+
# # Second-level domain example
|
43
|
+
# extract_subdomain('dev.www.example.co.uk', 2) # => "dev.www"
|
27
44
|
def extract_subdomain(host, tld_length)
|
28
45
|
extract_subdomains(host, tld_length).join('.')
|
29
46
|
end
|
@@ -49,7 +66,7 @@ module ActionDispatch
|
|
49
66
|
end
|
50
67
|
|
51
68
|
def path_for(options)
|
52
|
-
path = options[:script_name].to_s.chomp("/")
|
69
|
+
path = options[:script_name].to_s.chomp("/".freeze)
|
53
70
|
path << options[:path] if options.key?(:path)
|
54
71
|
|
55
72
|
add_trailing_slash(path) if options[:trailing_slash]
|
@@ -64,7 +81,8 @@ module ActionDispatch
|
|
64
81
|
def add_params(path, params)
|
65
82
|
params = { params: params } unless params.is_a?(Hash)
|
66
83
|
params.reject! { |_,v| v.to_param.nil? }
|
67
|
-
|
84
|
+
query = params.to_query
|
85
|
+
path << "?#{query}" unless query.empty?
|
68
86
|
end
|
69
87
|
|
70
88
|
def add_anchor(path, anchor)
|
@@ -166,43 +184,97 @@ module ActionDispatch
|
|
166
184
|
end
|
167
185
|
end
|
168
186
|
|
169
|
-
def initialize
|
187
|
+
def initialize
|
170
188
|
super
|
171
189
|
@protocol = nil
|
172
190
|
@port = nil
|
173
191
|
end
|
174
192
|
|
175
193
|
# Returns the complete URL used for this request.
|
194
|
+
#
|
195
|
+
# class Request < Rack::Request
|
196
|
+
# include ActionDispatch::Http::URL
|
197
|
+
# end
|
198
|
+
#
|
199
|
+
# req = Request.new 'HTTP_HOST' => 'example.com'
|
200
|
+
# req.url # => "http://example.com"
|
176
201
|
def url
|
177
202
|
protocol + host_with_port + fullpath
|
178
203
|
end
|
179
204
|
|
180
205
|
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
|
206
|
+
#
|
207
|
+
# class Request < Rack::Request
|
208
|
+
# include ActionDispatch::Http::URL
|
209
|
+
# end
|
210
|
+
#
|
211
|
+
# req = Request.new 'HTTP_HOST' => 'example.com'
|
212
|
+
# req.protocol # => "http://"
|
213
|
+
#
|
214
|
+
# req = Request.new 'HTTP_HOST' => 'example.com', 'HTTPS' => 'on'
|
215
|
+
# req.protocol # => "https://"
|
181
216
|
def protocol
|
182
217
|
@protocol ||= ssl? ? 'https://' : 'http://'
|
183
218
|
end
|
184
219
|
|
185
220
|
# Returns the \host for this request, such as "example.com".
|
221
|
+
#
|
222
|
+
# class Request < Rack::Request
|
223
|
+
# include ActionDispatch::Http::URL
|
224
|
+
# end
|
225
|
+
#
|
226
|
+
# req = Request.new 'HTTP_HOST' => 'example.com'
|
227
|
+
# req.raw_host_with_port # => "example.com"
|
228
|
+
#
|
229
|
+
# req = Request.new 'HTTP_HOST' => 'example.com:8080'
|
230
|
+
# req.raw_host_with_port # => "example.com:8080"
|
186
231
|
def raw_host_with_port
|
187
|
-
if forwarded =
|
232
|
+
if forwarded = x_forwarded_host.presence
|
188
233
|
forwarded.split(/,\s?/).last
|
189
234
|
else
|
190
|
-
|
235
|
+
get_header('HTTP_HOST') || "#{server_name || server_addr}:#{get_header('SERVER_PORT')}"
|
191
236
|
end
|
192
237
|
end
|
193
238
|
|
194
239
|
# Returns the host for this request, such as example.com.
|
240
|
+
#
|
241
|
+
# class Request < Rack::Request
|
242
|
+
# include ActionDispatch::Http::URL
|
243
|
+
# end
|
244
|
+
#
|
245
|
+
# req = Request.new 'HTTP_HOST' => 'example.com:8080'
|
246
|
+
# req.host # => "example.com"
|
195
247
|
def host
|
196
|
-
raw_host_with_port.sub(/:\d+$/, '')
|
248
|
+
raw_host_with_port.sub(/:\d+$/, ''.freeze)
|
197
249
|
end
|
198
250
|
|
199
251
|
# Returns a \host:\port string for this request, such as "example.com" or
|
200
252
|
# "example.com:8080".
|
253
|
+
#
|
254
|
+
# class Request < Rack::Request
|
255
|
+
# include ActionDispatch::Http::URL
|
256
|
+
# end
|
257
|
+
#
|
258
|
+
# req = Request.new 'HTTP_HOST' => 'example.com:80'
|
259
|
+
# req.host_with_port # => "example.com"
|
260
|
+
#
|
261
|
+
# req = Request.new 'HTTP_HOST' => 'example.com:8080'
|
262
|
+
# req.host_with_port # => "example.com:8080"
|
201
263
|
def host_with_port
|
202
264
|
"#{host}#{port_string}"
|
203
265
|
end
|
204
266
|
|
205
267
|
# Returns the port number of this request as an integer.
|
268
|
+
#
|
269
|
+
# class Request < Rack::Request
|
270
|
+
# include ActionDispatch::Http::URL
|
271
|
+
# end
|
272
|
+
#
|
273
|
+
# req = Request.new 'HTTP_HOST' => 'example.com'
|
274
|
+
# req.port # => 80
|
275
|
+
#
|
276
|
+
# req = Request.new 'HTTP_HOST' => 'example.com:8080'
|
277
|
+
# req.port # => 8080
|
206
278
|
def port
|
207
279
|
@port ||= begin
|
208
280
|
if raw_host_with_port =~ /:(\d+)$/
|
@@ -214,6 +286,13 @@ module ActionDispatch
|
|
214
286
|
end
|
215
287
|
|
216
288
|
# Returns the standard \port number for this request's protocol.
|
289
|
+
#
|
290
|
+
# class Request < Rack::Request
|
291
|
+
# include ActionDispatch::Http::URL
|
292
|
+
# end
|
293
|
+
#
|
294
|
+
# req = Request.new 'HTTP_HOST' => 'example.com:8080'
|
295
|
+
# req.standard_port # => 80
|
217
296
|
def standard_port
|
218
297
|
case protocol
|
219
298
|
when 'https://' then 443
|
@@ -222,24 +301,54 @@ module ActionDispatch
|
|
222
301
|
end
|
223
302
|
|
224
303
|
# Returns whether this request is using the standard port
|
304
|
+
#
|
305
|
+
# class Request < Rack::Request
|
306
|
+
# include ActionDispatch::Http::URL
|
307
|
+
# end
|
308
|
+
#
|
309
|
+
# req = Request.new 'HTTP_HOST' => 'example.com:80'
|
310
|
+
# req.standard_port? # => true
|
311
|
+
#
|
312
|
+
# req = Request.new 'HTTP_HOST' => 'example.com:8080'
|
313
|
+
# req.standard_port? # => false
|
225
314
|
def standard_port?
|
226
315
|
port == standard_port
|
227
316
|
end
|
228
317
|
|
229
318
|
# Returns a number \port suffix like 8080 if the \port number of this request
|
230
319
|
# is not the default HTTP \port 80 or HTTPS \port 443.
|
320
|
+
#
|
321
|
+
# class Request < Rack::Request
|
322
|
+
# include ActionDispatch::Http::URL
|
323
|
+
# end
|
324
|
+
#
|
325
|
+
# req = Request.new 'HTTP_HOST' => 'example.com:80'
|
326
|
+
# req.optional_port # => nil
|
327
|
+
#
|
328
|
+
# req = Request.new 'HTTP_HOST' => 'example.com:8080'
|
329
|
+
# req.optional_port # => 8080
|
231
330
|
def optional_port
|
232
331
|
standard_port? ? nil : port
|
233
332
|
end
|
234
333
|
|
235
334
|
# Returns a string \port suffix, including colon, like ":8080" if the \port
|
236
335
|
# number of this request is not the default HTTP \port 80 or HTTPS \port 443.
|
336
|
+
#
|
337
|
+
# class Request < Rack::Request
|
338
|
+
# include ActionDispatch::Http::URL
|
339
|
+
# end
|
340
|
+
#
|
341
|
+
# req = Request.new 'HTTP_HOST' => 'example.com:80'
|
342
|
+
# req.port_string # => ""
|
343
|
+
#
|
344
|
+
# req = Request.new 'HTTP_HOST' => 'example.com:8080'
|
345
|
+
# req.port_string # => ":8080"
|
237
346
|
def port_string
|
238
347
|
standard_port? ? '' : ":#{port}"
|
239
348
|
end
|
240
349
|
|
241
350
|
def server_port
|
242
|
-
|
351
|
+
get_header('SERVER_PORT').to_i
|
243
352
|
end
|
244
353
|
|
245
354
|
# Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'action_controller/metal/exceptions'
|
2
|
-
require 'active_support/deprecation'
|
3
2
|
|
4
3
|
module ActionDispatch
|
5
4
|
module Journey
|
@@ -15,7 +14,7 @@ module ActionDispatch
|
|
15
14
|
|
16
15
|
def generate(name, options, path_parameters, parameterize = nil)
|
17
16
|
constraints = path_parameters.merge(options)
|
18
|
-
missing_keys =
|
17
|
+
missing_keys = nil # need for variable scope
|
19
18
|
|
20
19
|
match_route(name, constraints) do |route|
|
21
20
|
parameterized_parts = extract_parameterized_parts(route, options, path_parameters, parameterize)
|
@@ -26,22 +25,22 @@ module ActionDispatch
|
|
26
25
|
next unless name || route.dispatcher?
|
27
26
|
|
28
27
|
missing_keys = missing_keys(route, parameterized_parts)
|
29
|
-
next
|
28
|
+
next if missing_keys && !missing_keys.empty?
|
30
29
|
params = options.dup.delete_if do |key, _|
|
31
30
|
parameterized_parts.key?(key) || route.defaults.key?(key)
|
32
31
|
end
|
33
32
|
|
34
33
|
defaults = route.defaults
|
35
34
|
required_parts = route.required_parts
|
36
|
-
parameterized_parts.
|
37
|
-
value.to_s
|
35
|
+
parameterized_parts.keep_if do |key, value|
|
36
|
+
(defaults[key].nil? && value.present?) || value.to_s != defaults[key].to_s || required_parts.include?(key)
|
38
37
|
end
|
39
38
|
|
40
39
|
return [route.format(parameterized_parts), params]
|
41
40
|
end
|
42
41
|
|
43
42
|
message = "No route matches #{Hash[constraints.sort_by{|k,v| k.to_s}].inspect}"
|
44
|
-
message << " missing required keys: #{missing_keys.sort.inspect}"
|
43
|
+
message << " missing required keys: #{missing_keys.sort.inspect}" if missing_keys && !missing_keys.empty?
|
45
44
|
|
46
45
|
raise ActionController::UrlGenerationError, message
|
47
46
|
end
|
@@ -55,12 +54,12 @@ module ActionDispatch
|
|
55
54
|
def extract_parameterized_parts(route, options, recall, parameterize = nil)
|
56
55
|
parameterized_parts = recall.merge(options)
|
57
56
|
|
58
|
-
keys_to_keep = route.parts.
|
57
|
+
keys_to_keep = route.parts.reverse_each.drop_while { |part|
|
59
58
|
!options.key?(part) || (options[part] || recall[part]).nil?
|
60
59
|
} | route.required_parts
|
61
60
|
|
62
|
-
|
63
|
-
|
61
|
+
parameterized_parts.delete_if do |bad_key, _|
|
62
|
+
!keys_to_keep.include?(bad_key)
|
64
63
|
end
|
65
64
|
|
66
65
|
if parameterize
|
@@ -81,9 +80,6 @@ module ActionDispatch
|
|
81
80
|
if named_routes.key?(name)
|
82
81
|
yield named_routes[name]
|
83
82
|
else
|
84
|
-
# Make sure we don't show the deprecation warning more than once
|
85
|
-
warned = false
|
86
|
-
|
87
83
|
routes = non_recursive(cache, options)
|
88
84
|
|
89
85
|
hash = routes.group_by { |_, r| r.score(options) }
|
@@ -92,17 +88,6 @@ module ActionDispatch
|
|
92
88
|
break if score < 0
|
93
89
|
|
94
90
|
hash[score].sort_by { |i, _| i }.each do |_, route|
|
95
|
-
if name && !warned
|
96
|
-
ActiveSupport::Deprecation.warn <<-MSG.squish
|
97
|
-
You are trying to generate the URL for a named route called
|
98
|
-
#{name.inspect} but no such route was found. In the future,
|
99
|
-
this will result in an `ActionController::UrlGenerationError`
|
100
|
-
exception.
|
101
|
-
MSG
|
102
|
-
|
103
|
-
warned = true
|
104
|
-
end
|
105
|
-
|
106
91
|
yield route
|
107
92
|
end
|
108
93
|
end
|
@@ -125,15 +110,36 @@ module ActionDispatch
|
|
125
110
|
routes
|
126
111
|
end
|
127
112
|
|
113
|
+
module RegexCaseComparator
|
114
|
+
DEFAULT_INPUT = /[-_.a-zA-Z0-9]+\/[-_.a-zA-Z0-9]+/
|
115
|
+
DEFAULT_REGEX = /\A#{DEFAULT_INPUT}\Z/
|
116
|
+
|
117
|
+
def self.===(regex)
|
118
|
+
DEFAULT_INPUT == regex
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
128
122
|
# Returns an array populated with missing keys if any are present.
|
129
123
|
def missing_keys(route, parts)
|
130
|
-
missing_keys =
|
124
|
+
missing_keys = nil
|
131
125
|
tests = route.path.requirements
|
132
126
|
route.required_parts.each { |key|
|
133
|
-
|
134
|
-
|
127
|
+
case tests[key]
|
128
|
+
when nil
|
129
|
+
unless parts[key]
|
130
|
+
missing_keys ||= []
|
131
|
+
missing_keys << key
|
132
|
+
end
|
133
|
+
when RegexCaseComparator
|
134
|
+
unless RegexCaseComparator::DEFAULT_REGEX === parts[key]
|
135
|
+
missing_keys ||= []
|
136
|
+
missing_keys << key
|
137
|
+
end
|
135
138
|
else
|
136
|
-
|
139
|
+
unless /\A#{tests[key]}\Z/ === parts[key]
|
140
|
+
missing_keys ||= []
|
141
|
+
missing_keys << key
|
142
|
+
end
|
137
143
|
end
|
138
144
|
}
|
139
145
|
missing_keys
|
@@ -149,7 +155,7 @@ module ActionDispatch
|
|
149
155
|
|
150
156
|
def build_cache
|
151
157
|
root = { ___routes: [] }
|
152
|
-
routes.each_with_index do |route, i|
|
158
|
+
routes.routes.each_with_index do |route, i|
|
153
159
|
leaf = route.required_defaults.inject(root) do |h, tuple|
|
154
160
|
h[tuple] ||= {}
|
155
161
|
end
|
@@ -45,51 +45,6 @@ module ActionDispatch
|
|
45
45
|
(@table.keys + @table.values.flat_map(&:keys)).uniq
|
46
46
|
end
|
47
47
|
|
48
|
-
# Returns a generalized transition graph with reduced states. The states
|
49
|
-
# are reduced like a DFA, but the table must be simulated like an NFA.
|
50
|
-
#
|
51
|
-
# Edges of the GTG are regular expressions.
|
52
|
-
def generalized_table
|
53
|
-
gt = GTG::TransitionTable.new
|
54
|
-
marked = {}
|
55
|
-
state_id = Hash.new { |h,k| h[k] = h.length }
|
56
|
-
alphabet = self.alphabet
|
57
|
-
|
58
|
-
stack = [eclosure(0)]
|
59
|
-
|
60
|
-
until stack.empty?
|
61
|
-
state = stack.pop
|
62
|
-
next if marked[state] || state.empty?
|
63
|
-
|
64
|
-
marked[state] = true
|
65
|
-
|
66
|
-
alphabet.each do |alpha|
|
67
|
-
next_state = eclosure(following_states(state, alpha))
|
68
|
-
next if next_state.empty?
|
69
|
-
|
70
|
-
gt[state_id[state], state_id[next_state]] = alpha
|
71
|
-
stack << next_state
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
final_groups = state_id.keys.find_all { |s|
|
76
|
-
s.sort.last == accepting
|
77
|
-
}
|
78
|
-
|
79
|
-
final_groups.each do |states|
|
80
|
-
id = state_id[states]
|
81
|
-
|
82
|
-
gt.add_accepting(id)
|
83
|
-
save = states.find { |s|
|
84
|
-
@memos.key?(s) && eclosure(s).sort.last == accepting
|
85
|
-
}
|
86
|
-
|
87
|
-
gt.add_memo(id, memo(save))
|
88
|
-
end
|
89
|
-
|
90
|
-
gt
|
91
|
-
end
|
92
|
-
|
93
48
|
# Returns set of NFA states to which there is a transition on ast symbol
|
94
49
|
# +a+ from some state +s+ in +t+.
|
95
50
|
def following_states(t, a)
|
@@ -107,7 +62,7 @@ module ActionDispatch
|
|
107
62
|
end
|
108
63
|
|
109
64
|
def alphabet
|
110
|
-
inverted.values.flat_map(&:keys).compact.uniq.sort_by
|
65
|
+
inverted.values.flat_map(&:keys).compact.uniq.sort_by(&:to_s)
|
111
66
|
end
|
112
67
|
|
113
68
|
# Returns a set of NFA states reachable from some NFA state +s+ in set
|
@@ -14,15 +14,15 @@ module ActionDispatch
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def each(&block)
|
17
|
-
Visitors::Each.
|
17
|
+
Visitors::Each::INSTANCE.accept(self, block)
|
18
18
|
end
|
19
19
|
|
20
20
|
def to_s
|
21
|
-
Visitors::String.
|
21
|
+
Visitors::String::INSTANCE.accept(self, '')
|
22
22
|
end
|
23
23
|
|
24
24
|
def to_dot
|
25
|
-
Visitors::Dot.
|
25
|
+
Visitors::Dot::INSTANCE.accept(self)
|
26
26
|
end
|
27
27
|
|
28
28
|
def to_sym
|
@@ -30,7 +30,7 @@ module ActionDispatch
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def name
|
33
|
-
left.tr '*:', ''
|
33
|
+
left.tr '*:'.freeze, ''.freeze
|
34
34
|
end
|
35
35
|
|
36
36
|
def type
|
@@ -39,10 +39,15 @@ module ActionDispatch
|
|
39
39
|
|
40
40
|
def symbol?; false; end
|
41
41
|
def literal?; false; end
|
42
|
+
def terminal?; false; end
|
43
|
+
def star?; false; end
|
44
|
+
def cat?; false; end
|
45
|
+
def group?; false; end
|
42
46
|
end
|
43
47
|
|
44
48
|
class Terminal < Node # :nodoc:
|
45
49
|
alias :symbol :left
|
50
|
+
def terminal?; true; end
|
46
51
|
end
|
47
52
|
|
48
53
|
class Literal < Terminal # :nodoc:
|
@@ -69,11 +74,13 @@ module ActionDispatch
|
|
69
74
|
class Symbol < Terminal # :nodoc:
|
70
75
|
attr_accessor :regexp
|
71
76
|
alias :symbol :regexp
|
77
|
+
attr_reader :name
|
72
78
|
|
73
79
|
DEFAULT_EXP = /[^\.\/\?]+/
|
74
80
|
def initialize(left)
|
75
81
|
super
|
76
82
|
@regexp = DEFAULT_EXP
|
83
|
+
@name = left.tr '*:'.freeze, ''.freeze
|
77
84
|
end
|
78
85
|
|
79
86
|
def default_regexp?
|
@@ -89,9 +96,11 @@ module ActionDispatch
|
|
89
96
|
|
90
97
|
class Group < Unary # :nodoc:
|
91
98
|
def type; :GROUP; end
|
99
|
+
def group?; true; end
|
92
100
|
end
|
93
101
|
|
94
102
|
class Star < Unary # :nodoc:
|
103
|
+
def star?; true; end
|
95
104
|
def type; :STAR; end
|
96
105
|
|
97
106
|
def name
|
@@ -111,6 +120,7 @@ module ActionDispatch
|
|
111
120
|
end
|
112
121
|
|
113
122
|
class Cat < Binary # :nodoc:
|
123
|
+
def cat?; true; end
|
114
124
|
def type; :CAT; end
|
115
125
|
end
|
116
126
|
|