actionpack 6.0.4.7 → 6.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +235 -331
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/abstract_controller/base.rb +35 -2
- data/lib/abstract_controller/callbacks.rb +2 -2
- data/lib/abstract_controller/helpers.rb +105 -90
- data/lib/abstract_controller/rendering.rb +9 -9
- data/lib/abstract_controller/translation.rb +8 -2
- data/lib/abstract_controller.rb +1 -0
- data/lib/action_controller/api.rb +2 -2
- data/lib/action_controller/base.rb +4 -2
- data/lib/action_controller/caching.rb +0 -1
- data/lib/action_controller/log_subscriber.rb +3 -3
- data/lib/action_controller/metal/conditional_get.rb +10 -2
- data/lib/action_controller/metal/content_security_policy.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +1 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +2 -4
- data/lib/action_controller/metal/exceptions.rb +33 -0
- data/lib/action_controller/metal/feature_policy.rb +46 -0
- data/lib/action_controller/metal/head.rb +7 -4
- data/lib/action_controller/metal/helpers.rb +11 -1
- data/lib/action_controller/metal/http_authentication.rb +5 -3
- data/lib/action_controller/metal/implicit_render.rb +1 -1
- data/lib/action_controller/metal/instrumentation.rb +11 -9
- data/lib/action_controller/metal/live.rb +1 -1
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +6 -2
- data/lib/action_controller/metal/parameter_encoding.rb +35 -4
- data/lib/action_controller/metal/params_wrapper.rb +16 -11
- data/lib/action_controller/metal/redirecting.rb +1 -1
- data/lib/action_controller/metal/rendering.rb +6 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +1 -1
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/strong_parameters.rb +103 -15
- data/lib/action_controller/metal.rb +2 -2
- data/lib/action_controller/renderer.rb +24 -13
- data/lib/action_controller/test_case.rb +62 -56
- data/lib/action_controller.rb +2 -3
- data/lib/action_dispatch/http/cache.rb +12 -10
- data/lib/action_dispatch/http/content_security_policy.rb +5 -1
- data/lib/action_dispatch/http/feature_policy.rb +168 -0
- data/lib/action_dispatch/http/filter_parameters.rb +1 -1
- data/lib/action_dispatch/http/filter_redirect.rb +1 -1
- data/lib/action_dispatch/http/headers.rb +3 -2
- data/lib/action_dispatch/http/mime_negotiation.rb +14 -8
- data/lib/action_dispatch/http/mime_type.rb +29 -16
- data/lib/action_dispatch/http/parameters.rb +1 -19
- data/lib/action_dispatch/http/request.rb +24 -8
- data/lib/action_dispatch/http/response.rb +17 -16
- data/lib/action_dispatch/http/url.rb +3 -2
- data/lib/action_dispatch/journey/formatter.rb +53 -28
- data/lib/action_dispatch/journey/gtg/builder.rb +22 -36
- data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -4
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
- data/lib/action_dispatch/journey/nodes/node.rb +4 -3
- data/lib/action_dispatch/journey/parser.rb +13 -13
- data/lib/action_dispatch/journey/parser.y +1 -1
- data/lib/action_dispatch/journey/path/pattern.rb +13 -18
- data/lib/action_dispatch/journey/route.rb +7 -18
- data/lib/action_dispatch/journey/router/utils.rb +6 -4
- data/lib/action_dispatch/journey/router.rb +26 -30
- data/lib/action_dispatch/journey.rb +0 -2
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +1 -1
- data/lib/action_dispatch/middleware/cookies.rb +67 -32
- data/lib/action_dispatch/middleware/debug_exceptions.rb +8 -15
- data/lib/action_dispatch/middleware/debug_view.rb +1 -1
- data/lib/action_dispatch/middleware/exception_wrapper.rb +28 -16
- data/lib/action_dispatch/middleware/executor.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +35 -35
- data/lib/action_dispatch/middleware/remote_ip.rb +5 -4
- data/lib/action_dispatch/middleware/request_id.rb +4 -5
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -2
- data/lib/action_dispatch/middleware/session/cookie_store.rb +2 -2
- data/lib/action_dispatch/middleware/ssl.rb +9 -6
- data/lib/action_dispatch/middleware/stack.rb +18 -0
- data/lib/action_dispatch/middleware/static.rb +154 -93
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +18 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +2 -5
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +88 -8
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +12 -1
- data/lib/action_dispatch/railtie.rb +3 -2
- data/lib/action_dispatch/request/session.rb +2 -8
- data/lib/action_dispatch/request/utils.rb +26 -2
- data/lib/action_dispatch/routing/inspector.rb +8 -7
- data/lib/action_dispatch/routing/mapper.rb +102 -71
- data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -19
- data/lib/action_dispatch/routing/redirection.rb +3 -3
- data/lib/action_dispatch/routing/route_set.rb +49 -41
- data/lib/action_dispatch/system_test_case.rb +29 -24
- data/lib/action_dispatch/system_testing/browser.rb +33 -27
- data/lib/action_dispatch/system_testing/driver.rb +6 -7
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +47 -6
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +4 -7
- data/lib/action_dispatch/testing/assertions/response.rb +2 -4
- data/lib/action_dispatch/testing/assertions/routing.rb +5 -5
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/integration.rb +38 -27
- data/lib/action_dispatch/testing/test_process.rb +29 -4
- data/lib/action_dispatch/testing/test_request.rb +3 -3
- data/lib/action_dispatch.rb +3 -2
- data/lib/action_pack/gem_version.rb +3 -3
- data/lib/action_pack.rb +1 -1
- metadata +23 -24
- data/lib/action_controller/metal/force_ssl.rb +0 -58
- data/lib/action_dispatch/http/parameter_filter.rb +0 -12
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -119
@@ -0,0 +1,18 @@
|
|
1
|
+
<% if exception.respond_to?(:original_message) && exception.respond_to?(:corrections) %>
|
2
|
+
<h2><%= h exception.original_message %></h2>
|
3
|
+
<%
|
4
|
+
# The 'did_you_mean' gem can raise exceptions when calling #corrections on
|
5
|
+
# the exception. If it does there are no corrections to show.
|
6
|
+
corrections = exception.corrections rescue []
|
7
|
+
%>
|
8
|
+
<% if corrections.any? %>
|
9
|
+
<b>Did you mean?</b>
|
10
|
+
<ul>
|
11
|
+
<% corrections.each do |correction| %>
|
12
|
+
<li style="list-style-type: none"><%= h correction %></li>
|
13
|
+
<% end %>
|
14
|
+
</ul>
|
15
|
+
<% end %>
|
16
|
+
<% else %>
|
17
|
+
<h2><%= h exception.message %></h2>
|
18
|
+
<% end %>
|
@@ -8,11 +8,8 @@
|
|
8
8
|
</header>
|
9
9
|
|
10
10
|
<div id="container">
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
<%= render "rescues/actions", exception: @exception, request: @request %>
|
15
|
-
</h2>
|
11
|
+
<%= render "rescues/message_and_suggestions", exception: @exception %>
|
12
|
+
<%= render "rescues/actions", exception: @exception, request: @request %>
|
16
13
|
|
17
14
|
<%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx, error_index: 0 %>
|
18
15
|
<%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show, error_index: 0 %>
|
@@ -11,10 +11,10 @@
|
|
11
11
|
<h2>
|
12
12
|
<%= h @exception.message %>
|
13
13
|
<% if defined?(ActiveStorage) && @exception.message.match?(%r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}}) %>
|
14
|
-
<br />To resolve this issue run: rails active_storage:install
|
14
|
+
<br />To resolve this issue run: bin/rails active_storage:install
|
15
15
|
<% end %>
|
16
16
|
<% if defined?(ActionMailbox) && @exception.message.match?(%r{#{ActionMailbox::InboundEmail.table_name}}) %>
|
17
|
-
<br />To resolve this issue run: rails action_mailbox:install
|
17
|
+
<br />To resolve this issue run: bin/rails action_mailbox:install
|
18
18
|
<% end %>
|
19
19
|
</h2>
|
20
20
|
|
@@ -5,10 +5,9 @@
|
|
5
5
|
|
6
6
|
<%= @exception.message %>
|
7
7
|
<% if defined?(ActiveStorage) && @exception.message.match?(%r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}}) %>
|
8
|
-
To resolve this issue run: rails active_storage:install
|
9
|
-
<% end %>
|
8
|
+
To resolve this issue run: bin/rails active_storage:install
|
10
9
|
<% if defined?(ActionMailbox) && @exception.message.match?(%r{#{ActionMailbox::InboundEmail.table_name}}) %>
|
11
|
-
To resolve this issue run: rails action_mailbox:install
|
10
|
+
To resolve this issue run: bin/rails action_mailbox:install
|
12
11
|
<% end %>
|
13
12
|
|
14
13
|
<%= render template: "rescues/_source" %>
|
@@ -2,11 +2,14 @@
|
|
2
2
|
<html lang="en">
|
3
3
|
<head>
|
4
4
|
<meta charset="utf-8" />
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
5
6
|
<title>Action Controller: Exception caught</title>
|
6
7
|
<style>
|
7
8
|
body {
|
8
9
|
background-color: #FAFAFA;
|
9
10
|
color: #333;
|
11
|
+
color-scheme: light dark;
|
12
|
+
supported-color-schemes: light dark;
|
10
13
|
margin: 0px;
|
11
14
|
}
|
12
15
|
|
@@ -30,18 +33,19 @@
|
|
30
33
|
|
31
34
|
header {
|
32
35
|
color: #F0F0F0;
|
33
|
-
background: #
|
36
|
+
background: #C00;
|
34
37
|
padding: 0.5em 1.5em;
|
35
38
|
}
|
36
39
|
|
37
40
|
h1 {
|
41
|
+
overflow-wrap: break-word;
|
38
42
|
margin: 0.2em 0;
|
39
43
|
line-height: 1.1em;
|
40
44
|
font-size: 2em;
|
41
45
|
}
|
42
46
|
|
43
47
|
h2 {
|
44
|
-
color: #
|
48
|
+
color: #C00;
|
45
49
|
line-height: 25px;
|
46
50
|
}
|
47
51
|
|
@@ -50,7 +54,7 @@
|
|
50
54
|
border-radius: 4px;
|
51
55
|
margin: 1em 0px;
|
52
56
|
display: block;
|
53
|
-
width: 978px;
|
57
|
+
max-width: 978px;
|
54
58
|
}
|
55
59
|
|
56
60
|
.summary {
|
@@ -78,7 +82,7 @@
|
|
78
82
|
.source {
|
79
83
|
border: 1px solid #D9D9D9;
|
80
84
|
background: #ECECEC;
|
81
|
-
width: 978px;
|
85
|
+
max-width: 978px;
|
82
86
|
}
|
83
87
|
|
84
88
|
.source pre {
|
@@ -114,22 +118,98 @@
|
|
114
118
|
}
|
115
119
|
|
116
120
|
.line.active {
|
117
|
-
background-color: #
|
121
|
+
background-color: #FCC;
|
118
122
|
}
|
119
123
|
|
120
124
|
.button_to {
|
121
125
|
display: inline-block;
|
126
|
+
margin-top: 0.75em;
|
127
|
+
margin-bottom: 0.75em;
|
122
128
|
}
|
123
129
|
|
124
130
|
.hidden {
|
125
131
|
display: none;
|
126
132
|
}
|
127
133
|
|
134
|
+
input[type="submit"] {
|
135
|
+
color: white;
|
136
|
+
background-color: #C00;
|
137
|
+
border: none;
|
138
|
+
border-radius: 12px;
|
139
|
+
box-shadow: 0 3px #F99;
|
140
|
+
font-size: 13px;
|
141
|
+
font-weight: bold;
|
142
|
+
margin: 0;
|
143
|
+
padding: 10px 18px;
|
144
|
+
-webkit-appearance: none;
|
145
|
+
}
|
146
|
+
input[type="submit"]:focus,
|
147
|
+
input[type="submit"]:hover {
|
148
|
+
opacity: 0.8;
|
149
|
+
}
|
150
|
+
input[type="submit"]:active {
|
151
|
+
box-shadow: 0 2px #F99;
|
152
|
+
transform: translateY(1px)
|
153
|
+
}
|
154
|
+
|
155
|
+
|
128
156
|
a { color: #980905; }
|
129
157
|
a:visited { color: #666; }
|
130
|
-
a.trace-frames {
|
131
|
-
|
132
|
-
|
158
|
+
a.trace-frames {
|
159
|
+
color: #666;
|
160
|
+
overflow-wrap: break-word;
|
161
|
+
}
|
162
|
+
a:hover { color: #C00; }
|
163
|
+
a.trace-frames.selected { color: #C00 }
|
164
|
+
|
165
|
+
@media (prefers-color-scheme: dark) {
|
166
|
+
body {
|
167
|
+
background-color: #222;
|
168
|
+
color: #ECECEC;
|
169
|
+
}
|
170
|
+
|
171
|
+
.details {
|
172
|
+
border-color: #666;
|
173
|
+
}
|
174
|
+
|
175
|
+
.summary {
|
176
|
+
border-color: #666;
|
177
|
+
}
|
178
|
+
|
179
|
+
.source {
|
180
|
+
border-color: #555;
|
181
|
+
background-color: #333;
|
182
|
+
}
|
183
|
+
|
184
|
+
.source .data {
|
185
|
+
background: #444;
|
186
|
+
}
|
187
|
+
|
188
|
+
.source .data .line_numbers {
|
189
|
+
background: #333;
|
190
|
+
border-color: #222;
|
191
|
+
}
|
192
|
+
|
193
|
+
.line:hover {
|
194
|
+
background: #666;
|
195
|
+
}
|
196
|
+
|
197
|
+
.line.active {
|
198
|
+
background-color: #900;
|
199
|
+
}
|
200
|
+
|
201
|
+
input[type="submit"] {
|
202
|
+
box-shadow: 0 3px #800;
|
203
|
+
}
|
204
|
+
input[type="submit"]:active {
|
205
|
+
box-shadow: 0 2px #800;
|
206
|
+
}
|
207
|
+
|
208
|
+
a { color: #C00; }
|
209
|
+
a.trace-frames { color: #999; }
|
210
|
+
a:hover { color: #E9382B; }
|
211
|
+
a.trace-frames.selected { color: #E9382B; }
|
212
|
+
}
|
133
213
|
|
134
214
|
<%= yield :style %>
|
135
215
|
</style>
|
@@ -49,6 +49,17 @@
|
|
49
49
|
width: 80%;
|
50
50
|
font-size: inherit;
|
51
51
|
}
|
52
|
+
|
53
|
+
@media (prefers-color-scheme: dark) {
|
54
|
+
#route_table tbody tr:nth-child(odd) {
|
55
|
+
background: #333;
|
56
|
+
}
|
57
|
+
|
58
|
+
#route_table tbody.exact_matches,
|
59
|
+
#route_table tbody.fuzzy_matches {
|
60
|
+
color: #333;
|
61
|
+
}
|
62
|
+
}
|
52
63
|
<% end %>
|
53
64
|
|
54
65
|
<table id='route_table' class='route_table'>
|
@@ -85,7 +96,7 @@
|
|
85
96
|
</table>
|
86
97
|
|
87
98
|
<script type='text/javascript'>
|
88
|
-
// support
|
99
|
+
// support forEach iterator on NodeList
|
89
100
|
NodeList.prototype.forEach = Array.prototype.forEach;
|
90
101
|
|
91
102
|
// Enables path search functionality
|
@@ -23,7 +23,7 @@ module ActionDispatch
|
|
23
23
|
config.action_dispatch.use_authenticated_cookie_encryption = false
|
24
24
|
config.action_dispatch.use_cookies_with_metadata = false
|
25
25
|
config.action_dispatch.perform_deep_munge = true
|
26
|
-
config.action_dispatch.
|
26
|
+
config.action_dispatch.request_id_header = "X-Request-Id"
|
27
27
|
|
28
28
|
config.action_dispatch.default_headers = {
|
29
29
|
"X-Frame-Options" => "SAMEORIGIN",
|
@@ -39,13 +39,14 @@ module ActionDispatch
|
|
39
39
|
config.eager_load_namespaces << ActionDispatch
|
40
40
|
|
41
41
|
initializer "action_dispatch.configure" do |app|
|
42
|
+
ActionDispatch::Http::URL.secure_protocol = app.config.force_ssl
|
42
43
|
ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length
|
43
44
|
ActionDispatch::Request.ignore_accept_header = app.config.action_dispatch.ignore_accept_header
|
44
45
|
ActionDispatch::Request::Utils.perform_deep_munge = app.config.action_dispatch.perform_deep_munge
|
46
|
+
|
45
47
|
ActiveSupport.on_load(:action_dispatch_response) do
|
46
48
|
self.default_charset = app.config.action_dispatch.default_charset || app.config.encoding
|
47
49
|
self.default_headers = app.config.action_dispatch.default_headers
|
48
|
-
self.return_only_media_type_on_content_type = app.config.action_dispatch.return_only_media_type_on_content_type
|
49
50
|
end
|
50
51
|
|
51
52
|
ActionDispatch::ExceptionWrapper.rescue_responses.merge!(config.action_dispatch.rescue_responses)
|
@@ -158,7 +158,7 @@ module ActionDispatch
|
|
158
158
|
# # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2", "foo" => "bar"}
|
159
159
|
def update(hash)
|
160
160
|
load_for_write!
|
161
|
-
@delegate.update stringify_keys
|
161
|
+
@delegate.update hash.stringify_keys
|
162
162
|
end
|
163
163
|
|
164
164
|
# Deletes given key from the session.
|
@@ -233,15 +233,9 @@ module ActionDispatch
|
|
233
233
|
def load!
|
234
234
|
id, session = @by.load_session @req
|
235
235
|
options[:id] = id
|
236
|
-
@delegate.replace(stringify_keys
|
236
|
+
@delegate.replace(session.stringify_keys)
|
237
237
|
@loaded = true
|
238
238
|
end
|
239
|
-
|
240
|
-
def stringify_keys(other)
|
241
|
-
other.each_with_object({}) { |(key, value), hash|
|
242
|
-
hash[key.to_s] = value
|
243
|
-
}
|
244
|
-
end
|
245
239
|
end
|
246
240
|
end
|
247
241
|
end
|
@@ -41,6 +41,10 @@ module ActionDispatch
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
def self.set_binary_encoding(request, params, controller, action)
|
45
|
+
CustomParamEncoder.encode(request, params, controller, action)
|
46
|
+
end
|
47
|
+
|
44
48
|
class ParamEncoder # :nodoc:
|
45
49
|
# Convert nested Hash to HashWithIndifferentAccess.
|
46
50
|
def self.normalize_encode_params(params)
|
@@ -51,8 +55,8 @@ module ActionDispatch
|
|
51
55
|
if params.has_key?(:tempfile)
|
52
56
|
ActionDispatch::Http::UploadedFile.new(params)
|
53
57
|
else
|
54
|
-
params.
|
55
|
-
|
58
|
+
params.transform_values do |val|
|
59
|
+
normalize_encode_params(val)
|
56
60
|
end.with_indifferent_access
|
57
61
|
end
|
58
62
|
else
|
@@ -73,6 +77,26 @@ module ActionDispatch
|
|
73
77
|
list
|
74
78
|
end
|
75
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
|
76
100
|
end
|
77
101
|
end
|
78
102
|
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)
|
@@ -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)
|
97
|
+
filter.any? { |default, value| value.match?(route_wrapper.send(default)) }
|
98
98
|
end
|
99
99
|
else
|
100
100
|
@routes
|
@@ -200,6 +200,11 @@ module ActionDispatch
|
|
200
200
|
end
|
201
201
|
|
202
202
|
class Expanded < Base
|
203
|
+
def initialize(width: IO.console_size[1])
|
204
|
+
@width = width
|
205
|
+
super()
|
206
|
+
end
|
207
|
+
|
203
208
|
def section_title(title)
|
204
209
|
@buffer << "\n#{"[ #{title} ]"}"
|
205
210
|
end
|
@@ -222,11 +227,7 @@ module ActionDispatch
|
|
222
227
|
end
|
223
228
|
|
224
229
|
def route_header(index:)
|
225
|
-
|
226
|
-
header_prefix = "--[ Route #{index} ]"
|
227
|
-
dash_remainder = [console_width - header_prefix.size, 0].max
|
228
|
-
|
229
|
-
"#{header_prefix}#{'-' * dash_remainder}"
|
230
|
+
"--[ Route #{index} ]".ljust(@width, "-")
|
230
231
|
end
|
231
232
|
end
|
232
233
|
end
|