actionview 4.2.11.1 → 5.2.7

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionview might be problematic. Click here for more details.

Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +108 -240
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -6
  5. data/lib/action_view/base.rb +38 -28
  6. data/lib/action_view/buffers.rb +3 -1
  7. data/lib/action_view/context.rb +3 -3
  8. data/lib/action_view/dependency_tracker.rb +54 -20
  9. data/lib/action_view/digestor.rb +94 -83
  10. data/lib/action_view/flows.rb +11 -11
  11. data/lib/action_view/gem_version.rb +5 -3
  12. data/lib/action_view/helpers/active_model_helper.rb +17 -11
  13. data/lib/action_view/helpers/asset_tag_helper.rb +244 -62
  14. data/lib/action_view/helpers/asset_url_helper.rb +170 -67
  15. data/lib/action_view/helpers/atom_feed_helper.rb +19 -17
  16. data/lib/action_view/helpers/cache_helper.rb +105 -42
  17. data/lib/action_view/helpers/capture_helper.rb +16 -13
  18. data/lib/action_view/helpers/controller_helper.rb +15 -4
  19. data/lib/action_view/helpers/csp_helper.rb +24 -0
  20. data/lib/action_view/helpers/csrf_helper.rb +7 -5
  21. data/lib/action_view/helpers/date_helper.rb +170 -112
  22. data/lib/action_view/helpers/debug_helper.rb +7 -6
  23. data/lib/action_view/helpers/form_helper.rb +521 -127
  24. data/lib/action_view/helpers/form_options_helper.rb +109 -63
  25. data/lib/action_view/helpers/form_tag_helper.rb +110 -67
  26. data/lib/action_view/helpers/javascript_helper.rb +27 -12
  27. data/lib/action_view/helpers/number_helper.rb +77 -58
  28. data/lib/action_view/helpers/output_safety_helper.rb +36 -4
  29. data/lib/action_view/helpers/record_tag_helper.rb +14 -99
  30. data/lib/action_view/helpers/rendering_helper.rb +6 -5
  31. data/lib/action_view/helpers/sanitize_helper.rb +20 -15
  32. data/lib/action_view/helpers/tag_helper.rb +198 -73
  33. data/lib/action_view/helpers/tags/base.rb +134 -97
  34. data/lib/action_view/helpers/tags/check_box.rb +20 -18
  35. data/lib/action_view/helpers/tags/checkable.rb +4 -2
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -33
  37. data/lib/action_view/helpers/tags/collection_helpers.rb +70 -36
  38. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -11
  39. data/lib/action_view/helpers/tags/collection_select.rb +4 -2
  40. data/lib/action_view/helpers/tags/color_field.rb +3 -1
  41. data/lib/action_view/helpers/tags/date_field.rb +2 -0
  42. data/lib/action_view/helpers/tags/date_select.rb +38 -36
  43. data/lib/action_view/helpers/tags/datetime_field.rb +4 -2
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +2 -0
  45. data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
  46. data/lib/action_view/helpers/tags/email_field.rb +2 -0
  47. data/lib/action_view/helpers/tags/file_field.rb +2 -0
  48. data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
  49. data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
  50. data/lib/action_view/helpers/tags/label.rb +3 -1
  51. data/lib/action_view/helpers/tags/month_field.rb +2 -0
  52. data/lib/action_view/helpers/tags/number_field.rb +2 -0
  53. data/lib/action_view/helpers/tags/password_field.rb +3 -1
  54. data/lib/action_view/helpers/tags/placeholderable.rb +3 -1
  55. data/lib/action_view/helpers/tags/radio_button.rb +7 -5
  56. data/lib/action_view/helpers/tags/range_field.rb +2 -0
  57. data/lib/action_view/helpers/tags/search_field.rb +14 -9
  58. data/lib/action_view/helpers/tags/select.rb +11 -9
  59. data/lib/action_view/helpers/tags/tel_field.rb +2 -0
  60. data/lib/action_view/helpers/tags/text_area.rb +4 -2
  61. data/lib/action_view/helpers/tags/text_field.rb +8 -7
  62. data/lib/action_view/helpers/tags/time_field.rb +2 -0
  63. data/lib/action_view/helpers/tags/time_select.rb +2 -0
  64. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
  65. data/lib/action_view/helpers/tags/translator.rb +17 -13
  66. data/lib/action_view/helpers/tags/url_field.rb +2 -0
  67. data/lib/action_view/helpers/tags/week_field.rb +2 -0
  68. data/lib/action_view/helpers/tags.rb +3 -1
  69. data/lib/action_view/helpers/text_helper.rb +55 -36
  70. data/lib/action_view/helpers/translation_helper.rb +74 -32
  71. data/lib/action_view/helpers/url_helper.rb +159 -104
  72. data/lib/action_view/helpers.rb +5 -1
  73. data/lib/action_view/layouts.rb +65 -58
  74. data/lib/action_view/log_subscriber.rb +60 -8
  75. data/lib/action_view/lookup_context.rb +80 -65
  76. data/lib/action_view/model_naming.rb +3 -1
  77. data/lib/action_view/path_set.rb +30 -19
  78. data/lib/action_view/railtie.rb +39 -6
  79. data/lib/action_view/record_identifier.rb +53 -25
  80. data/lib/action_view/renderer/abstract_renderer.rb +21 -15
  81. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +57 -0
  82. data/lib/action_view/renderer/partial_renderer.rb +218 -214
  83. data/lib/action_view/renderer/renderer.rb +8 -6
  84. data/lib/action_view/renderer/streaming_template_renderer.rb +50 -48
  85. data/lib/action_view/renderer/template_renderer.rb +67 -66
  86. data/lib/action_view/rendering.rb +19 -14
  87. data/lib/action_view/routing_url_for.rb +27 -17
  88. data/lib/action_view/tasks/cache_digests.rake +25 -0
  89. data/lib/action_view/template/error.rb +16 -16
  90. data/lib/action_view/template/handlers/builder.rb +10 -11
  91. data/lib/action_view/template/handlers/erb/erubi.rb +83 -0
  92. data/lib/action_view/template/handlers/erb.rb +9 -80
  93. data/lib/action_view/template/handlers/html.rb +11 -0
  94. data/lib/action_view/template/handlers/raw.rb +3 -3
  95. data/lib/action_view/template/handlers.rb +11 -7
  96. data/lib/action_view/template/html.rb +5 -5
  97. data/lib/action_view/template/resolver.rb +140 -115
  98. data/lib/action_view/template/text.rb +8 -9
  99. data/lib/action_view/template/types.rb +18 -18
  100. data/lib/action_view/template.rb +56 -31
  101. data/lib/action_view/test_case.rb +50 -29
  102. data/lib/action_view/testing/resolvers.rb +31 -31
  103. data/lib/action_view/version.rb +3 -1
  104. data/lib/action_view/view_paths.rb +28 -34
  105. data/lib/action_view.rb +8 -7
  106. data/lib/assets/compiled/rails-ujs.js +720 -0
  107. metadata +25 -24
  108. data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "action_view/rendering"
2
- require "active_support/core_ext/module/remove_method"
4
+ require "active_support/core_ext/module/redefine_method"
3
5
 
4
6
  module ActionView
5
7
  # Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
@@ -91,16 +93,16 @@ module ActionView
91
93
  # layout false
92
94
  #
93
95
  # In these examples, we have three implicit lookup scenarios:
94
- # * The BankController uses the "bank" layout.
95
- # * The ExchangeController uses the "exchange" layout.
96
- # * The CurrencyController inherits the layout from BankController.
96
+ # * The +BankController+ uses the "bank" layout.
97
+ # * The +ExchangeController+ uses the "exchange" layout.
98
+ # * The +CurrencyController+ inherits the layout from BankController.
97
99
  #
98
100
  # However, when a layout is explicitly set, the explicitly set layout wins:
99
- # * The InformationController uses the "information" layout, explicitly set.
100
- # * The TellerController also uses the "information" layout, because the parent explicitly set it.
101
- # * The EmployeeController uses the "employee" layout, because it set the layout to nil, resetting the parent configuration.
102
- # * The VaultController chooses a layout dynamically by calling the <tt>access_level_layout</tt> method.
103
- # * The TillController does not use a layout at all.
101
+ # * The +InformationController+ uses the "information" layout, explicitly set.
102
+ # * The +TellerController+ also uses the "information" layout, because the parent explicitly set it.
103
+ # * The +EmployeeController+ uses the "employee" layout, because it set the layout to +nil+, resetting the parent configuration.
104
+ # * The +VaultController+ chooses a layout dynamically by calling the <tt>access_level_layout</tt> method.
105
+ # * The +TillController+ does not use a layout at all.
104
106
  #
105
107
  # == Types of layouts
106
108
  #
@@ -148,8 +150,8 @@ module ActionView
148
150
  # The template will be looked always in <tt>app/views/layouts/</tt> folder. But you can point
149
151
  # <tt>layouts</tt> folder direct also. <tt>layout "layouts/demo"</tt> is the same as <tt>layout "demo"</tt>.
150
152
  #
151
- # Setting the layout to nil forces it to be looked up in the filesystem and fallbacks to the parent behavior if none exists.
152
- # Setting it to nil is useful to re-enable template lookup overriding a previous configuration set in the parent:
153
+ # Setting the layout to +nil+ forces it to be looked up in the filesystem and fallbacks to the parent behavior if none exists.
154
+ # Setting it to +nil+ is useful to re-enable template lookup overriding a previous configuration set in the parent:
153
155
  #
154
156
  # class ApplicationController < ActionController::Base
155
157
  # layout "application"
@@ -204,9 +206,9 @@ module ActionView
204
206
  include ActionView::Rendering
205
207
 
206
208
  included do
207
- class_attribute :_layout, :_layout_conditions, :instance_accessor => false
208
- self._layout = nil
209
- self._layout_conditions = {}
209
+ class_attribute :_layout, instance_accessor: false
210
+ class_attribute :_layout_conditions, instance_accessor: false, default: {}
211
+
210
212
  _write_layout_method
211
213
  end
212
214
 
@@ -223,36 +225,39 @@ module ActionView
223
225
  module LayoutConditions # :nodoc:
224
226
  private
225
227
 
226
- # Determines whether the current action has a layout definition by
227
- # checking the action name against the :only and :except conditions
228
- # set by the <tt>layout</tt> method.
229
- #
230
- # ==== Returns
231
- # * <tt> Boolean</tt> - True if the action has a layout definition, false otherwise.
232
- def _conditional_layout?
233
- return unless super
234
-
235
- conditions = _layout_conditions
236
-
237
- if only = conditions[:only]
238
- only.include?(action_name)
239
- elsif except = conditions[:except]
240
- !except.include?(action_name)
241
- else
242
- true
228
+ # Determines whether the current action has a layout definition by
229
+ # checking the action name against the :only and :except conditions
230
+ # set by the <tt>layout</tt> method.
231
+ #
232
+ # ==== Returns
233
+ # * <tt>Boolean</tt> - True if the action has a layout definition, false otherwise.
234
+ def _conditional_layout?
235
+ return unless super
236
+
237
+ conditions = _layout_conditions
238
+
239
+ if only = conditions[:only]
240
+ only.include?(action_name)
241
+ elsif except = conditions[:except]
242
+ !except.include?(action_name)
243
+ else
244
+ true
245
+ end
243
246
  end
244
- end
245
247
  end
246
248
 
247
249
  # Specify the layout to use for this class.
248
250
  #
249
251
  # If the specified layout is a:
250
252
  # String:: the String is the template name
251
- # Symbol:: call the method specified by the symbol, which will return the template name
253
+ # Symbol:: call the method specified by the symbol
254
+ # Proc:: call the passed Proc
252
255
  # false:: There is no layout
253
256
  # true:: raise an ArgumentError
254
257
  # nil:: Force default layout behavior with inheritance
255
258
  #
259
+ # Return value of +Proc+ and +Symbol+ arguments should be +String+, +false+, +true+ or +nil+
260
+ # with the same meaning as described above.
256
261
  # ==== Parameters
257
262
  # * <tt>layout</tt> - The layout to use.
258
263
  #
@@ -262,7 +267,7 @@ module ActionView
262
267
  def layout(layout, conditions = {})
263
268
  include LayoutConditions unless conditions.empty?
264
269
 
265
- conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} }
270
+ conditions.each { |k, v| conditions[k] = Array(v).map(&:to_s) }
266
271
  self._layout_conditions = conditions
267
272
 
268
273
  self._layout = layout
@@ -274,10 +279,10 @@ module ActionView
274
279
  # If a layout is not explicitly mentioned then look for a layout with the controller's name.
275
280
  # if nothing is found then try same procedure to find super class's layout.
276
281
  def _write_layout_method # :nodoc:
277
- remove_possible_method(:_layout)
282
+ silence_redefinition_of_method(:_layout)
278
283
 
279
- prefixes = _implied_layout_name =~ /\blayouts/ ? [] : ["layouts"]
280
- default_behavior = "lookup_context.find_all('#{_implied_layout_name}', #{prefixes.inspect}).first || super"
284
+ prefixes = /\blayouts/.match?(_implied_layout_name) ? [] : ["layouts"]
285
+ default_behavior = "lookup_context.find_all('#{_implied_layout_name}', #{prefixes.inspect}, false, [], { formats: formats }).first || super"
281
286
  name_clause = if name
282
287
  default_behavior
283
288
  else
@@ -286,7 +291,8 @@ module ActionView
286
291
  RUBY
287
292
  end
288
293
 
289
- layout_definition = case _layout
294
+ layout_definition = \
295
+ case _layout
290
296
  when String
291
297
  _layout.inspect
292
298
  when Symbol
@@ -313,10 +319,10 @@ module ActionView
313
319
  raise ArgumentError, "Layouts must be specified as a String, Symbol, Proc, false, or nil"
314
320
  when nil
315
321
  name_clause
316
- end
322
+ end
317
323
 
318
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
319
- def _layout
324
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
325
+ def _layout(formats)
320
326
  if _conditional_layout?
321
327
  #{layout_definition}
322
328
  else
@@ -329,14 +335,14 @@ module ActionView
329
335
 
330
336
  private
331
337
 
332
- # If no layout is supplied, look for a template named the return
333
- # value of this method.
334
- #
335
- # ==== Returns
336
- # * <tt>String</tt> - A template name
337
- def _implied_layout_name # :nodoc:
338
- controller_path
339
- end
338
+ # If no layout is supplied, look for a template named the return
339
+ # value of this method.
340
+ #
341
+ # ==== Returns
342
+ # * <tt>String</tt> - A template name
343
+ def _implied_layout_name
344
+ controller_path
345
+ end
340
346
  end
341
347
 
342
348
  def _normalize_options(options) # :nodoc:
@@ -372,7 +378,7 @@ module ActionView
372
378
  end
373
379
 
374
380
  # This will be overwritten by _write_layout_method
375
- def _layout; end
381
+ def _layout(*); end
376
382
 
377
383
  # Determine the layout for a given name, taking into account the name type.
378
384
  #
@@ -382,8 +388,8 @@ module ActionView
382
388
  case name
383
389
  when String then _normalize_layout(name)
384
390
  when Proc then name
385
- when true then Proc.new { _default_layout(true) }
386
- when :default then Proc.new { _default_layout(false) }
391
+ when true then Proc.new { |formats| _default_layout(formats, true) }
392
+ when :default then Proc.new { |formats| _default_layout(formats, false) }
387
393
  when false, nil then nil
388
394
  else
389
395
  raise ArgumentError,
@@ -399,14 +405,15 @@ module ActionView
399
405
  # Optionally raises an exception if the layout could not be found.
400
406
  #
401
407
  # ==== Parameters
402
- # * <tt>require_layout</tt> - If set to true and layout is not found,
403
- # an ArgumentError exception is raised (defaults to false)
408
+ # * <tt>formats</tt> - The formats accepted to this layout
409
+ # * <tt>require_layout</tt> - If set to +true+ and layout is not found,
410
+ # an +ArgumentError+ exception is raised (defaults to +false+)
404
411
  #
405
412
  # ==== Returns
406
- # * <tt>template</tt> - The template object for the default layout (or nil)
407
- def _default_layout(require_layout = false)
413
+ # * <tt>template</tt> - The template object for the default layout (or +nil+)
414
+ def _default_layout(formats, require_layout = false)
408
415
  begin
409
- value = _layout if action_has_layout?
416
+ value = _layout(formats) if action_has_layout?
410
417
  rescue NameError => e
411
418
  raise e, "Could not render layout: #{e.message}"
412
419
  end
@@ -420,7 +427,7 @@ module ActionView
420
427
  end
421
428
 
422
429
  def _include_layout?(options)
423
- (options.keys & [:body, :text, :plain, :html, :inline, :partial]).empty? || options.key?(:layout)
430
+ (options.keys & [:body, :plain, :html, :inline, :partial]).empty? || options.key?(:layout)
424
431
  end
425
432
  end
426
433
  end
@@ -1,4 +1,6 @@
1
- require 'active_support/log_subscriber'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/log_subscriber"
2
4
 
3
5
  module ActionView
4
6
  # = Action View Log Subscriber
@@ -14,30 +16,80 @@ module ActionView
14
16
 
15
17
  def render_template(event)
16
18
  info do
17
- message = " Rendered #{from_rails_root(event.payload[:identifier])}"
19
+ message = " Rendered #{from_rails_root(event.payload[:identifier])}".dup
20
+ message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
21
+ message << " (#{event.duration.round(1)}ms)"
22
+ end
23
+ end
24
+
25
+ def render_partial(event)
26
+ info do
27
+ message = " Rendered #{from_rails_root(event.payload[:identifier])}".dup
18
28
  message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
19
29
  message << " (#{event.duration.round(1)}ms)"
30
+ message << " #{cache_message(event.payload)}" unless event.payload[:cache_hit].nil?
31
+ message
20
32
  end
21
33
  end
22
- alias :render_partial :render_template
23
- alias :render_collection :render_template
34
+
35
+ def render_collection(event)
36
+ identifier = event.payload[:identifier] || "templates"
37
+
38
+ info do
39
+ " Rendered collection of #{from_rails_root(identifier)}" \
40
+ " #{render_count(event.payload)} (#{event.duration.round(1)}ms)"
41
+ end
42
+ end
43
+
44
+ def start(name, id, payload)
45
+ if name == "render_template.action_view"
46
+ log_rendering_start(payload)
47
+ end
48
+
49
+ super
50
+ end
24
51
 
25
52
  def logger
26
53
  ActionView::Base.logger
27
54
  end
28
55
 
29
- protected
56
+ private
30
57
 
31
- EMPTY = ''
32
- def from_rails_root(string)
58
+ EMPTY = ""
59
+ def from_rails_root(string) # :doc:
33
60
  string = string.sub(rails_root, EMPTY)
34
61
  string.sub!(VIEWS_PATTERN, EMPTY)
35
62
  string
36
63
  end
37
64
 
38
- def rails_root
65
+ def rails_root # :doc:
39
66
  @root ||= "#{Rails.root}/"
40
67
  end
68
+
69
+ def render_count(payload) # :doc:
70
+ if payload[:cache_hits]
71
+ "[#{payload[:cache_hits]} / #{payload[:count]} cache hits]"
72
+ else
73
+ "[#{payload[:count]} times]"
74
+ end
75
+ end
76
+
77
+ def cache_message(payload) # :doc:
78
+ case payload[:cache_hit]
79
+ when :hit
80
+ "[cache hit]"
81
+ when :miss
82
+ "[cache miss]"
83
+ end
84
+ end
85
+
86
+ def log_rendering_start(payload)
87
+ info do
88
+ message = " Rendering #{from_rails_root(payload[:identifier])}".dup
89
+ message << " within #{from_rails_root(payload[:layout])}" if payload[:layout]
90
+ message
91
+ end
92
+ end
41
93
  end
42
94
  end
43
95
 
@@ -1,27 +1,28 @@
1
- require 'thread_safe'
2
- require 'active_support/core_ext/module/remove_method'
3
- require 'active_support/core_ext/module/attribute_accessors'
4
- require 'action_view/template/resolver'
1
+ # frozen_string_literal: true
2
+
3
+ require "concurrent/map"
4
+ require "active_support/core_ext/module/remove_method"
5
+ require "active_support/core_ext/module/attribute_accessors"
6
+ require "action_view/template/resolver"
5
7
 
6
8
  module ActionView
7
9
  # = Action View Lookup Context
8
10
  #
9
- # LookupContext is the object responsible to hold all information required to lookup
10
- # templates, i.e. view paths and details. The LookupContext is also responsible to
11
- # generate a key, given to view paths, used in the resolver cache lookup. Since
12
- # this key is generated just once during the request, it speeds up all cache accesses.
11
+ # <tt>LookupContext</tt> is the object responsible for holding all information
12
+ # required for looking up templates, i.e. view paths and details.
13
+ # <tt>LookupContext</tt> is also responsible for generating a key, given to
14
+ # view paths, used in the resolver cache lookup. Since this key is generated
15
+ # only once during the request, it speeds up all cache accesses.
13
16
  class LookupContext #:nodoc:
14
17
  attr_accessor :prefixes, :rendered_format
15
18
 
16
- mattr_accessor :fallbacks
17
- @@fallbacks = FallbackFileSystemResolver.instances
19
+ mattr_accessor :fallbacks, default: FallbackFileSystemResolver.instances
18
20
 
19
- mattr_accessor :registered_details
20
- self.registered_details = []
21
+ mattr_accessor :registered_details, default: []
21
22
 
22
- def self.register_detail(name, options = {}, &block)
23
- self.registered_details << name
24
- initialize = registered_details.map { |n| "@details[:#{n}] = details[:#{n}] || default_#{n}" }
23
+ def self.register_detail(name, &block)
24
+ registered_details << name
25
+ Accessors::DEFAULT_PROCS[name] = block
25
26
 
26
27
  Accessors.send :define_method, :"default_#{name}", &block
27
28
  Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
@@ -33,16 +34,12 @@ module ActionView
33
34
  value = value.present? ? Array(value) : default_#{name}
34
35
  _set_detail(:#{name}, value) if value != @details[:#{name}]
35
36
  end
36
-
37
- remove_possible_method :initialize_details
38
- def initialize_details(details)
39
- #{initialize.join("\n")}
40
- end
41
37
  METHOD
42
38
  end
43
39
 
44
40
  # Holds accessors for the registered details.
45
41
  module Accessors #:nodoc:
42
+ DEFAULT_PROCS = {}
46
43
  end
47
44
 
48
45
  register_detail(:locale) do
@@ -54,29 +51,27 @@ module ActionView
54
51
  end
55
52
  register_detail(:formats) { ActionView::Base.default_formats || [:html, :text, :js, :css, :xml, :json] }
56
53
  register_detail(:variants) { [] }
57
- register_detail(:handlers){ Template::Handlers.extensions }
54
+ register_detail(:handlers) { Template::Handlers.extensions }
58
55
 
59
56
  class DetailsKey #:nodoc:
60
57
  alias :eql? :equal?
61
- alias :object_hash :hash
62
58
 
63
- attr_reader :hash
64
- @details_keys = ThreadSafe::Cache.new
59
+ @details_keys = Concurrent::Map.new
65
60
 
66
61
  def self.get(details)
67
62
  if details[:formats]
68
63
  details = details.dup
69
- details[:formats] &= Mime::SET.symbols
64
+ details[:formats] &= Template::Types.symbols
70
65
  end
71
- @details_keys[details] ||= new
66
+ @details_keys[details] ||= Concurrent::Map.new
72
67
  end
73
68
 
74
69
  def self.clear
75
70
  @details_keys.clear
76
71
  end
77
72
 
78
- def initialize
79
- @hash = object_hash
73
+ def self.digest_caches
74
+ @details_keys.values
80
75
  end
81
76
  end
82
77
 
@@ -98,9 +93,9 @@ module ActionView
98
93
  @cache = old_value
99
94
  end
100
95
 
101
- protected
96
+ private
102
97
 
103
- def _set_detail(key, value)
98
+ def _set_detail(key, value) # :doc:
104
99
  @details = @details.dup if @details_key
105
100
  @details_key = nil
106
101
  @details[key] = value
@@ -130,11 +125,16 @@ module ActionView
130
125
  @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options))
131
126
  end
132
127
 
133
- def exists?(name, prefixes = [], partial = false, keys = [], options = {})
128
+ def exists?(name, prefixes = [], partial = false, keys = [], **options)
134
129
  @view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys, options))
135
130
  end
136
131
  alias :template_exists? :exists?
137
132
 
133
+ def any?(name, prefixes = [], partial = false)
134
+ @view_paths.exists?(*args_for_any(name, prefixes, partial))
135
+ end
136
+ alias :any_templates? :any?
137
+
138
138
  # Adds fallbacks to the view paths. Useful in cases when you are rendering
139
139
  # a :file.
140
140
  def with_fallbacks
@@ -149,16 +149,16 @@ module ActionView
149
149
  added_resolvers.times { view_paths.pop }
150
150
  end
151
151
 
152
- protected
152
+ private
153
153
 
154
- def args_for_lookup(name, prefixes, partial, keys, details_options) #:nodoc:
154
+ def args_for_lookup(name, prefixes, partial, keys, details_options)
155
155
  name, prefixes = normalize_name(name, prefixes)
156
156
  details, details_key = detail_args_for(details_options)
157
157
  [name, prefixes, partial || false, details, details_key, keys]
158
158
  end
159
159
 
160
160
  # Compute details hash and key according to user options (e.g. passed from #render).
161
- def detail_args_for(options)
161
+ def detail_args_for(options) # :doc:
162
162
  return @details, details_key if options.empty? # most common path.
163
163
  user_details = @details.merge(options)
164
164
 
@@ -171,18 +171,44 @@ module ActionView
171
171
  [user_details, details_key]
172
172
  end
173
173
 
174
+ def args_for_any(name, prefixes, partial)
175
+ name, prefixes = normalize_name(name, prefixes)
176
+ details, details_key = detail_args_for_any
177
+ [name, prefixes, partial || false, details, details_key]
178
+ end
179
+
180
+ def detail_args_for_any
181
+ @detail_args_for_any ||= begin
182
+ details = {}
183
+
184
+ registered_details.each do |k|
185
+ if k == :variants
186
+ details[k] = :any
187
+ else
188
+ details[k] = Accessors::DEFAULT_PROCS[k].call
189
+ end
190
+ end
191
+
192
+ if @cache
193
+ [details, DetailsKey.get(details)]
194
+ else
195
+ [details, nil]
196
+ end
197
+ end
198
+ end
199
+
174
200
  # Support legacy foo.erb names even though we now ignore .erb
175
201
  # as well as incorrectly putting part of the path in the template
176
202
  # name instead of the prefix.
177
- def normalize_name(name, prefixes) #:nodoc:
203
+ def normalize_name(name, prefixes)
178
204
  prefixes = prefixes.presence
179
- parts = name.to_s.split('/')
205
+ parts = name.to_s.split("/".freeze)
180
206
  parts.shift if parts.first.empty?
181
- name = parts.pop
207
+ name = parts.pop
182
208
 
183
209
  return name, prefixes || [""] if parts.empty?
184
210
 
185
- parts = parts.join('/')
211
+ parts = parts.join("/".freeze)
186
212
  prefixes = prefixes ? prefixes.map { |p| "#{p}/#{parts}" } : [parts]
187
213
 
188
214
  return name, prefixes
@@ -194,21 +220,32 @@ module ActionView
194
220
  include ViewPaths
195
221
 
196
222
  def initialize(view_paths, details = {}, prefixes = [])
197
- @details, @details_key = {}, nil
198
- @skip_default_locale = false
223
+ @details_key = nil
199
224
  @cache = true
200
225
  @prefixes = prefixes
201
226
  @rendered_format = nil
202
227
 
228
+ @details = initialize_details({}, details)
203
229
  self.view_paths = view_paths
204
- initialize_details(details)
205
230
  end
206
231
 
232
+ def digest_cache
233
+ details_key
234
+ end
235
+
236
+ def initialize_details(target, details)
237
+ registered_details.each do |k|
238
+ target[k] = details[k] || Accessors::DEFAULT_PROCS[k].call
239
+ end
240
+ target
241
+ end
242
+ private :initialize_details
243
+
207
244
  # Override formats= to expand ["*/*"] values and automatically
208
245
  # add :html as fallback to :js.
209
246
  def formats=(values)
210
247
  if values
211
- values.concat(default_formats) if values.delete "*/*"
248
+ values.concat(default_formats) if values.delete "*/*".freeze
212
249
  if values == [:js]
213
250
  values << :html
214
251
  @html_fallback_for_js = true
@@ -217,12 +254,6 @@ module ActionView
217
254
  super(values)
218
255
  end
219
256
 
220
- # Do not use the default locale on template lookup.
221
- def skip_default_locale!
222
- @skip_default_locale = true
223
- self.locale = nil
224
- end
225
-
226
257
  # Override locale to return a symbol instead of array.
227
258
  def locale
228
259
  @details[:locale].first
@@ -237,23 +268,7 @@ module ActionView
237
268
  config.locale = value
238
269
  end
239
270
 
240
- super(@skip_default_locale ? I18n.locale : default_locale)
241
- end
242
-
243
- # Uses the first format in the formats array for layout lookup.
244
- def with_layout_format
245
- if formats.size == 1
246
- yield
247
- else
248
- old_formats = formats
249
- _set_detail(:formats, formats[0,1])
250
-
251
- begin
252
- yield
253
- ensure
254
- _set_detail(:formats, old_formats)
255
- end
256
- end
271
+ super(default_locale)
257
272
  end
258
273
  end
259
274
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionView
2
- module ModelNaming
4
+ module ModelNaming #:nodoc:
3
5
  # Converts the given object to an ActiveModel compliant one.
4
6
  def convert_to_model(object)
5
7
  object.respond_to?(:to_model) ? object.to_model : object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionView #:nodoc:
2
4
  # = Action View PathSet
3
5
  #
@@ -58,32 +60,41 @@ module ActionView #:nodoc:
58
60
  find_all(path, prefixes, *args).any?
59
61
  end
60
62
 
63
+ def find_all_with_query(query) # :nodoc:
64
+ paths.each do |resolver|
65
+ templates = resolver.find_all_with_query(query)
66
+ return templates unless templates.empty?
67
+ end
68
+
69
+ []
70
+ end
71
+
61
72
  private
62
73
 
63
- def _find_all(path, prefixes, args, outside_app)
64
- prefixes = [prefixes] if String === prefixes
65
- prefixes.each do |prefix|
66
- paths.each do |resolver|
67
- if outside_app
68
- templates = resolver.find_all_anywhere(path, prefix, *args)
69
- else
70
- templates = resolver.find_all(path, prefix, *args)
74
+ def _find_all(path, prefixes, args, outside_app)
75
+ prefixes = [prefixes] if String === prefixes
76
+ prefixes.each do |prefix|
77
+ paths.each do |resolver|
78
+ if outside_app
79
+ templates = resolver.find_all_anywhere(path, prefix, *args)
80
+ else
81
+ templates = resolver.find_all(path, prefix, *args)
82
+ end
83
+ return templates unless templates.empty?
71
84
  end
72
- return templates unless templates.empty?
73
85
  end
86
+ []
74
87
  end
75
- []
76
- end
77
88
 
78
- def typecast(paths)
79
- paths.map do |path|
80
- case path
81
- when Pathname, String
82
- OptimizedFileSystemResolver.new path.to_s
83
- else
84
- path
89
+ def typecast(paths)
90
+ paths.map do |path|
91
+ case path
92
+ when Pathname, String
93
+ OptimizedFileSystemResolver.new path.to_s
94
+ else
95
+ path
96
+ end
85
97
  end
86
98
  end
87
- end
88
99
  end
89
100
  end