actionview 5.2.8.1 → 6.0.6.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.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +280 -94
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -3
- data/lib/action_view/base.rb +108 -11
- data/lib/action_view/buffers.rb +15 -0
- data/lib/action_view/cache_expiry.rb +53 -0
- data/lib/action_view/context.rb +5 -9
- data/lib/action_view/digestor.rb +12 -20
- data/lib/action_view/flows.rb +0 -1
- data/lib/action_view/gem_version.rb +3 -3
- data/lib/action_view/helpers/active_model_helper.rb +0 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +8 -31
- data/lib/action_view/helpers/asset_url_helper.rb +4 -3
- data/lib/action_view/helpers/cache_helper.rb +19 -12
- data/lib/action_view/helpers/capture_helper.rb +4 -0
- data/lib/action_view/helpers/csp_helper.rb +4 -2
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +70 -27
- data/lib/action_view/helpers/form_helper.rb +240 -8
- data/lib/action_view/helpers/form_options_helper.rb +27 -18
- data/lib/action_view/helpers/form_tag_helper.rb +17 -15
- data/lib/action_view/helpers/javascript_helper.rb +9 -8
- data/lib/action_view/helpers/number_helper.rb +8 -2
- data/lib/action_view/helpers/output_safety_helper.rb +1 -1
- data/lib/action_view/helpers/rendering_helper.rb +6 -4
- data/lib/action_view/helpers/sanitize_helper.rb +12 -18
- data/lib/action_view/helpers/tag_helper.rb +8 -7
- data/lib/action_view/helpers/tags/base.rb +9 -6
- data/lib/action_view/helpers/tags/check_box.rb +0 -1
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -1
- data/lib/action_view/helpers/tags/collection_helpers.rb +0 -1
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -1
- data/lib/action_view/helpers/tags/color_field.rb +1 -2
- data/lib/action_view/helpers/tags/date_field.rb +0 -1
- data/lib/action_view/helpers/tags/date_select.rb +0 -1
- data/lib/action_view/helpers/tags/datetime_field.rb +0 -1
- data/lib/action_view/helpers/tags/datetime_local_field.rb +0 -1
- data/lib/action_view/helpers/tags/label.rb +0 -1
- data/lib/action_view/helpers/tags/month_field.rb +0 -1
- data/lib/action_view/helpers/tags/radio_button.rb +0 -1
- data/lib/action_view/helpers/tags/select.rb +0 -1
- data/lib/action_view/helpers/tags/text_field.rb +0 -1
- data/lib/action_view/helpers/tags/time_field.rb +0 -1
- data/lib/action_view/helpers/tags/translator.rb +1 -6
- data/lib/action_view/helpers/tags/week_field.rb +0 -1
- data/lib/action_view/helpers/text_helper.rb +3 -4
- data/lib/action_view/helpers/translation_helper.rb +19 -17
- data/lib/action_view/helpers/url_helper.rb +14 -14
- data/lib/action_view/helpers.rb +0 -2
- data/lib/action_view/layouts.rb +5 -8
- data/lib/action_view/log_subscriber.rb +6 -7
- data/lib/action_view/lookup_context.rb +75 -32
- data/lib/action_view/path_set.rb +5 -11
- data/lib/action_view/railtie.rb +24 -1
- data/lib/action_view/record_identifier.rb +2 -3
- data/lib/action_view/renderer/abstract_renderer.rb +56 -4
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +63 -17
- data/lib/action_view/renderer/partial_renderer.rb +67 -57
- data/lib/action_view/renderer/renderer.rb +16 -4
- data/lib/action_view/renderer/streaming_template_renderer.rb +5 -7
- data/lib/action_view/renderer/template_renderer.rb +25 -20
- data/lib/action_view/rendering.rb +51 -32
- data/lib/action_view/routing_url_for.rb +12 -11
- data/lib/action_view/template/error.rb +30 -15
- data/lib/action_view/template/handlers/builder.rb +2 -2
- data/lib/action_view/template/handlers/erb/erubi.rb +7 -3
- data/lib/action_view/template/handlers/erb.rb +17 -8
- data/lib/action_view/template/handlers/html.rb +1 -1
- data/lib/action_view/template/handlers/raw.rb +2 -2
- data/lib/action_view/template/handlers.rb +27 -1
- data/lib/action_view/template/html.rb +14 -5
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +28 -0
- data/lib/action_view/template/resolver.rb +134 -135
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/text.rb +5 -3
- data/lib/action_view/template.rb +102 -71
- data/lib/action_view/test_case.rb +3 -4
- data/lib/action_view/testing/resolvers.rb +33 -21
- data/lib/action_view/unbound_template.rb +31 -0
- data/lib/action_view/view_paths.rb +25 -2
- data/lib/action_view.rb +4 -2
- data/lib/assets/compiled/rails-ujs.js +30 -4
- metadata +27 -18
- data/lib/action_view/helpers/record_tag_helper.rb +0 -23
@@ -16,13 +16,8 @@ module ActionView
|
|
16
16
|
translated_attribute || human_attribute_name
|
17
17
|
end
|
18
18
|
|
19
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
20
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
21
|
-
protected
|
22
|
-
|
23
|
-
attr_reader :object_name, :method_and_value, :scope, :model
|
24
|
-
|
25
19
|
private
|
20
|
+
attr_reader :object_name, :method_and_value, :scope, :model
|
26
21
|
|
27
22
|
def i18n_default
|
28
23
|
if model
|
@@ -188,7 +188,7 @@ module ActionView
|
|
188
188
|
|
189
189
|
unless separator.empty?
|
190
190
|
text.split(separator).each do |value|
|
191
|
-
if value.match(regex)
|
191
|
+
if value.match?(regex)
|
192
192
|
phrase = value
|
193
193
|
break
|
194
194
|
end
|
@@ -228,7 +228,7 @@ module ActionView
|
|
228
228
|
# pluralize(2, 'Person', locale: :de)
|
229
229
|
# # => 2 Personen
|
230
230
|
def pluralize(count, singular, plural_arg = nil, plural: plural_arg, locale: I18n.locale)
|
231
|
-
word = if
|
231
|
+
word = if count == 1 || count.to_s =~ /^1(\.0+)?$/
|
232
232
|
singular
|
233
233
|
else
|
234
234
|
plural || singular.pluralize(locale)
|
@@ -259,7 +259,7 @@ module ActionView
|
|
259
259
|
# # => Once\r\nupon\r\na\r\ntime
|
260
260
|
def word_wrap(text, line_width: 80, break_sequence: "\n")
|
261
261
|
text.split("\n").collect! do |line|
|
262
|
-
line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1#{break_sequence}").
|
262
|
+
line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1#{break_sequence}").rstrip : line
|
263
263
|
end * break_sequence
|
264
264
|
end
|
265
265
|
|
@@ -426,7 +426,6 @@ module ActionView
|
|
426
426
|
end
|
427
427
|
|
428
428
|
private
|
429
|
-
|
430
429
|
def next_index
|
431
430
|
step_index(1)
|
432
431
|
end
|
@@ -57,13 +57,10 @@ module ActionView
|
|
57
57
|
# that include HTML tags so that you know what kind of output to expect
|
58
58
|
# when you call translate in a template and translators know which keys
|
59
59
|
# they can provide HTML values for.
|
60
|
-
def translate(key, options
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
if has_default && !remaining_defaults.first.kind_of?(Symbol)
|
66
|
-
options[:default] = remaining_defaults
|
60
|
+
def translate(key, **options)
|
61
|
+
if options.has_key?(:default)
|
62
|
+
remaining_defaults = Array.wrap(options.delete(:default)).compact
|
63
|
+
options[:default] = remaining_defaults unless remaining_defaults.first.kind_of?(Symbol)
|
67
64
|
end
|
68
65
|
|
69
66
|
# If the user has explicitly decided to NOT raise errors, pass that option to I18n.
|
@@ -88,24 +85,26 @@ module ActionView
|
|
88
85
|
|
89
86
|
html_safe_options[:default] = MISSING_TRANSLATION unless html_safe_options[:default].blank?
|
90
87
|
|
91
|
-
translation = I18n.translate(scope_key_by_partial(key), html_safe_options.merge(raise: i18n_raise))
|
88
|
+
translation = I18n.translate(scope_key_by_partial(key), **html_safe_options.merge(raise: i18n_raise))
|
92
89
|
|
93
90
|
if translation.equal?(MISSING_TRANSLATION)
|
94
91
|
options[:default].first
|
92
|
+
elsif translation.respond_to?(:map)
|
93
|
+
translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element }
|
95
94
|
else
|
96
95
|
translation.respond_to?(:html_safe) ? translation.html_safe : translation
|
97
96
|
end
|
98
97
|
else
|
99
|
-
I18n.translate(scope_key_by_partial(key), options.merge(raise: i18n_raise))
|
98
|
+
I18n.translate(scope_key_by_partial(key), **options.merge(raise: i18n_raise))
|
100
99
|
end
|
101
100
|
rescue I18n::MissingTranslationData => e
|
102
101
|
if remaining_defaults.present?
|
103
|
-
translate remaining_defaults.shift, options.merge(default: remaining_defaults)
|
102
|
+
translate remaining_defaults.shift, **options.merge(default: remaining_defaults)
|
104
103
|
else
|
105
104
|
raise e if raise_error
|
106
105
|
|
107
106
|
keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope])
|
108
|
-
title = "translation missing: #{keys.join('.')}"
|
107
|
+
title = +"translation missing: #{keys.join('.')}"
|
109
108
|
|
110
109
|
interpolations = options.except(:default, :scope)
|
111
110
|
if interpolations.any?
|
@@ -121,10 +120,10 @@ module ActionView
|
|
121
120
|
|
122
121
|
# Delegates to <tt>I18n.localize</tt> with no additional functionality.
|
123
122
|
#
|
124
|
-
# See
|
123
|
+
# See https://www.rubydoc.info/github/svenfuchs/i18n/master/I18n/Backend/Base:localize
|
125
124
|
# for more information.
|
126
|
-
def localize(
|
127
|
-
I18n.localize(
|
125
|
+
def localize(object, **options)
|
126
|
+
I18n.localize(object, **options)
|
128
127
|
end
|
129
128
|
alias :l :localize
|
130
129
|
|
@@ -133,9 +132,12 @@ module ActionView
|
|
133
132
|
private_constant :MISSING_TRANSLATION
|
134
133
|
|
135
134
|
def scope_key_by_partial(key)
|
136
|
-
|
135
|
+
stringified_key = key.to_s
|
136
|
+
if stringified_key.first == "."
|
137
137
|
if @virtual_path
|
138
|
-
@
|
138
|
+
@_scope_key_by_partial_cache ||= {}
|
139
|
+
@_scope_key_by_partial_cache[@virtual_path] ||= @virtual_path.gsub(%r{/_?}, ".")
|
140
|
+
"#{@_scope_key_by_partial_cache[@virtual_path]}#{stringified_key}"
|
139
141
|
else
|
140
142
|
raise "Cannot use t(#{key.inspect}) shortcut because path is not available"
|
141
143
|
end
|
@@ -145,7 +147,7 @@ module ActionView
|
|
145
147
|
end
|
146
148
|
|
147
149
|
def html_safe_translation_key?(key)
|
148
|
-
/(
|
150
|
+
/(?:_|\b)html\z/.match?(key.to_s)
|
149
151
|
end
|
150
152
|
end
|
151
153
|
end
|
@@ -200,9 +200,9 @@ module ActionView
|
|
200
200
|
html_options = convert_options_to_data_attributes(options, html_options)
|
201
201
|
|
202
202
|
url = url_for(options)
|
203
|
-
html_options["href"
|
203
|
+
html_options["href"] ||= url
|
204
204
|
|
205
|
-
content_tag("a"
|
205
|
+
content_tag("a", name || url, html_options, &block)
|
206
206
|
end
|
207
207
|
|
208
208
|
# Generates a form containing a single button that submits to the URL created
|
@@ -308,7 +308,7 @@ module ActionView
|
|
308
308
|
params = html_options.delete("params")
|
309
309
|
|
310
310
|
method = html_options.delete("method").to_s
|
311
|
-
method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : "".
|
311
|
+
method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : "".html_safe
|
312
312
|
|
313
313
|
form_method = method == "get" ? "get" : "post"
|
314
314
|
form_options = html_options.delete("form") || {}
|
@@ -321,7 +321,7 @@ module ActionView
|
|
321
321
|
request_method = method.empty? ? "post" : method
|
322
322
|
token_tag(nil, form_options: { action: url, method: request_method })
|
323
323
|
else
|
324
|
-
""
|
324
|
+
""
|
325
325
|
end
|
326
326
|
|
327
327
|
html_options = convert_options_to_data_attributes(options, html_options)
|
@@ -487,12 +487,12 @@ module ActionView
|
|
487
487
|
option = html_options.delete(item).presence || next
|
488
488
|
"#{item.dasherize}=#{ERB::Util.url_encode(option)}"
|
489
489
|
}.compact
|
490
|
-
extras = extras.empty? ? ""
|
490
|
+
extras = extras.empty? ? "" : "?" + extras.join("&")
|
491
491
|
|
492
492
|
encoded_email_address = ERB::Util.url_encode(email_address).gsub("%40", "@")
|
493
493
|
html_options["href"] = "mailto:#{encoded_email_address}#{extras}"
|
494
494
|
|
495
|
-
content_tag("a"
|
495
|
+
content_tag("a", name || email_address, html_options, &block)
|
496
496
|
end
|
497
497
|
|
498
498
|
# True if the current request URI was generated by the given +options+.
|
@@ -553,7 +553,7 @@ module ActionView
|
|
553
553
|
url_string = URI.parser.unescape(url_for(options)).force_encoding(Encoding::BINARY)
|
554
554
|
|
555
555
|
# We ignore any extra parameters in the request_uri if the
|
556
|
-
# submitted
|
556
|
+
# submitted URL doesn't have any either. This lets the function
|
557
557
|
# work with things like ?order=asc
|
558
558
|
# the behaviour can be disabled with check_parameters: true
|
559
559
|
request_uri = url_string.index("?") || check_parameters ? request.fullpath : request.path
|
@@ -575,21 +575,21 @@ module ActionView
|
|
575
575
|
def convert_options_to_data_attributes(options, html_options)
|
576
576
|
if html_options
|
577
577
|
html_options = html_options.stringify_keys
|
578
|
-
html_options["data-remote"] = "true"
|
578
|
+
html_options["data-remote"] = "true" if link_to_remote_options?(options) || link_to_remote_options?(html_options)
|
579
579
|
|
580
|
-
method = html_options.delete("method"
|
580
|
+
method = html_options.delete("method")
|
581
581
|
|
582
582
|
add_method_to_attributes!(html_options, method) if method
|
583
583
|
|
584
584
|
html_options
|
585
585
|
else
|
586
|
-
link_to_remote_options?(options) ? { "data-remote" => "true"
|
586
|
+
link_to_remote_options?(options) ? { "data-remote" => "true" } : {}
|
587
587
|
end
|
588
588
|
end
|
589
589
|
|
590
590
|
def link_to_remote_options?(options)
|
591
591
|
if options.is_a?(Hash)
|
592
|
-
options.delete("remote"
|
592
|
+
options.delete("remote") || options.delete(:remote)
|
593
593
|
end
|
594
594
|
end
|
595
595
|
|
@@ -618,11 +618,11 @@ module ActionView
|
|
618
618
|
end
|
619
619
|
|
620
620
|
def token_tag(token = nil, form_options: {})
|
621
|
-
if token != false && protect_against_forgery?
|
621
|
+
if token != false && defined?(protect_against_forgery?) && protect_against_forgery?
|
622
622
|
token ||= form_authenticity_token(form_options: form_options)
|
623
623
|
tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token)
|
624
624
|
else
|
625
|
-
""
|
625
|
+
""
|
626
626
|
end
|
627
627
|
end
|
628
628
|
|
@@ -636,7 +636,7 @@ module ActionView
|
|
636
636
|
# to_form_params(name: 'David', nationality: 'Danish')
|
637
637
|
# # => [{name: 'name', value: 'David'}, {name: 'nationality', value: 'Danish'}]
|
638
638
|
#
|
639
|
-
# to_form_params(country: {name: 'Denmark'})
|
639
|
+
# to_form_params(country: { name: 'Denmark' })
|
640
640
|
# # => [{name: 'country[name]', value: 'Denmark'}]
|
641
641
|
#
|
642
642
|
# to_form_params(countries: ['Denmark', 'Sweden']})
|
data/lib/action_view/helpers.rb
CHANGED
@@ -23,7 +23,6 @@ module ActionView #:nodoc:
|
|
23
23
|
autoload :JavaScriptHelper, "action_view/helpers/javascript_helper"
|
24
24
|
autoload :NumberHelper
|
25
25
|
autoload :OutputSafetyHelper
|
26
|
-
autoload :RecordTagHelper
|
27
26
|
autoload :RenderingHelper
|
28
27
|
autoload :SanitizeHelper
|
29
28
|
autoload :TagHelper
|
@@ -57,7 +56,6 @@ module ActionView #:nodoc:
|
|
57
56
|
include JavaScriptHelper
|
58
57
|
include NumberHelper
|
59
58
|
include OutputSafetyHelper
|
60
|
-
include RecordTagHelper
|
61
59
|
include RenderingHelper
|
62
60
|
include SanitizeHelper
|
63
61
|
include TagHelper
|
data/lib/action_view/layouts.rb
CHANGED
@@ -224,7 +224,6 @@ module ActionView
|
|
224
224
|
# that if no layout conditions are used, this method is not used
|
225
225
|
module LayoutConditions # :nodoc:
|
226
226
|
private
|
227
|
-
|
228
227
|
# Determines whether the current action has a layout definition by
|
229
228
|
# checking the action name against the :only and :except conditions
|
230
229
|
# set by the <tt>layout</tt> method.
|
@@ -322,7 +321,7 @@ module ActionView
|
|
322
321
|
end
|
323
322
|
|
324
323
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
325
|
-
def _layout(formats)
|
324
|
+
def _layout(lookup_context, formats)
|
326
325
|
if _conditional_layout?
|
327
326
|
#{layout_definition}
|
328
327
|
else
|
@@ -334,7 +333,6 @@ module ActionView
|
|
334
333
|
end
|
335
334
|
|
336
335
|
private
|
337
|
-
|
338
336
|
# If no layout is supplied, look for a template named the return
|
339
337
|
# value of this method.
|
340
338
|
#
|
@@ -372,7 +370,6 @@ module ActionView
|
|
372
370
|
end
|
373
371
|
|
374
372
|
private
|
375
|
-
|
376
373
|
def _conditional_layout?
|
377
374
|
true
|
378
375
|
end
|
@@ -388,8 +385,8 @@ module ActionView
|
|
388
385
|
case name
|
389
386
|
when String then _normalize_layout(name)
|
390
387
|
when Proc then name
|
391
|
-
when true then Proc.new { |formats| _default_layout(formats, true) }
|
392
|
-
when :default then Proc.new { |formats| _default_layout(formats, false) }
|
388
|
+
when true then Proc.new { |lookup_context, formats| _default_layout(lookup_context, formats, true) }
|
389
|
+
when :default then Proc.new { |lookup_context, formats| _default_layout(lookup_context, formats, false) }
|
393
390
|
when false, nil then nil
|
394
391
|
else
|
395
392
|
raise ArgumentError,
|
@@ -411,9 +408,9 @@ module ActionView
|
|
411
408
|
#
|
412
409
|
# ==== Returns
|
413
410
|
# * <tt>template</tt> - The template object for the default layout (or +nil+)
|
414
|
-
def _default_layout(formats, require_layout = false)
|
411
|
+
def _default_layout(lookup_context, formats, require_layout = false)
|
415
412
|
begin
|
416
|
-
value = _layout(formats) if action_has_layout?
|
413
|
+
value = _layout(lookup_context, formats) if action_has_layout?
|
417
414
|
rescue NameError => e
|
418
415
|
raise e, "Could not render layout: #{e.message}"
|
419
416
|
end
|
@@ -16,17 +16,17 @@ module ActionView
|
|
16
16
|
|
17
17
|
def render_template(event)
|
18
18
|
info do
|
19
|
-
message = " Rendered #{from_rails_root(event.payload[:identifier])}"
|
19
|
+
message = +" Rendered #{from_rails_root(event.payload[:identifier])}"
|
20
20
|
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
|
21
|
-
message << " (#{event.duration.round(1)}ms)"
|
21
|
+
message << " (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
25
|
def render_partial(event)
|
26
26
|
info do
|
27
|
-
message = " Rendered #{from_rails_root(event.payload[:identifier])}"
|
27
|
+
message = +" Rendered #{from_rails_root(event.payload[:identifier])}"
|
28
28
|
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
|
29
|
-
message << " (#{event.duration.round(1)}ms)"
|
29
|
+
message << " (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
|
30
30
|
message << " #{cache_message(event.payload)}" unless event.payload[:cache_hit].nil?
|
31
31
|
message
|
32
32
|
end
|
@@ -37,7 +37,7 @@ module ActionView
|
|
37
37
|
|
38
38
|
info do
|
39
39
|
" Rendered collection of #{from_rails_root(identifier)}" \
|
40
|
-
" #{render_count(event.payload)} (#{event.duration.round(1)}ms)"
|
40
|
+
" #{render_count(event.payload)} (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
@@ -54,7 +54,6 @@ module ActionView
|
|
54
54
|
end
|
55
55
|
|
56
56
|
private
|
57
|
-
|
58
57
|
EMPTY = ""
|
59
58
|
def from_rails_root(string) # :doc:
|
60
59
|
string = string.sub(rails_root, EMPTY)
|
@@ -85,7 +84,7 @@ module ActionView
|
|
85
84
|
|
86
85
|
def log_rendering_start(payload)
|
87
86
|
info do
|
88
|
-
message = " Rendering #{from_rails_root(payload[:identifier])}"
|
87
|
+
message = +" Rendering #{from_rails_root(payload[:identifier])}"
|
89
88
|
message << " within #{from_rails_root(payload[:layout])}" if payload[:layout]
|
90
89
|
message
|
91
90
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require "concurrent/map"
|
4
4
|
require "active_support/core_ext/module/remove_method"
|
5
5
|
require "active_support/core_ext/module/attribute_accessors"
|
6
|
+
require "active_support/deprecation"
|
6
7
|
require "action_view/template/resolver"
|
7
8
|
|
8
9
|
module ActionView
|
@@ -15,6 +16,8 @@ module ActionView
|
|
15
16
|
# only once during the request, it speeds up all cache accesses.
|
16
17
|
class LookupContext #:nodoc:
|
17
18
|
attr_accessor :prefixes, :rendered_format
|
19
|
+
deprecate :rendered_format
|
20
|
+
deprecate :rendered_format=
|
18
21
|
|
19
22
|
mattr_accessor :fallbacks, default: FallbackFileSystemResolver.instances
|
20
23
|
|
@@ -24,7 +27,7 @@ module ActionView
|
|
24
27
|
registered_details << name
|
25
28
|
Accessors::DEFAULT_PROCS[name] = block
|
26
29
|
|
27
|
-
Accessors.
|
30
|
+
Accessors.define_method(:"default_#{name}", &block)
|
28
31
|
Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
|
29
32
|
def #{name}
|
30
33
|
@details.fetch(:#{name}, [])
|
@@ -57,21 +60,39 @@ module ActionView
|
|
57
60
|
alias :eql? :equal?
|
58
61
|
|
59
62
|
@details_keys = Concurrent::Map.new
|
63
|
+
@digest_cache = Concurrent::Map.new
|
64
|
+
@view_context_mutex = Mutex.new
|
60
65
|
|
61
|
-
def self.
|
66
|
+
def self.digest_cache(details)
|
67
|
+
@digest_cache[details_cache_key(details)] ||= Concurrent::Map.new
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.details_cache_key(details)
|
62
71
|
if details[:formats]
|
63
72
|
details = details.dup
|
64
73
|
details[:formats] &= Template::Types.symbols
|
65
74
|
end
|
66
|
-
@details_keys[details] ||=
|
75
|
+
@details_keys[details] ||= Object.new
|
67
76
|
end
|
68
77
|
|
69
78
|
def self.clear
|
79
|
+
ActionView::ViewPaths.all_view_paths.each do |path_set|
|
80
|
+
path_set.each(&:clear_cache)
|
81
|
+
end
|
82
|
+
ActionView::LookupContext.fallbacks.each(&:clear_cache)
|
83
|
+
@view_context_class = nil
|
70
84
|
@details_keys.clear
|
85
|
+
@digest_cache.clear
|
71
86
|
end
|
72
87
|
|
73
88
|
def self.digest_caches
|
74
|
-
@
|
89
|
+
@digest_cache.values
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.view_context_class(klass)
|
93
|
+
@view_context_mutex.synchronize do
|
94
|
+
@view_context_class ||= klass.with_empty_template_cache
|
95
|
+
end
|
75
96
|
end
|
76
97
|
end
|
77
98
|
|
@@ -82,7 +103,7 @@ module ActionView
|
|
82
103
|
# Calculate the details key. Remove the handlers from calculation to improve performance
|
83
104
|
# since the user cannot modify it explicitly.
|
84
105
|
def details_key #:nodoc:
|
85
|
-
@details_key ||= DetailsKey.
|
106
|
+
@details_key ||= DetailsKey.details_cache_key(@details) if @cache
|
86
107
|
end
|
87
108
|
|
88
109
|
# Temporary skip passing the details_key forward.
|
@@ -94,9 +115,9 @@ module ActionView
|
|
94
115
|
end
|
95
116
|
|
96
117
|
private
|
97
|
-
|
98
118
|
def _set_detail(key, value) # :doc:
|
99
|
-
@details = @details.dup if @details_key
|
119
|
+
@details = @details.dup if @digest_cache || @details_key
|
120
|
+
@digest_cache = nil
|
100
121
|
@details_key = nil
|
101
122
|
@details[key] = value
|
102
123
|
end
|
@@ -106,20 +127,13 @@ module ActionView
|
|
106
127
|
module ViewPaths
|
107
128
|
attr_reader :view_paths, :html_fallback_for_js
|
108
129
|
|
109
|
-
# Whenever setting view paths, makes a copy so that we can manipulate them in
|
110
|
-
# instance objects as we wish.
|
111
|
-
def view_paths=(paths)
|
112
|
-
@view_paths = ActionView::PathSet.new(Array(paths))
|
113
|
-
end
|
114
|
-
|
115
130
|
def find(name, prefixes = [], partial = false, keys = [], options = {})
|
116
131
|
@view_paths.find(*args_for_lookup(name, prefixes, partial, keys, options))
|
117
132
|
end
|
118
133
|
alias :find_template :find
|
119
134
|
|
120
|
-
|
121
|
-
|
122
|
-
end
|
135
|
+
alias :find_file :find
|
136
|
+
deprecate :find_file
|
123
137
|
|
124
138
|
def find_all(name, prefixes = [], partial = false, keys = [], options = {})
|
125
139
|
@view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options))
|
@@ -138,18 +152,32 @@ module ActionView
|
|
138
152
|
# Adds fallbacks to the view paths. Useful in cases when you are rendering
|
139
153
|
# a :file.
|
140
154
|
def with_fallbacks
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
155
|
+
view_paths = build_view_paths((@view_paths.paths + self.class.fallbacks).uniq)
|
156
|
+
|
157
|
+
if block_given?
|
158
|
+
ActiveSupport::Deprecation.warn <<~eowarn.squish
|
159
|
+
Calling `with_fallbacks` with a block is deprecated. Call methods on
|
160
|
+
the lookup context returned by `with_fallbacks` instead.
|
161
|
+
eowarn
|
162
|
+
|
163
|
+
begin
|
164
|
+
_view_paths = @view_paths
|
165
|
+
@view_paths = view_paths
|
166
|
+
yield
|
167
|
+
ensure
|
168
|
+
@view_paths = _view_paths
|
169
|
+
end
|
170
|
+
else
|
171
|
+
ActionView::LookupContext.new(view_paths, @details, @prefixes)
|
146
172
|
end
|
147
|
-
yield
|
148
|
-
ensure
|
149
|
-
added_resolvers.times { view_paths.pop }
|
150
173
|
end
|
151
174
|
|
152
175
|
private
|
176
|
+
# Whenever setting view paths, makes a copy so that we can manipulate them in
|
177
|
+
# instance objects as we wish.
|
178
|
+
def build_view_paths(paths)
|
179
|
+
ActionView::PathSet.new(Array(paths))
|
180
|
+
end
|
153
181
|
|
154
182
|
def args_for_lookup(name, prefixes, partial, keys, details_options)
|
155
183
|
name, prefixes = normalize_name(name, prefixes)
|
@@ -163,7 +191,7 @@ module ActionView
|
|
163
191
|
user_details = @details.merge(options)
|
164
192
|
|
165
193
|
if @cache
|
166
|
-
details_key = DetailsKey.
|
194
|
+
details_key = DetailsKey.details_cache_key(user_details)
|
167
195
|
else
|
168
196
|
details_key = nil
|
169
197
|
end
|
@@ -190,7 +218,7 @@ module ActionView
|
|
190
218
|
end
|
191
219
|
|
192
220
|
if @cache
|
193
|
-
[details, DetailsKey.
|
221
|
+
[details, DetailsKey.details_cache_key(details)]
|
194
222
|
else
|
195
223
|
[details, nil]
|
196
224
|
end
|
@@ -202,13 +230,13 @@ module ActionView
|
|
202
230
|
# name instead of the prefix.
|
203
231
|
def normalize_name(name, prefixes)
|
204
232
|
prefixes = prefixes.presence
|
205
|
-
parts = name.to_s.split("/"
|
233
|
+
parts = name.to_s.split("/")
|
206
234
|
parts.shift if parts.first.empty?
|
207
235
|
name = parts.pop
|
208
236
|
|
209
237
|
return name, prefixes || [""] if parts.empty?
|
210
238
|
|
211
|
-
parts = parts.join("/"
|
239
|
+
parts = parts.join("/")
|
212
240
|
prefixes = prefixes ? prefixes.map { |p| "#{p}/#{parts}" } : [parts]
|
213
241
|
|
214
242
|
return name, prefixes
|
@@ -221,16 +249,23 @@ module ActionView
|
|
221
249
|
|
222
250
|
def initialize(view_paths, details = {}, prefixes = [])
|
223
251
|
@details_key = nil
|
252
|
+
@digest_cache = nil
|
224
253
|
@cache = true
|
225
254
|
@prefixes = prefixes
|
226
|
-
@rendered_format = nil
|
227
255
|
|
228
256
|
@details = initialize_details({}, details)
|
229
|
-
|
257
|
+
@view_paths = build_view_paths(view_paths)
|
230
258
|
end
|
231
259
|
|
232
260
|
def digest_cache
|
233
|
-
|
261
|
+
@digest_cache ||= DetailsKey.digest_cache(@details)
|
262
|
+
end
|
263
|
+
|
264
|
+
def with_prepended_formats(formats)
|
265
|
+
details = @details.dup
|
266
|
+
details[:formats] = formats
|
267
|
+
|
268
|
+
self.class.new(@view_paths, details, @prefixes)
|
234
269
|
end
|
235
270
|
|
236
271
|
def initialize_details(target, details)
|
@@ -245,7 +280,15 @@ module ActionView
|
|
245
280
|
# add :html as fallback to :js.
|
246
281
|
def formats=(values)
|
247
282
|
if values
|
248
|
-
values
|
283
|
+
values = values.dup
|
284
|
+
values.concat(default_formats) if values.delete "*/*"
|
285
|
+
values.uniq!
|
286
|
+
|
287
|
+
invalid_values = (values - Template::Types.symbols)
|
288
|
+
unless invalid_values.empty?
|
289
|
+
raise ArgumentError, "Invalid formats: #{invalid_values.map(&:inspect).join(", ")}"
|
290
|
+
end
|
291
|
+
|
249
292
|
if values == [:js]
|
250
293
|
values << :html
|
251
294
|
@html_fallback_for_js = true
|
data/lib/action_view/path_set.rb
CHANGED
@@ -48,12 +48,11 @@ module ActionView #:nodoc:
|
|
48
48
|
find_all(*args).first || raise(MissingTemplate.new(self, *args))
|
49
49
|
end
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
end
|
51
|
+
alias :find_file :find
|
52
|
+
deprecate :find_file
|
54
53
|
|
55
54
|
def find_all(path, prefixes = [], *args)
|
56
|
-
_find_all path, prefixes, args
|
55
|
+
_find_all path, prefixes, args
|
57
56
|
end
|
58
57
|
|
59
58
|
def exists?(path, prefixes, *args)
|
@@ -70,16 +69,11 @@ module ActionView #:nodoc:
|
|
70
69
|
end
|
71
70
|
|
72
71
|
private
|
73
|
-
|
74
|
-
def _find_all(path, prefixes, args, outside_app)
|
72
|
+
def _find_all(path, prefixes, args)
|
75
73
|
prefixes = [prefixes] if String === prefixes
|
76
74
|
prefixes.each do |prefix|
|
77
75
|
paths.each do |resolver|
|
78
|
-
|
79
|
-
templates = resolver.find_all_anywhere(path, prefix, *args)
|
80
|
-
else
|
81
|
-
templates = resolver.find_all(path, prefix, *args)
|
82
|
-
end
|
76
|
+
templates = resolver.find_all(path, prefix, *args)
|
83
77
|
return templates unless templates.empty?
|
84
78
|
end
|
85
79
|
end
|