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.

Files changed (125) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +379 -462
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -3
  5. data/lib/abstract_controller.rb +0 -2
  6. data/lib/abstract_controller/base.rb +17 -32
  7. data/lib/abstract_controller/callbacks.rb +52 -19
  8. data/lib/abstract_controller/collector.rb +4 -9
  9. data/lib/abstract_controller/helpers.rb +2 -2
  10. data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
  11. data/lib/abstract_controller/rendering.rb +27 -22
  12. data/lib/abstract_controller/translation.rb +8 -7
  13. data/lib/action_controller.rb +4 -3
  14. data/lib/action_controller/api.rb +146 -0
  15. data/lib/action_controller/base.rb +6 -10
  16. data/lib/action_controller/caching.rb +1 -3
  17. data/lib/action_controller/caching/fragments.rb +48 -3
  18. data/lib/action_controller/form_builder.rb +48 -0
  19. data/lib/action_controller/log_subscriber.rb +1 -10
  20. data/lib/action_controller/metal.rb +89 -62
  21. data/lib/action_controller/metal/basic_implicit_render.rb +11 -0
  22. data/lib/action_controller/metal/conditional_get.rb +65 -24
  23. data/lib/action_controller/metal/cookies.rb +0 -2
  24. data/lib/action_controller/metal/data_streaming.rb +2 -22
  25. data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
  26. data/lib/action_controller/metal/exceptions.rb +11 -6
  27. data/lib/action_controller/metal/force_ssl.rb +6 -6
  28. data/lib/action_controller/metal/head.rb +14 -7
  29. data/lib/action_controller/metal/helpers.rb +9 -5
  30. data/lib/action_controller/metal/http_authentication.rb +37 -38
  31. data/lib/action_controller/metal/implicit_render.rb +23 -6
  32. data/lib/action_controller/metal/instrumentation.rb +0 -1
  33. data/lib/action_controller/metal/live.rb +17 -55
  34. data/lib/action_controller/metal/mime_responds.rb +17 -37
  35. data/lib/action_controller/metal/params_wrapper.rb +8 -8
  36. data/lib/action_controller/metal/redirecting.rb +32 -9
  37. data/lib/action_controller/metal/renderers.rb +10 -8
  38. data/lib/action_controller/metal/rendering.rb +38 -6
  39. data/lib/action_controller/metal/request_forgery_protection.rb +67 -35
  40. data/lib/action_controller/metal/rescue.rb +2 -4
  41. data/lib/action_controller/metal/streaming.rb +4 -4
  42. data/lib/action_controller/metal/strong_parameters.rb +231 -78
  43. data/lib/action_controller/metal/testing.rb +1 -12
  44. data/lib/action_controller/metal/url_for.rb +12 -5
  45. data/lib/action_controller/renderer.rb +111 -0
  46. data/lib/action_controller/template_assertions.rb +9 -0
  47. data/lib/action_controller/test_case.rb +267 -363
  48. data/lib/action_dispatch.rb +2 -1
  49. data/lib/action_dispatch/http/cache.rb +23 -26
  50. data/lib/action_dispatch/http/filter_parameters.rb +6 -8
  51. data/lib/action_dispatch/http/filter_redirect.rb +7 -8
  52. data/lib/action_dispatch/http/headers.rb +28 -11
  53. data/lib/action_dispatch/http/mime_negotiation.rb +40 -26
  54. data/lib/action_dispatch/http/mime_type.rb +92 -61
  55. data/lib/action_dispatch/http/mime_types.rb +1 -4
  56. data/lib/action_dispatch/http/parameter_filter.rb +18 -8
  57. data/lib/action_dispatch/http/parameters.rb +45 -41
  58. data/lib/action_dispatch/http/request.rb +146 -82
  59. data/lib/action_dispatch/http/response.rb +180 -99
  60. data/lib/action_dispatch/http/url.rb +117 -8
  61. data/lib/action_dispatch/journey/formatter.rb +34 -28
  62. data/lib/action_dispatch/journey/gtg/transition_table.rb +1 -1
  63. data/lib/action_dispatch/journey/nfa/dot.rb +0 -2
  64. data/lib/action_dispatch/journey/nfa/transition_table.rb +1 -46
  65. data/lib/action_dispatch/journey/nodes/node.rb +14 -4
  66. data/lib/action_dispatch/journey/parser_extras.rb +4 -0
  67. data/lib/action_dispatch/journey/path/pattern.rb +37 -41
  68. data/lib/action_dispatch/journey/route.rb +71 -17
  69. data/lib/action_dispatch/journey/router.rb +5 -6
  70. data/lib/action_dispatch/journey/router/utils.rb +5 -5
  71. data/lib/action_dispatch/journey/routes.rb +14 -15
  72. data/lib/action_dispatch/journey/visitors.rb +86 -43
  73. data/lib/action_dispatch/middleware/cookies.rb +184 -135
  74. data/lib/action_dispatch/middleware/debug_exceptions.rb +115 -45
  75. data/lib/action_dispatch/middleware/exception_wrapper.rb +21 -20
  76. data/lib/action_dispatch/middleware/flash.rb +61 -45
  77. data/lib/action_dispatch/middleware/load_interlock.rb +21 -0
  78. data/lib/action_dispatch/middleware/params_parser.rb +30 -46
  79. data/lib/action_dispatch/middleware/public_exceptions.rb +2 -2
  80. data/lib/action_dispatch/middleware/reloader.rb +2 -4
  81. data/lib/action_dispatch/middleware/remote_ip.rb +29 -19
  82. data/lib/action_dispatch/middleware/request_id.rb +11 -6
  83. data/lib/action_dispatch/middleware/session/abstract_store.rb +23 -11
  84. data/lib/action_dispatch/middleware/session/cache_store.rb +9 -6
  85. data/lib/action_dispatch/middleware/session/cookie_store.rb +29 -23
  86. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +4 -0
  87. data/lib/action_dispatch/middleware/show_exceptions.rb +11 -9
  88. data/lib/action_dispatch/middleware/ssl.rb +93 -36
  89. data/lib/action_dispatch/middleware/stack.rb +43 -48
  90. data/lib/action_dispatch/middleware/static.rb +52 -40
  91. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
  92. data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
  93. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  94. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
  95. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
  96. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
  97. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +59 -63
  98. data/lib/action_dispatch/railtie.rb +0 -2
  99. data/lib/action_dispatch/request/session.rb +66 -34
  100. data/lib/action_dispatch/request/utils.rb +51 -19
  101. data/lib/action_dispatch/routing.rb +3 -8
  102. data/lib/action_dispatch/routing/inspector.rb +6 -30
  103. data/lib/action_dispatch/routing/mapper.rb +447 -322
  104. data/lib/action_dispatch/routing/polymorphic_routes.rb +8 -14
  105. data/lib/action_dispatch/routing/redirection.rb +3 -3
  106. data/lib/action_dispatch/routing/route_set.rb +124 -227
  107. data/lib/action_dispatch/routing/url_for.rb +27 -10
  108. data/lib/action_dispatch/testing/assertions.rb +1 -1
  109. data/lib/action_dispatch/testing/assertions/response.rb +27 -9
  110. data/lib/action_dispatch/testing/assertions/routing.rb +9 -9
  111. data/lib/action_dispatch/testing/integration.rb +237 -76
  112. data/lib/action_dispatch/testing/test_process.rb +5 -5
  113. data/lib/action_dispatch/testing/test_request.rb +12 -21
  114. data/lib/action_dispatch/testing/test_response.rb +1 -4
  115. data/lib/action_pack.rb +1 -1
  116. data/lib/action_pack/gem_version.rb +4 -4
  117. metadata +26 -25
  118. data/lib/action_controller/metal/hide_actions.rb +0 -40
  119. data/lib/action_controller/metal/rack_delegation.rb +0 -32
  120. data/lib/action_controller/middleware.rb +0 -39
  121. data/lib/action_controller/model_naming.rb +0 -12
  122. data/lib/action_dispatch/journey/router/strexp.rb +0 -27
  123. data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
  124. data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
  125. 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
- path << "?#{params.to_query}" unless params.empty?
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(env)
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 = env["HTTP_X_FORWARDED_HOST"].presence
232
+ if forwarded = x_forwarded_host.presence
188
233
  forwarded.split(/,\s?/).last
189
234
  else
190
- env['HTTP_HOST'] || "#{env['SERVER_NAME'] || env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
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
- @env['SERVER_PORT'].to_i
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 unless missing_keys.empty?
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.delete_if do |key, value|
37
- value.to_s == defaults[key].to_s && !required_parts.include?(key)
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}" unless missing_keys.empty?
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.reverse.drop_while { |part|
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
- (parameterized_parts.keys - keys_to_keep).each do |bad_key|
63
- parameterized_parts.delete(bad_key)
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
- if tests.key?(key)
134
- missing_keys << key unless /\A#{tests[key]}\Z/ === parts[key]
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
- missing_keys << key unless parts[key]
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
@@ -109,7 +109,7 @@ module ActionDispatch
109
109
  svg = to_svg
110
110
  javascripts = [states, fsm_js]
111
111
 
112
- # Annoying hack for 1.9 warnings
112
+ # Annoying hack warnings
113
113
  fun_routes = fun_routes
114
114
  stylesheets = stylesheets
115
115
  svg = svg
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module ActionDispatch
4
2
  module Journey # :nodoc:
5
3
  module NFA # :nodoc:
@@ -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 { |x| x.to_s }
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.new(block).accept(self)
17
+ Visitors::Each::INSTANCE.accept(self, block)
18
18
  end
19
19
 
20
20
  def to_s
21
- Visitors::String.new.accept(self)
21
+ Visitors::String::INSTANCE.accept(self, '')
22
22
  end
23
23
 
24
24
  def to_dot
25
- Visitors::Dot.new.accept(self)
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