actionpack 5.2.1 → 7.0.2.4

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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +264 -220
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -6
  5. data/lib/abstract_controller/asset_paths.rb +1 -1
  6. data/lib/abstract_controller/base.rb +24 -4
  7. data/lib/abstract_controller/caching/fragments.rb +8 -24
  8. data/lib/abstract_controller/caching.rb +2 -2
  9. data/lib/abstract_controller/callbacks.rb +34 -8
  10. data/lib/abstract_controller/collector.rb +5 -4
  11. data/lib/abstract_controller/error.rb +1 -1
  12. data/lib/abstract_controller/helpers.rb +107 -90
  13. data/lib/abstract_controller/logger.rb +1 -1
  14. data/lib/abstract_controller/railties/routes_helpers.rb +19 -1
  15. data/lib/abstract_controller/rendering.rb +9 -9
  16. data/lib/abstract_controller/translation.rb +12 -5
  17. data/lib/abstract_controller/url_for.rb +4 -6
  18. data/lib/abstract_controller.rb +2 -0
  19. data/lib/action_controller/api.rb +5 -4
  20. data/lib/action_controller/base.rb +6 -9
  21. data/lib/action_controller/caching.rb +1 -3
  22. data/lib/action_controller/log_subscriber.rb +13 -9
  23. data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
  24. data/lib/action_controller/metal/conditional_get.rb +57 -6
  25. data/lib/action_controller/metal/content_security_policy.rb +2 -3
  26. data/lib/action_controller/metal/cookies.rb +4 -2
  27. data/lib/action_controller/metal/data_streaming.rb +9 -18
  28. data/lib/action_controller/metal/default_headers.rb +17 -0
  29. data/lib/action_controller/metal/etag_with_template_digest.rb +4 -6
  30. data/lib/action_controller/metal/exceptions.rb +55 -12
  31. data/lib/action_controller/metal/flash.rb +10 -6
  32. data/lib/action_controller/metal/head.rb +7 -4
  33. data/lib/action_controller/metal/helpers.rb +15 -6
  34. data/lib/action_controller/metal/http_authentication.rb +41 -39
  35. data/lib/action_controller/metal/implicit_render.rb +5 -15
  36. data/lib/action_controller/metal/instrumentation.rb +59 -55
  37. data/lib/action_controller/metal/live.rb +80 -33
  38. data/lib/action_controller/metal/logging.rb +20 -0
  39. data/lib/action_controller/metal/mime_responds.rb +22 -7
  40. data/lib/action_controller/metal/parameter_encoding.rb +35 -4
  41. data/lib/action_controller/metal/params_wrapper.rb +50 -31
  42. data/lib/action_controller/metal/permissions_policy.rb +46 -0
  43. data/lib/action_controller/metal/redirecting.rb +93 -23
  44. data/lib/action_controller/metal/renderers.rb +4 -4
  45. data/lib/action_controller/metal/rendering.rb +14 -9
  46. data/lib/action_controller/metal/request_forgery_protection.rb +160 -58
  47. data/lib/action_controller/metal/rescue.rb +2 -2
  48. data/lib/action_controller/metal/streaming.rb +1 -4
  49. data/lib/action_controller/metal/strong_parameters.rb +236 -88
  50. data/lib/action_controller/metal/testing.rb +9 -2
  51. data/lib/action_controller/metal/url_for.rb +1 -1
  52. data/lib/action_controller/metal.rb +16 -17
  53. data/lib/action_controller/railtie.rb +49 -6
  54. data/lib/action_controller/railties/helpers.rb +1 -1
  55. data/lib/action_controller/renderer.rb +37 -13
  56. data/lib/action_controller/template_assertions.rb +1 -1
  57. data/lib/action_controller/test_case.rb +98 -68
  58. data/lib/action_controller.rb +4 -5
  59. data/lib/action_dispatch/http/cache.rb +45 -32
  60. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  61. data/lib/action_dispatch/http/content_security_policy.rb +69 -56
  62. data/lib/action_dispatch/http/filter_parameters.rb +14 -8
  63. data/lib/action_dispatch/http/filter_redirect.rb +2 -3
  64. data/lib/action_dispatch/http/headers.rb +4 -4
  65. data/lib/action_dispatch/http/mime_negotiation.rb +44 -16
  66. data/lib/action_dispatch/http/mime_type.rb +47 -30
  67. data/lib/action_dispatch/http/parameters.rb +18 -27
  68. data/lib/action_dispatch/http/permissions_policy.rb +173 -0
  69. data/lib/action_dispatch/http/request.rb +49 -35
  70. data/lib/action_dispatch/http/response.rb +34 -26
  71. data/lib/action_dispatch/http/upload.rb +9 -1
  72. data/lib/action_dispatch/http/url.rb +86 -94
  73. data/lib/action_dispatch/journey/formatter.rb +55 -31
  74. data/lib/action_dispatch/journey/gtg/builder.rb +30 -46
  75. data/lib/action_dispatch/journey/gtg/simulator.rb +15 -8
  76. data/lib/action_dispatch/journey/gtg/transition_table.rb +78 -21
  77. data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
  78. data/lib/action_dispatch/journey/nodes/node.rb +83 -16
  79. data/lib/action_dispatch/journey/parser.rb +13 -13
  80. data/lib/action_dispatch/journey/parser.y +1 -1
  81. data/lib/action_dispatch/journey/path/pattern.rb +42 -34
  82. data/lib/action_dispatch/journey/route.rb +14 -31
  83. data/lib/action_dispatch/journey/router/utils.rb +16 -14
  84. data/lib/action_dispatch/journey/router.rb +27 -35
  85. data/lib/action_dispatch/journey/routes.rb +3 -5
  86. data/lib/action_dispatch/journey/scanner.rb +10 -4
  87. data/lib/action_dispatch/journey/visitors.rb +1 -4
  88. data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
  89. data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
  90. data/lib/action_dispatch/journey.rb +0 -2
  91. data/lib/action_dispatch/middleware/actionable_exceptions.rb +45 -0
  92. data/lib/action_dispatch/middleware/callbacks.rb +2 -4
  93. data/lib/action_dispatch/middleware/cookies.rb +136 -113
  94. data/lib/action_dispatch/middleware/debug_exceptions.rb +47 -68
  95. data/lib/action_dispatch/middleware/debug_locks.rb +8 -8
  96. data/lib/action_dispatch/middleware/debug_view.rb +66 -0
  97. data/lib/action_dispatch/middleware/exception_wrapper.rb +79 -30
  98. data/lib/action_dispatch/middleware/executor.rb +4 -1
  99. data/lib/action_dispatch/middleware/flash.rb +10 -12
  100. data/lib/action_dispatch/middleware/host_authorization.rb +159 -0
  101. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
  102. data/lib/action_dispatch/middleware/remote_ip.rb +30 -20
  103. data/lib/action_dispatch/middleware/request_id.rb +5 -6
  104. data/lib/action_dispatch/middleware/server_timing.rb +33 -0
  105. data/lib/action_dispatch/middleware/session/abstract_store.rb +16 -3
  106. data/lib/action_dispatch/middleware/session/cache_store.rb +11 -6
  107. data/lib/action_dispatch/middleware/session/cookie_store.rb +24 -19
  108. data/lib/action_dispatch/middleware/show_exceptions.rb +20 -11
  109. data/lib/action_dispatch/middleware/ssl.rb +20 -15
  110. data/lib/action_dispatch/middleware/stack.rb +79 -7
  111. data/lib/action_dispatch/middleware/static.rb +150 -94
  112. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  114. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  115. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +6 -11
  116. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  117. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  118. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +46 -36
  119. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +8 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +7 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +25 -6
  122. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  123. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +9 -6
  124. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -1
  125. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +121 -15
  126. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  128. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +5 -5
  129. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +4 -4
  130. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +5 -5
  131. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
  132. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +16 -2
  133. data/lib/action_dispatch/railtie.rb +16 -4
  134. data/lib/action_dispatch/request/session.rb +59 -22
  135. data/lib/action_dispatch/request/utils.rb +28 -2
  136. data/lib/action_dispatch/routing/inspector.rb +102 -54
  137. data/lib/action_dispatch/routing/mapper.rb +184 -156
  138. data/lib/action_dispatch/routing/polymorphic_routes.rb +21 -19
  139. data/lib/action_dispatch/routing/redirection.rb +4 -6
  140. data/lib/action_dispatch/routing/route_set.rb +83 -73
  141. data/lib/action_dispatch/routing/routes_proxy.rb +1 -1
  142. data/lib/action_dispatch/routing/url_for.rb +2 -3
  143. data/lib/action_dispatch/routing.rb +23 -22
  144. data/lib/action_dispatch/system_test_case.rb +65 -16
  145. data/lib/action_dispatch/system_testing/browser.rb +43 -16
  146. data/lib/action_dispatch/system_testing/driver.rb +42 -10
  147. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +58 -12
  148. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +3 -10
  149. data/lib/action_dispatch/testing/assertion_response.rb +0 -1
  150. data/lib/action_dispatch/testing/assertions/response.rb +4 -7
  151. data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
  152. data/lib/action_dispatch/testing/assertions.rb +3 -6
  153. data/lib/action_dispatch/testing/integration.rb +61 -30
  154. data/lib/action_dispatch/testing/request_encoder.rb +2 -2
  155. data/lib/action_dispatch/testing/test_process.rb +8 -6
  156. data/lib/action_dispatch/testing/test_request.rb +3 -3
  157. data/lib/action_dispatch/testing/test_response.rb +4 -32
  158. data/lib/action_dispatch.rb +15 -7
  159. data/lib/action_pack/gem_version.rb +4 -4
  160. data/lib/action_pack.rb +1 -1
  161. metadata +44 -25
  162. data/lib/action_controller/metal/force_ssl.rb +0 -99
  163. data/lib/action_dispatch/http/parameter_filter.rb +0 -86
  164. data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
  165. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
  166. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
  167. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -6,6 +6,7 @@ module ActionDispatch
6
6
  class Request
7
7
  # Session is responsible for lazily loading the session from store.
8
8
  class Session # :nodoc:
9
+ DisabledSessionError = Class.new(StandardError)
9
10
  ENV_SESSION_KEY = Rack::RACK_SESSION # :nodoc:
10
11
  ENV_SESSION_OPTIONS_KEY = Rack::RACK_SESSION_OPTIONS # :nodoc:
11
12
 
@@ -23,6 +24,12 @@ module ActionDispatch
23
24
  session
24
25
  end
25
26
 
27
+ def self.disabled(req)
28
+ new(nil, req, enabled: false).tap do
29
+ Session::Options.set(req, Session::Options.new(nil, { id: nil }))
30
+ end
31
+ end
32
+
26
33
  def self.find(req)
27
34
  req.get_header ENV_SESSION_KEY
28
35
  end
@@ -31,7 +38,11 @@ module ActionDispatch
31
38
  req.set_header ENV_SESSION_KEY, session
32
39
  end
33
40
 
34
- class Options #:nodoc:
41
+ def self.delete(req)
42
+ req.delete_header ENV_SESSION_KEY
43
+ end
44
+
45
+ class Options # :nodoc:
35
46
  def self.set(req, options)
36
47
  req.set_header ENV_SESSION_OPTIONS_KEY, options
37
48
  end
@@ -60,37 +71,59 @@ module ActionDispatch
60
71
  def values_at(*args); @delegate.values_at(*args); end
61
72
  end
62
73
 
63
- def initialize(by, req)
74
+ def initialize(by, req, enabled: true)
64
75
  @by = by
65
76
  @req = req
66
77
  @delegate = {}
67
78
  @loaded = false
68
79
  @exists = nil # We haven't checked yet.
80
+ @enabled = enabled
69
81
  end
70
82
 
71
83
  def id
72
84
  options.id(@req)
73
85
  end
74
86
 
87
+ def enabled?
88
+ @enabled
89
+ end
90
+
75
91
  def options
76
92
  Options.find @req
77
93
  end
78
94
 
79
95
  def destroy
80
96
  clear
81
- options = self.options || {}
82
- @by.send(:delete_session, @req, options.id(@req), options)
83
97
 
84
- # Load the new sid to be written with the response.
85
- @loaded = false
86
- load_for_write!
98
+ if enabled?
99
+ options = self.options || {}
100
+ @by.send(:delete_session, @req, options.id(@req), options)
101
+
102
+ # Load the new sid to be written with the response.
103
+ @loaded = false
104
+ load_for_write!
105
+ end
87
106
  end
88
107
 
89
108
  # Returns value of the key stored in the session or
90
109
  # +nil+ if the given key is not found in the session.
91
110
  def [](key)
92
111
  load_for_read!
93
- @delegate[key.to_s]
112
+ key = key.to_s
113
+
114
+ if key == "session_id"
115
+ id&.public_id
116
+ else
117
+ @delegate[key]
118
+ end
119
+ end
120
+
121
+ # Returns the nested value specified by the sequence of keys, returning
122
+ # +nil+ if any intermediate step is +nil+.
123
+ def dig(*keys)
124
+ load_for_read!
125
+ keys = keys.map.with_index { |key, i| i.zero? ? key.to_s : key }
126
+ @delegate.dig(*keys)
94
127
  end
95
128
 
96
129
  # Returns true if the session has the given key or false.
@@ -121,7 +154,7 @@ module ActionDispatch
121
154
 
122
155
  # Clears the session.
123
156
  def clear
124
- load_for_write!
157
+ load_for_delete!
125
158
  @delegate.clear
126
159
  end
127
160
 
@@ -144,12 +177,12 @@ module ActionDispatch
144
177
  # # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2", "foo" => "bar"}
145
178
  def update(hash)
146
179
  load_for_write!
147
- @delegate.update stringify_keys(hash)
180
+ @delegate.update hash.stringify_keys
148
181
  end
149
182
 
150
183
  # Deletes given key from the session.
151
184
  def delete(key)
152
- load_for_write!
185
+ load_for_delete!
153
186
  @delegate.delete key.to_s
154
187
  end
155
188
 
@@ -185,6 +218,7 @@ module ActionDispatch
185
218
  end
186
219
 
187
220
  def exists?
221
+ return false unless enabled?
188
222
  return @exists unless @exists.nil?
189
223
  @exists = @by.send(:session_exists?, @req)
190
224
  end
@@ -208,26 +242,29 @@ module ActionDispatch
208
242
  end
209
243
 
210
244
  private
211
-
212
245
  def load_for_read!
213
246
  load! if !loaded? && exists?
214
247
  end
215
248
 
216
249
  def load_for_write!
217
- load! unless loaded?
250
+ if enabled?
251
+ load! unless loaded?
252
+ else
253
+ raise DisabledSessionError, "Your application has sessions disabled. To write to the session you must first configure a session store"
254
+ end
218
255
  end
219
256
 
220
- def load!
221
- id, session = @by.load_session @req
222
- options[:id] = id
223
- @delegate.replace(stringify_keys(session))
224
- @loaded = true
257
+ def load_for_delete!
258
+ load! if enabled? && !loaded?
225
259
  end
226
260
 
227
- def stringify_keys(other)
228
- other.each_with_object({}) { |(key, value), hash|
229
- hash[key.to_s] = value
230
- }
261
+ def load!
262
+ if enabled?
263
+ id, session = @by.load_session @req
264
+ options[:id] = id
265
+ @delegate.replace(session.stringify_keys)
266
+ end
267
+ @loaded = true
231
268
  end
232
269
  end
233
270
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/hash/indifferent_access"
4
+
3
5
  module ActionDispatch
4
6
  class Request
5
7
  class Utils # :nodoc:
@@ -39,6 +41,10 @@ module ActionDispatch
39
41
  end
40
42
  end
41
43
 
44
+ def self.set_binary_encoding(request, params, controller, action)
45
+ CustomParamEncoder.encode(request, params, controller, action)
46
+ end
47
+
42
48
  class ParamEncoder # :nodoc:
43
49
  # Convert nested Hash to HashWithIndifferentAccess.
44
50
  def self.normalize_encode_params(params)
@@ -49,8 +55,8 @@ module ActionDispatch
49
55
  if params.has_key?(:tempfile)
50
56
  ActionDispatch::Http::UploadedFile.new(params)
51
57
  else
52
- params.each_with_object({}) do |(key, val), new_hash|
53
- new_hash[key] = normalize_encode_params(val)
58
+ params.transform_values do |val|
59
+ normalize_encode_params(val)
54
60
  end.with_indifferent_access
55
61
  end
56
62
  else
@@ -71,6 +77,26 @@ module ActionDispatch
71
77
  list
72
78
  end
73
79
  end
80
+
81
+ class CustomParamEncoder # :nodoc:
82
+ def self.encode(request, params, controller, action)
83
+ return params unless controller && controller.valid_encoding? && encoding_template = action_encoding_template(request, controller, action)
84
+ params.except(:controller, :action).each do |key, value|
85
+ ActionDispatch::Request::Utils.each_param_value(value) do |param|
86
+ if encoding_template[key.to_s]
87
+ param.force_encoding(encoding_template[key.to_s])
88
+ end
89
+ end
90
+ end
91
+ params
92
+ end
93
+
94
+ def self.action_encoding_template(request, controller, action) # :nodoc:
95
+ request.controller_class_for(controller).action_encoding_template(action)
96
+ rescue MissingController
97
+ nil
98
+ end
99
+ end
74
100
  end
75
101
  end
76
102
  end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "delegate"
4
- require "active_support/core_ext/string/strip"
4
+ require "io/console/size"
5
5
 
6
6
  module ActionDispatch
7
7
  module Routing
8
- class RouteWrapper < SimpleDelegator
8
+ class RouteWrapper < SimpleDelegator # :nodoc:
9
9
  def endpoint
10
10
  app.dispatcher? ? "#{controller}##{action}" : rack_app.inspect
11
11
  end
@@ -53,7 +53,7 @@ module ActionDispatch
53
53
 
54
54
  ##
55
55
  # This class is just used for displaying route information when someone
56
- # executes `rails routes` or looks at the RoutingError page.
56
+ # executes `bin/rails routes` or looks at the RoutingError page.
57
57
  # People should not use this class.
58
58
  class RoutesInspector # :nodoc:
59
59
  def initialize(routes)
@@ -61,11 +61,11 @@ module ActionDispatch
61
61
  @routes = routes
62
62
  end
63
63
 
64
- def format(formatter, filter = nil)
64
+ def format(formatter, filter = {})
65
65
  routes_to_display = filter_routes(normalize_filter(filter))
66
66
  routes = collect_routes(routes_to_display)
67
67
  if routes.none?
68
- formatter.no_routes(collect_routes(@routes))
68
+ formatter.no_routes(collect_routes(@routes), filter)
69
69
  return formatter.result
70
70
  end
71
71
 
@@ -81,12 +81,12 @@ module ActionDispatch
81
81
  end
82
82
 
83
83
  private
84
-
85
84
  def normalize_filter(filter)
86
- if filter.is_a?(Hash) && filter[:controller]
87
- { controller: /#{filter[:controller].downcase.sub(/_?controller\z/, '').sub('::', '/')}/ }
88
- elsif filter
89
- { controller: /#{filter}/, action: /#{filter}/, verb: /#{filter}/, name: /#{filter}/, path: /#{filter}/ }
85
+ if filter[:controller]
86
+ { controller: /#{filter[:controller].underscore.sub(/_?controller\z/, "")}/ }
87
+ elsif filter[:grep]
88
+ { controller: /#{filter[:grep]}/, action: /#{filter[:grep]}/,
89
+ verb: /#{filter[:grep]}/, name: /#{filter[:grep]}/, path: /#{filter[:grep]}/ }
90
90
  end
91
91
  end
92
92
 
@@ -94,7 +94,7 @@ module ActionDispatch
94
94
  if filter
95
95
  @routes.select do |route|
96
96
  route_wrapper = RouteWrapper.new(route)
97
- filter.any? { |default, value| route_wrapper.send(default) =~ value }
97
+ filter.any? { |default, value| value.match?(route_wrapper.send(default)) }
98
98
  end
99
99
  else
100
100
  @routes
@@ -126,62 +126,110 @@ module ActionDispatch
126
126
  end
127
127
  end
128
128
 
129
- class ConsoleFormatter
130
- def initialize
131
- @buffer = []
132
- end
129
+ module ConsoleFormatter
130
+ class Base
131
+ def initialize
132
+ @buffer = []
133
+ end
133
134
 
134
- def result
135
- @buffer.join("\n")
136
- end
135
+ def result
136
+ @buffer.join("\n")
137
+ end
137
138
 
138
- def section_title(title)
139
- @buffer << "\n#{title}:"
140
- end
139
+ def section_title(title)
140
+ end
141
141
 
142
- def section(routes)
143
- @buffer << draw_section(routes)
144
- end
142
+ def section(routes)
143
+ end
145
144
 
146
- def header(routes)
147
- @buffer << draw_header(routes)
148
- end
145
+ def header(routes)
146
+ end
149
147
 
150
- def no_routes(routes)
151
- @buffer <<
152
- if routes.none?
153
- <<-MESSAGE.strip_heredoc
154
- You don't have any routes defined!
148
+ def no_routes(routes, filter)
149
+ @buffer <<
150
+ if routes.none?
151
+ <<~MESSAGE
152
+ You don't have any routes defined!
153
+
154
+ Please add some routes in config/routes.rb.
155
+ MESSAGE
156
+ elsif filter.key?(:controller)
157
+ "No routes were found for this controller."
158
+ elsif filter.key?(:grep)
159
+ "No routes were found for this grep pattern."
160
+ end
155
161
 
156
- Please add some routes in config/routes.rb.
157
- MESSAGE
158
- else
159
- "No routes were found for this controller"
162
+ @buffer << "For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html."
160
163
  end
161
- @buffer << "For more information about routes, see the Rails guide: http://guides.rubyonrails.org/routing.html."
162
164
  end
163
165
 
164
- private
165
- def draw_section(routes)
166
- header_lengths = ["Prefix", "Verb", "URI Pattern"].map(&:length)
167
- name_width, verb_width, path_width = widths(routes).zip(header_lengths).map(&:max)
166
+ class Sheet < Base
167
+ def section_title(title)
168
+ @buffer << "\n#{title}:"
169
+ end
168
170
 
169
- routes.map do |r|
170
- "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
171
- end
171
+ def section(routes)
172
+ @buffer << draw_section(routes)
173
+ end
174
+
175
+ def header(routes)
176
+ @buffer << draw_header(routes)
172
177
  end
173
178
 
174
- def draw_header(routes)
175
- name_width, verb_width, path_width = widths(routes)
179
+ private
180
+ def draw_section(routes)
181
+ header_lengths = ["Prefix", "Verb", "URI Pattern"].map(&:length)
182
+ name_width, verb_width, path_width = widths(routes).zip(header_lengths).map(&:max)
183
+
184
+ routes.map do |r|
185
+ "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
186
+ end
187
+ end
188
+
189
+ def draw_header(routes)
190
+ name_width, verb_width, path_width = widths(routes)
191
+
192
+ "#{"Prefix".rjust(name_width)} #{"Verb".ljust(verb_width)} #{"URI Pattern".ljust(path_width)} Controller#Action"
193
+ end
194
+
195
+ def widths(routes)
196
+ [routes.map { |r| r[:name].length }.max || 0,
197
+ routes.map { |r| r[:verb].length }.max || 0,
198
+ routes.map { |r| r[:path].length }.max || 0]
199
+ end
200
+ end
176
201
 
177
- "#{"Prefix".rjust(name_width)} #{"Verb".ljust(verb_width)} #{"URI Pattern".ljust(path_width)} Controller#Action"
202
+ class Expanded < Base
203
+ def initialize(width: IO.console_size[1])
204
+ @width = width
205
+ super()
178
206
  end
179
207
 
180
- def widths(routes)
181
- [routes.map { |r| r[:name].length }.max || 0,
182
- routes.map { |r| r[:verb].length }.max || 0,
183
- routes.map { |r| r[:path].length }.max || 0]
208
+ def section_title(title)
209
+ @buffer << "\n#{"[ #{title} ]"}"
184
210
  end
211
+
212
+ def section(routes)
213
+ @buffer << draw_expanded_section(routes)
214
+ end
215
+
216
+ private
217
+ def draw_expanded_section(routes)
218
+ routes.map.each_with_index do |r, i|
219
+ <<~MESSAGE.chomp
220
+ #{route_header(index: i + 1)}
221
+ Prefix | #{r[:name]}
222
+ Verb | #{r[:verb]}
223
+ URI | #{r[:path]}
224
+ Controller#Action | #{r[:reqs]}
225
+ MESSAGE
226
+ end
227
+ end
228
+
229
+ def route_header(index:)
230
+ "--[ Route #{index} ]".ljust(@width, "-")
231
+ end
232
+ end
185
233
  end
186
234
 
187
235
  class HtmlTableFormatter
@@ -203,16 +251,16 @@ module ActionDispatch
203
251
  end
204
252
 
205
253
  def no_routes(*)
206
- @buffer << <<-MESSAGE.strip_heredoc
254
+ @buffer << <<~MESSAGE
207
255
  <p>You don't have any routes defined!</p>
208
256
  <ul>
209
257
  <li>Please add some routes in <tt>config/routes.rb</tt>.</li>
210
258
  <li>
211
259
  For more information about routes, please see the Rails guide
212
- <a href="http://guides.rubyonrails.org/routing.html">Rails Routing from the Outside In</a>.
260
+ <a href="https://guides.rubyonrails.org/routing.html">Rails Routing from the Outside In</a>.
213
261
  </li>
214
262
  </ul>
215
- MESSAGE
263
+ MESSAGE
216
264
  end
217
265
 
218
266
  def result