actionpack 4.1.7 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +311 -527
  3. data/README.rdoc +7 -2
  4. data/lib/abstract_controller/base.rb +16 -6
  5. data/lib/abstract_controller/callbacks.rb +28 -51
  6. data/lib/abstract_controller/helpers.rb +11 -4
  7. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  8. data/lib/abstract_controller/url_for.rb +1 -1
  9. data/lib/action_controller/base.rb +2 -1
  10. data/lib/action_controller/caching/fragments.rb +7 -1
  11. data/lib/action_controller/caching.rb +1 -1
  12. data/lib/action_controller/log_subscriber.rb +26 -26
  13. data/lib/action_controller/metal/conditional_get.rb +37 -12
  14. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  15. data/lib/action_controller/metal/exceptions.rb +1 -1
  16. data/lib/action_controller/metal/force_ssl.rb +1 -1
  17. data/lib/action_controller/metal/head.rb +7 -3
  18. data/lib/action_controller/metal/http_authentication.rb +14 -9
  19. data/lib/action_controller/metal/instrumentation.rb +8 -5
  20. data/lib/action_controller/metal/live.rb +57 -6
  21. data/lib/action_controller/metal/mime_responds.rb +23 -246
  22. data/lib/action_controller/metal/params_wrapper.rb +2 -2
  23. data/lib/action_controller/metal/rack_delegation.rb +1 -1
  24. data/lib/action_controller/metal/redirecting.rb +14 -8
  25. data/lib/action_controller/metal/renderers.rb +30 -10
  26. data/lib/action_controller/metal/rendering.rb +2 -6
  27. data/lib/action_controller/metal/request_forgery_protection.rb +78 -7
  28. data/lib/action_controller/metal/streaming.rb +1 -1
  29. data/lib/action_controller/metal/strong_parameters.rb +125 -12
  30. data/lib/action_controller/metal/url_for.rb +11 -12
  31. data/lib/action_controller/metal.rb +12 -11
  32. data/lib/action_controller/model_naming.rb +1 -1
  33. data/lib/action_controller/railtie.rb +4 -0
  34. data/lib/action_controller/test_case.rb +112 -75
  35. data/lib/action_controller.rb +1 -1
  36. data/lib/action_dispatch/http/cache.rb +5 -4
  37. data/lib/action_dispatch/http/filter_parameters.rb +2 -2
  38. data/lib/action_dispatch/http/headers.rb +43 -9
  39. data/lib/action_dispatch/http/mime_negotiation.rb +10 -3
  40. data/lib/action_dispatch/http/mime_type.rb +2 -2
  41. data/lib/action_dispatch/http/parameter_filter.rb +1 -1
  42. data/lib/action_dispatch/http/parameters.rb +11 -26
  43. data/lib/action_dispatch/http/request.rb +37 -11
  44. data/lib/action_dispatch/http/response.rb +70 -18
  45. data/lib/action_dispatch/http/upload.rb +3 -8
  46. data/lib/action_dispatch/http/url.rb +88 -69
  47. data/lib/action_dispatch/journey/formatter.rb +33 -17
  48. data/lib/action_dispatch/journey/gtg/builder.rb +3 -3
  49. data/lib/action_dispatch/journey/gtg/simulator.rb +10 -7
  50. data/lib/action_dispatch/journey/gtg/transition_table.rb +20 -28
  51. data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
  52. data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
  53. data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -5
  54. data/lib/action_dispatch/journey/nodes/node.rb +4 -0
  55. data/lib/action_dispatch/journey/parser.rb +52 -60
  56. data/lib/action_dispatch/journey/parser.y +11 -10
  57. data/lib/action_dispatch/journey/path/pattern.rb +16 -19
  58. data/lib/action_dispatch/journey/route.rb +3 -18
  59. data/lib/action_dispatch/journey/router/strexp.rb +9 -6
  60. data/lib/action_dispatch/journey/router.rb +53 -77
  61. data/lib/action_dispatch/journey/scanner.rb +5 -5
  62. data/lib/action_dispatch/journey/visitors.rb +81 -92
  63. data/lib/action_dispatch/journey/visualizer/fsm.css +0 -4
  64. data/lib/action_dispatch/journey/visualizer/index.html.erb +2 -2
  65. data/lib/action_dispatch/middleware/callbacks.rb +1 -1
  66. data/lib/action_dispatch/middleware/cookies.rb +29 -29
  67. data/lib/action_dispatch/middleware/debug_exceptions.rb +15 -4
  68. data/lib/action_dispatch/middleware/exception_wrapper.rb +50 -18
  69. data/lib/action_dispatch/middleware/flash.rb +13 -7
  70. data/lib/action_dispatch/middleware/params_parser.rb +1 -1
  71. data/lib/action_dispatch/middleware/public_exceptions.rb +12 -3
  72. data/lib/action_dispatch/middleware/remote_ip.rb +40 -54
  73. data/lib/action_dispatch/middleware/request_id.rb +1 -1
  74. data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -1
  75. data/lib/action_dispatch/middleware/show_exceptions.rb +1 -0
  76. data/lib/action_dispatch/middleware/static.rb +66 -37
  77. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +21 -19
  78. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +37 -9
  79. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +2 -8
  80. data/lib/action_dispatch/middleware/templates/rescues/{diagnostics.erb → diagnostics.html.erb} +0 -0
  81. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  82. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +6 -0
  83. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +4 -0
  84. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +2 -0
  85. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -24
  86. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +0 -1
  87. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +120 -64
  88. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  89. data/lib/action_dispatch/routing/inspector.rb +5 -12
  90. data/lib/action_dispatch/routing/mapper.rb +410 -281
  91. data/lib/action_dispatch/routing/polymorphic_routes.rb +191 -79
  92. data/lib/action_dispatch/routing/redirection.rb +10 -12
  93. data/lib/action_dispatch/routing/route_set.rb +297 -168
  94. data/lib/action_dispatch/routing/url_for.rb +15 -4
  95. data/lib/action_dispatch/testing/assertions/dom.rb +2 -26
  96. data/lib/action_dispatch/testing/assertions/response.rb +2 -7
  97. data/lib/action_dispatch/testing/assertions/routing.rb +22 -22
  98. data/lib/action_dispatch/testing/assertions/selector.rb +2 -429
  99. data/lib/action_dispatch/testing/assertions/tag.rb +2 -134
  100. data/lib/action_dispatch/testing/assertions.rb +11 -7
  101. data/lib/action_dispatch/testing/integration.rb +24 -19
  102. data/lib/action_dispatch/testing/test_request.rb +1 -1
  103. data/lib/action_dispatch/testing/test_response.rb +7 -0
  104. data/lib/action_pack/gem_version.rb +3 -3
  105. metadata +55 -13
  106. data/lib/action_controller/metal/responder.rb +0 -297
@@ -18,6 +18,7 @@ module ActionDispatch
18
18
  # A +Tempfile+ object with the actual uploaded file. Note that some of
19
19
  # its interface is available directly.
20
20
  attr_accessor :tempfile
21
+ alias :to_io :tempfile
21
22
 
22
23
  # A string with the headers of the multipart request.
23
24
  attr_accessor :headers
@@ -26,7 +27,8 @@ module ActionDispatch
26
27
  @tempfile = hash[:tempfile]
27
28
  raise(ArgumentError, ':tempfile is required') unless @tempfile
28
29
 
29
- @original_filename = encode_filename(hash[:filename])
30
+ @original_filename = hash[:filename]
31
+ @original_filename &&= @original_filename.encode "UTF-8"
30
32
  @content_type = hash[:type]
31
33
  @headers = hash[:head]
32
34
  end
@@ -65,13 +67,6 @@ module ActionDispatch
65
67
  def eof?
66
68
  @tempfile.eof?
67
69
  end
68
-
69
- private
70
-
71
- def encode_filename(filename)
72
- # Encode the filename in the utf8 encoding, unless it is nil
73
- filename.force_encoding(Encoding::UTF_8).encode! if filename
74
- end
75
70
  end
76
71
  end
77
72
  end
@@ -5,51 +5,83 @@ module ActionDispatch
5
5
  module Http
6
6
  module URL
7
7
  IP_HOST_REGEXP = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
8
- HOST_REGEXP = /(^.*:\/\/)?([^:]+)(?::(\d+$))?/
8
+ HOST_REGEXP = /(^[^:]+:\/\/)?([^:]+)(?::(\d+$))?/
9
9
  PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
10
10
 
11
11
  mattr_accessor :tld_length
12
12
  self.tld_length = 1
13
13
 
14
14
  class << self
15
- def extract_domain(host, tld_length = @@tld_length)
16
- host.split('.').last(1 + tld_length).join('.') if named_host?(host)
15
+ def extract_domain(host, tld_length)
16
+ extract_domain_from(host, tld_length) if named_host?(host)
17
17
  end
18
18
 
19
- def extract_subdomains(host, tld_length = @@tld_length)
19
+ def extract_subdomains(host, tld_length)
20
20
  if named_host?(host)
21
- parts = host.split('.')
22
- parts[0..-(tld_length + 2)]
21
+ extract_subdomains_from(host, tld_length)
23
22
  else
24
23
  []
25
24
  end
26
25
  end
27
26
 
28
- def extract_subdomain(host, tld_length = @@tld_length)
27
+ def extract_subdomain(host, tld_length)
29
28
  extract_subdomains(host, tld_length).join('.')
30
29
  end
31
30
 
32
- def url_for(options = {})
33
- options = options.dup
34
- path = options.delete(:script_name).to_s.chomp("/")
35
- path << options.delete(:path).to_s
31
+ def url_for(options)
32
+ if options[:only_path]
33
+ path_for options
34
+ else
35
+ full_url_for options
36
+ end
37
+ end
36
38
 
37
- add_trailing_slash(path) if options[:trailing_slash]
39
+ def full_url_for(options)
40
+ host = options[:host]
41
+ protocol = options[:protocol]
42
+ port = options[:port]
38
43
 
39
- params = options[:params].is_a?(Hash) ? options[:params] : options.slice(:params)
40
- params.reject! { |_,v| v.to_param.nil? }
44
+ unless host
45
+ raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true'
46
+ end
41
47
 
42
- result = build_host_url(options)
48
+ build_host_url(host, port, protocol, options, path_for(options))
49
+ end
43
50
 
44
- result << path
51
+ def path_for(options)
52
+ path = options[:script_name].to_s.chomp("/")
53
+ path << options[:path] if options.key?(:path)
45
54
 
46
- result << "?#{params.to_query}" unless params.empty?
47
- result << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor]
48
- result
55
+ add_trailing_slash(path) if options[:trailing_slash]
56
+ add_params(path, options[:params]) if options.key?(:params)
57
+ add_anchor(path, options[:anchor]) if options.key?(:anchor)
58
+
59
+ path
49
60
  end
50
61
 
51
62
  private
52
63
 
64
+ def add_params(path, params)
65
+ params = { params: params } unless params.is_a?(Hash)
66
+ params.reject! { |_,v| v.to_param.nil? }
67
+ path << "?#{params.to_query}" unless params.empty?
68
+ end
69
+
70
+ def add_anchor(path, anchor)
71
+ if anchor
72
+ path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
73
+ end
74
+ end
75
+
76
+ def extract_domain_from(host, tld_length)
77
+ host.split('.').last(1 + tld_length).join('.')
78
+ end
79
+
80
+ def extract_subdomains_from(host, tld_length)
81
+ parts = host.split('.')
82
+ parts[0..-(tld_length + 2)]
83
+ end
84
+
53
85
  def add_trailing_slash(path)
54
86
  # includes querysting
55
87
  if path.include?('?')
@@ -58,54 +90,38 @@ module ActionDispatch
58
90
  elsif !path.include?(".")
59
91
  path.sub!(/[^\/]\z|\A\z/, '\&/')
60
92
  end
61
-
62
- path
63
93
  end
64
94
 
65
- def build_host_url(options)
66
- if options[:host].blank? && options[:only_path].blank?
67
- raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true'
95
+ def build_host_url(host, port, protocol, options, path)
96
+ if match = host.match(HOST_REGEXP)
97
+ protocol ||= match[1] unless protocol == false
98
+ host = match[2]
99
+ port = match[3] unless options.key? :port
68
100
  end
69
101
 
70
- result = ""
102
+ protocol = normalize_protocol protocol
103
+ host = normalize_host(host, options)
71
104
 
72
- unless options[:only_path]
73
- if match = options[:host].match(HOST_REGEXP)
74
- options[:protocol] ||= match[1] unless options[:protocol] == false
75
- options[:host] = match[2]
76
- options[:port] = match[3] unless options.key?(:port)
77
- end
105
+ result = protocol.dup
78
106
 
79
- options[:protocol] = normalize_protocol(options)
80
- options[:host] = normalize_host(options)
81
- options[:port] = normalize_port(options)
82
-
83
- result << options[:protocol]
84
- result << rewrite_authentication(options)
85
- result << options[:host]
86
- result << ":#{options[:port]}" if options[:port]
107
+ if options[:user] && options[:password]
108
+ result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
87
109
  end
88
- result
89
- end
90
110
 
91
- def named_host?(host)
92
- host && IP_HOST_REGEXP !~ host
93
- end
111
+ result << host
112
+ normalize_port(port, protocol) { |normalized_port|
113
+ result << ":#{normalized_port}"
114
+ }
94
115
 
95
- def same_host?(options)
96
- (options[:subdomain] == true || !options.key?(:subdomain)) && options[:domain].nil?
116
+ result.concat path
97
117
  end
98
118
 
99
- def rewrite_authentication(options)
100
- if options[:user] && options[:password]
101
- "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
102
- else
103
- ""
104
- end
119
+ def named_host?(host)
120
+ IP_HOST_REGEXP !~ host
105
121
  end
106
122
 
107
- def normalize_protocol(options)
108
- case options[:protocol]
123
+ def normalize_protocol(protocol)
124
+ case protocol
109
125
  when nil
110
126
  "http://"
111
127
  when false, "//"
@@ -113,36 +129,39 @@ module ActionDispatch
113
129
  when PROTOCOL_REGEXP
114
130
  "#{$1}://"
115
131
  else
116
- raise ArgumentError, "Invalid :protocol option: #{options[:protocol].inspect}"
132
+ raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
117
133
  end
118
134
  end
119
135
 
120
- def normalize_host(options)
121
- return options[:host] if !named_host?(options[:host]) || same_host?(options)
136
+ def normalize_host(_host, options)
137
+ return _host unless named_host?(_host)
122
138
 
123
139
  tld_length = options[:tld_length] || @@tld_length
140
+ subdomain = options.fetch :subdomain, true
141
+ domain = options[:domain]
124
142
 
125
143
  host = ""
126
- if options[:subdomain] == true || !options.key?(:subdomain)
127
- host << extract_subdomain(options[:host], tld_length).to_param
128
- elsif options[:subdomain].present?
129
- host << options[:subdomain].to_param
144
+ if subdomain == true
145
+ return _host if domain.nil?
146
+
147
+ host << extract_subdomains_from(_host, tld_length).join('.')
148
+ elsif subdomain
149
+ host << subdomain.to_param
130
150
  end
131
151
  host << "." unless host.empty?
132
- host << (options[:domain] || extract_domain(options[:host], tld_length))
152
+ host << (domain || extract_domain_from(_host, tld_length))
133
153
  host
134
154
  end
135
155
 
136
- def normalize_port(options)
137
- return nil if options[:port].nil? || options[:port] == false
156
+ def normalize_port(port, protocol)
157
+ return unless port
138
158
 
139
- case options[:protocol]
140
- when "//"
141
- options[:port]
159
+ case protocol
160
+ when "//" then yield port
142
161
  when "https://"
143
- options[:port].to_i == 443 ? nil : options[:port]
162
+ yield port unless port.to_i == 443
144
163
  else
145
- options[:port].to_i == 80 ? nil : options[:port]
164
+ yield port unless port.to_i == 80
146
165
  end
147
166
  end
148
167
  end
@@ -1,4 +1,5 @@
1
1
  require 'action_controller/metal/exceptions'
2
+ require 'active_support/deprecation'
2
3
 
3
4
  module ActionDispatch
4
5
  module Journey
@@ -12,12 +13,12 @@ module ActionDispatch
12
13
  @cache = nil
13
14
  end
14
15
 
15
- def generate(type, name, options, recall = {}, parameterize = nil)
16
- constraints = recall.merge(options)
16
+ def generate(name, options, path_parameters, parameterize = nil)
17
+ constraints = path_parameters.merge(options)
17
18
  missing_keys = []
18
19
 
19
20
  match_route(name, constraints) do |route|
20
- parameterized_parts = extract_parameterized_parts(route, options, recall, parameterize)
21
+ parameterized_parts = extract_parameterized_parts(route, options, path_parameters, parameterize)
21
22
 
22
23
  # Skip this route unless a name has been provided or it is a
23
24
  # standard Rails route since we can't determine whether an options
@@ -30,11 +31,17 @@ module ActionDispatch
30
31
  parameterized_parts.key?(key) || route.defaults.key?(key)
31
32
  end
32
33
 
34
+ defaults = route.defaults
35
+ 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)
38
+ end
39
+
33
40
  return [route.format(parameterized_parts), params]
34
41
  end
35
42
 
36
43
  message = "No route matches #{Hash[constraints.sort].inspect}"
37
- message << " missing required keys: #{missing_keys.sort.inspect}" if name
44
+ message << " missing required keys: #{missing_keys.sort.inspect}" unless missing_keys.empty?
38
45
 
39
46
  raise ActionController::UrlGenerationError, message
40
47
  end
@@ -74,14 +81,28 @@ module ActionDispatch
74
81
  if named_routes.key?(name)
75
82
  yield named_routes[name]
76
83
  else
77
- routes = non_recursive(cache, options.to_a)
84
+ # Make sure we don't show the deprecation warning more than once
85
+ warned = false
86
+
87
+ routes = non_recursive(cache, options)
78
88
 
79
89
  hash = routes.group_by { |_, r| r.score(options) }
80
90
 
81
91
  hash.keys.sort.reverse_each do |score|
82
- next if score < 0
92
+ break if score < 0
83
93
 
84
94
  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
+
85
106
  yield route
86
107
  end
87
108
  end
@@ -90,14 +111,14 @@ module ActionDispatch
90
111
 
91
112
  def non_recursive(cache, options)
92
113
  routes = []
93
- stack = [cache]
114
+ queue = [cache]
94
115
 
95
- while stack.any?
96
- c = stack.shift
116
+ while queue.any?
117
+ c = queue.shift
97
118
  routes.concat(c[:___routes]) if c.key?(:___routes)
98
119
 
99
120
  options.each do |pair|
100
- stack << c[pair] if c.key?(pair)
121
+ queue << c[pair] if c.key?(pair)
101
122
  end
102
123
  end
103
124
 
@@ -121,14 +142,9 @@ module ActionDispatch
121
142
  def possibles(cache, options, depth = 0)
122
143
  cache.fetch(:___routes) { [] } + options.find_all { |pair|
123
144
  cache.key?(pair)
124
- }.map { |pair|
145
+ }.flat_map { |pair|
125
146
  possibles(cache[pair], options, depth + 1)
126
- }.flatten(1)
127
- end
128
-
129
- # Returns +true+ if no missing keys are present, otherwise +false+.
130
- def verify_required_parts!(route, parts)
131
- missing_keys(route, parts).empty?
147
+ }
132
148
  end
133
149
 
134
150
  def build_cache
@@ -27,7 +27,7 @@ module ActionDispatch
27
27
  marked[s] = true # mark s
28
28
 
29
29
  s.group_by { |state| symbol(state) }.each do |sym, ps|
30
- u = ps.map { |l| followpos(l) }.flatten
30
+ u = ps.flat_map { |l| followpos(l) }
31
31
  next if u.empty?
32
32
 
33
33
  if u.uniq == [DUMMY]
@@ -90,7 +90,7 @@ module ActionDispatch
90
90
  firstpos(node.left)
91
91
  end
92
92
  when Nodes::Or
93
- node.children.map { |c| firstpos(c) }.flatten.uniq
93
+ node.children.flat_map { |c| firstpos(c) }.uniq
94
94
  when Nodes::Unary
95
95
  firstpos(node.left)
96
96
  when Nodes::Terminal
@@ -105,7 +105,7 @@ module ActionDispatch
105
105
  when Nodes::Star
106
106
  firstpos(node.left)
107
107
  when Nodes::Or
108
- node.children.map { |c| lastpos(c) }.flatten.uniq
108
+ node.children.flat_map { |c| lastpos(c) }.uniq
109
109
  when Nodes::Cat
110
110
  if nullable?(node.right)
111
111
  lastpos(node.left) | lastpos(node.right)
@@ -19,6 +19,14 @@ module ActionDispatch
19
19
  end
20
20
 
21
21
  def simulate(string)
22
+ ms = memos(string) { return }
23
+ MatchData.new(ms)
24
+ end
25
+
26
+ alias :=~ :simulate
27
+ alias :match :simulate
28
+
29
+ def memos(string)
22
30
  input = StringScanner.new(string)
23
31
  state = [0]
24
32
  while sym = input.scan(%r([/.?]|[^/.?]+))
@@ -29,15 +37,10 @@ module ActionDispatch
29
37
  tt.accepting? s
30
38
  }
31
39
 
32
- return if acceptance_states.empty?
40
+ return yield if acceptance_states.empty?
33
41
 
34
- memos = acceptance_states.map { |x| tt.memo(x) }.flatten.compact
35
-
36
- MatchData.new(memos)
42
+ acceptance_states.flat_map { |x| tt.memo(x) }.compact
37
43
  end
38
-
39
- alias :=~ :simulate
40
- alias :match :simulate
41
44
  end
42
45
  end
43
46
  end
@@ -40,7 +40,19 @@ module ActionDispatch
40
40
  end
41
41
 
42
42
  def move(t, a)
43
- move_string(t, a).concat(move_regexp(t, a))
43
+ return [] if t.empty?
44
+
45
+ regexps = []
46
+
47
+ t.map { |s|
48
+ if states = @regexp_states[s]
49
+ regexps.concat states.map { |re, v| re === a ? v : nil }
50
+ end
51
+
52
+ if states = @string_states[s]
53
+ states[a]
54
+ end
55
+ }.compact.concat regexps
44
56
  end
45
57
 
46
58
  def as_json(options = nil)
@@ -76,13 +88,13 @@ module ActionDispatch
76
88
  erb = File.read File.join(viz_dir, 'index.html.erb')
77
89
  states = "function tt() { return #{to_json}; }"
78
90
 
79
- fun_routes = paths.shuffle.first(3).map do |ast|
91
+ fun_routes = paths.sample(3).map do |ast|
80
92
  ast.map { |n|
81
93
  case n
82
94
  when Nodes::Symbol
83
95
  case n.left
84
96
  when ':id' then rand(100).to_s
85
- when ':format' then %w{ xml json }.shuffle.first
97
+ when ':format' then %w{ xml json }.sample
86
98
  else
87
99
  'omg'
88
100
  end
@@ -114,17 +126,17 @@ module ActionDispatch
114
126
  end
115
127
 
116
128
  def states
117
- ss = @string_states.keys + @string_states.values.map(&:values).flatten
118
- rs = @regexp_states.keys + @regexp_states.values.map(&:values).flatten
129
+ ss = @string_states.keys + @string_states.values.flat_map(&:values)
130
+ rs = @regexp_states.keys + @regexp_states.values.flat_map(&:values)
119
131
  (ss + rs).uniq
120
132
  end
121
133
 
122
134
  def transitions
123
- @string_states.map { |from, hash|
135
+ @string_states.flat_map { |from, hash|
124
136
  hash.map { |s, to| [from, s, to] }
125
- }.flatten(1) + @regexp_states.map { |from, hash|
137
+ } + @regexp_states.flat_map { |from, hash|
126
138
  hash.map { |s, to| [from, s, to] }
127
- }.flatten(1)
139
+ }
128
140
  end
129
141
 
130
142
  private
@@ -139,26 +151,6 @@ module ActionDispatch
139
151
  raise ArgumentError, 'unknown symbol: %s' % sym.class
140
152
  end
141
153
  end
142
-
143
- def move_regexp(t, a)
144
- return [] if t.empty?
145
-
146
- t.map { |s|
147
- if states = @regexp_states[s]
148
- states.map { |re, v| re === a ? v : nil }
149
- end
150
- }.flatten.compact.uniq
151
- end
152
-
153
- def move_string(t, a)
154
- return [] if t.empty?
155
-
156
- t.map do |s|
157
- if states = @string_states[s]
158
- states[a]
159
- end
160
- end.compact
161
- end
162
154
  end
163
155
  end
164
156
  end