actionview 6.1.7.2 → 7.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +299 -277
  3. data/MIT-LICENSE +2 -1
  4. data/README.rdoc +3 -3
  5. data/app/assets/javascripts/rails-ujs.esm.js +686 -0
  6. data/app/assets/javascripts/rails-ujs.js +630 -0
  7. data/lib/action_view/base.rb +37 -19
  8. data/lib/action_view/buffers.rb +107 -9
  9. data/lib/action_view/cache_expiry.rb +48 -37
  10. data/lib/action_view/context.rb +1 -1
  11. data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
  12. data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
  13. data/lib/action_view/dependency_tracker.rb +6 -147
  14. data/lib/action_view/deprecator.rb +7 -0
  15. data/lib/action_view/digestor.rb +8 -5
  16. data/lib/action_view/flows.rb +4 -4
  17. data/lib/action_view/gem_version.rb +4 -4
  18. data/lib/action_view/helpers/active_model_helper.rb +3 -3
  19. data/lib/action_view/helpers/asset_tag_helper.rb +200 -60
  20. data/lib/action_view/helpers/asset_url_helper.rb +22 -21
  21. data/lib/action_view/helpers/atom_feed_helper.rb +8 -9
  22. data/lib/action_view/helpers/cache_helper.rb +55 -12
  23. data/lib/action_view/helpers/capture_helper.rb +34 -14
  24. data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
  25. data/lib/action_view/helpers/controller_helper.rb +8 -2
  26. data/lib/action_view/helpers/csp_helper.rb +3 -3
  27. data/lib/action_view/helpers/csrf_helper.rb +4 -4
  28. data/lib/action_view/helpers/date_helper.rb +123 -57
  29. data/lib/action_view/helpers/debug_helper.rb +6 -4
  30. data/lib/action_view/helpers/form_helper.rb +253 -97
  31. data/lib/action_view/helpers/form_options_helper.rb +72 -34
  32. data/lib/action_view/helpers/form_tag_helper.rb +189 -58
  33. data/lib/action_view/helpers/javascript_helper.rb +4 -5
  34. data/lib/action_view/helpers/number_helper.rb +43 -335
  35. data/lib/action_view/helpers/output_safety_helper.rb +6 -6
  36. data/lib/action_view/helpers/rendering_helper.rb +6 -7
  37. data/lib/action_view/helpers/sanitize_helper.rb +54 -24
  38. data/lib/action_view/helpers/tag_helper.rb +42 -35
  39. data/lib/action_view/helpers/tags/base.rb +16 -77
  40. data/lib/action_view/helpers/tags/check_box.rb +1 -1
  41. data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
  42. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
  43. data/lib/action_view/helpers/tags/collection_select.rb +4 -1
  44. data/lib/action_view/helpers/tags/date_field.rb +1 -1
  45. data/lib/action_view/helpers/tags/date_select.rb +2 -0
  46. data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
  47. data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
  48. data/lib/action_view/helpers/tags/file_field.rb +16 -0
  49. data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
  50. data/lib/action_view/helpers/tags/month_field.rb +1 -1
  51. data/lib/action_view/helpers/tags/select.rb +4 -1
  52. data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
  53. data/lib/action_view/helpers/tags/time_field.rb +11 -2
  54. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
  55. data/lib/action_view/helpers/tags/week_field.rb +1 -1
  56. data/lib/action_view/helpers/tags/weekday_select.rb +31 -0
  57. data/lib/action_view/helpers/tags.rb +5 -2
  58. data/lib/action_view/helpers/text_helper.rb +180 -97
  59. data/lib/action_view/helpers/translation_helper.rb +14 -45
  60. data/lib/action_view/helpers/url_helper.rb +230 -132
  61. data/lib/action_view/helpers.rb +27 -25
  62. data/lib/action_view/layouts.rb +15 -10
  63. data/lib/action_view/log_subscriber.rb +49 -32
  64. data/lib/action_view/lookup_context.rb +58 -61
  65. data/lib/action_view/model_naming.rb +2 -2
  66. data/lib/action_view/path_registry.rb +57 -0
  67. data/lib/action_view/path_set.rb +28 -35
  68. data/lib/action_view/railtie.rb +44 -9
  69. data/lib/action_view/record_identifier.rb +16 -9
  70. data/lib/action_view/render_parser.rb +188 -0
  71. data/lib/action_view/renderer/abstract_renderer.rb +3 -3
  72. data/lib/action_view/renderer/collection_renderer.rb +10 -2
  73. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +21 -3
  74. data/lib/action_view/renderer/partial_renderer.rb +3 -36
  75. data/lib/action_view/renderer/renderer.rb +6 -4
  76. data/lib/action_view/renderer/streaming_template_renderer.rb +6 -5
  77. data/lib/action_view/renderer/template_renderer.rb +9 -4
  78. data/lib/action_view/rendering.rb +25 -7
  79. data/lib/action_view/ripper_ast_parser.rb +198 -0
  80. data/lib/action_view/routing_url_for.rb +8 -5
  81. data/lib/action_view/template/error.rb +122 -14
  82. data/lib/action_view/template/handlers/builder.rb +4 -4
  83. data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
  84. data/lib/action_view/template/handlers/erb.rb +79 -1
  85. data/lib/action_view/template/handlers.rb +4 -4
  86. data/lib/action_view/template/html.rb +4 -4
  87. data/lib/action_view/template/inline.rb +3 -3
  88. data/lib/action_view/template/raw_file.rb +4 -4
  89. data/lib/action_view/template/renderable.rb +1 -1
  90. data/lib/action_view/template/resolver.rb +96 -313
  91. data/lib/action_view/template/text.rb +4 -4
  92. data/lib/action_view/template/types.rb +25 -32
  93. data/lib/action_view/template.rb +245 -41
  94. data/lib/action_view/template_details.rb +66 -0
  95. data/lib/action_view/template_path.rb +66 -0
  96. data/lib/action_view/test_case.rb +182 -23
  97. data/lib/action_view/testing/resolvers.rb +11 -12
  98. data/lib/action_view/unbound_template.rb +43 -7
  99. data/lib/action_view/version.rb +1 -1
  100. data/lib/action_view/view_paths.rb +19 -28
  101. data/lib/action_view.rb +6 -4
  102. data/lib/assets/compiled/rails-ujs.js +36 -5
  103. metadata +32 -25
@@ -1,34 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/benchmarkable"
4
+ require "action_view/helpers/capture_helper"
5
+ require "action_view/helpers/output_safety_helper"
6
+ require "action_view/helpers/tag_helper"
7
+ require "action_view/helpers/url_helper"
8
+ require "action_view/helpers/sanitize_helper"
9
+ require "action_view/helpers/text_helper"
10
+ require "action_view/helpers/active_model_helper"
11
+ require "action_view/helpers/asset_tag_helper"
12
+ require "action_view/helpers/asset_url_helper"
13
+ require "action_view/helpers/atom_feed_helper"
14
+ require "action_view/helpers/cache_helper"
15
+ require "action_view/helpers/content_exfiltration_prevention_helper"
16
+ require "action_view/helpers/controller_helper"
17
+ require "action_view/helpers/csp_helper"
18
+ require "action_view/helpers/csrf_helper"
19
+ require "action_view/helpers/date_helper"
20
+ require "action_view/helpers/debug_helper"
21
+ require "action_view/helpers/form_tag_helper"
22
+ require "action_view/helpers/form_helper"
23
+ require "action_view/helpers/form_options_helper"
24
+ require "action_view/helpers/javascript_helper"
25
+ require "action_view/helpers/number_helper"
26
+ require "action_view/helpers/rendering_helper"
27
+ require "action_view/helpers/translation_helper"
4
28
 
5
- module ActionView #:nodoc:
6
- module Helpers #:nodoc:
29
+ module ActionView # :nodoc:
30
+ module Helpers # :nodoc:
7
31
  extend ActiveSupport::Autoload
8
32
 
9
- autoload :ActiveModelHelper
10
- autoload :AssetTagHelper
11
- autoload :AssetUrlHelper
12
- autoload :AtomFeedHelper
13
- autoload :CacheHelper
14
- autoload :CaptureHelper
15
- autoload :ControllerHelper
16
- autoload :CspHelper
17
- autoload :CsrfHelper
18
- autoload :DateHelper
19
- autoload :DebugHelper
20
- autoload :FormHelper
21
- autoload :FormOptionsHelper
22
- autoload :FormTagHelper
23
- autoload :JavaScriptHelper, "action_view/helpers/javascript_helper"
24
- autoload :NumberHelper
25
- autoload :OutputSafetyHelper
26
- autoload :RenderingHelper
27
- autoload :SanitizeHelper
28
- autoload :TagHelper
29
- autoload :TextHelper
30
- autoload :TranslationHelper
31
- autoload :UrlHelper
32
33
  autoload :Tags
33
34
 
34
35
  def self.eager_load!
@@ -45,6 +46,7 @@ module ActionView #:nodoc:
45
46
  include AtomFeedHelper
46
47
  include CacheHelper
47
48
  include CaptureHelper
49
+ include ContentExfiltrationPreventionHelper
48
50
  include ControllerHelper
49
51
  include CspHelper
50
52
  include CsrfHelper
@@ -4,12 +4,14 @@ require "action_view/rendering"
4
4
  require "active_support/core_ext/module/redefine_method"
5
5
 
6
6
  module ActionView
7
+ # = Action View \Layouts
8
+ #
7
9
  # Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
8
10
  # repeated setups. The inclusion pattern has pages that look like this:
9
11
  #
10
- # <%= render "shared/header" %>
12
+ # <%= render "application/header" %>
11
13
  # Hello World
12
- # <%= render "shared/footer" %>
14
+ # <%= render "application/footer" %>
13
15
  #
14
16
  # This approach is a decent way of keeping common structures isolated from the changing content, but it's verbose
15
17
  # and if you ever want to change the structure of these two includes, you'll have to change all the templates.
@@ -150,7 +152,7 @@ module ActionView
150
152
  # The template will be looked always in <tt>app/views/layouts/</tt> folder. But you can point
151
153
  # <tt>layouts</tt> folder direct also. <tt>layout "layouts/demo"</tt> is the same as <tt>layout "demo"</tt>.
152
154
  #
153
- # Setting the layout to +nil+ forces it to be looked up in the filesystem and fallbacks to the parent behavior if none exists.
155
+ # Setting the layout to +nil+ forces it to be looked up in the filesystem and falls back to the parent behavior if none exists.
154
156
  # Setting it to +nil+ is useful to re-enable template lookup overriding a previous configuration set in the parent:
155
157
  #
156
158
  # class ApplicationController < ActionController::Base
@@ -162,7 +164,7 @@ module ActionView
162
164
  # end
163
165
  #
164
166
  # class CommentsController < ApplicationController
165
- # # Will search for "comments" layout and fallback "application" layout
167
+ # # Will search for "comments" layout and fall back to "application" layout
166
168
  # layout nil
167
169
  # end
168
170
  #
@@ -183,7 +185,7 @@ module ActionView
183
185
  # be rendered directly, without wrapping a layout around the rendered view.
184
186
  #
185
187
  # Both the <tt>:only</tt> and <tt>:except</tt> condition can accept an arbitrary number of method references, so
186
- # #<tt>except: [ :rss, :text_only ]</tt> is valid, as is <tt>except: :rss</tt>.
188
+ # <tt>except: [ :rss, :text_only ]</tt> is valid, as is <tt>except: :rss</tt>.
187
189
  #
188
190
  # == Using a different layout in the action render call
189
191
  #
@@ -210,9 +212,9 @@ module ActionView
210
212
  class_attribute :_layout_conditions, instance_accessor: false, default: {}
211
213
 
212
214
  _write_layout_method
213
- end
214
215
 
215
- delegate :_layout_conditions, to: :class
216
+ delegate :_layout_conditions, to: :class
217
+ end
216
218
 
217
219
  module ClassMethods
218
220
  def inherited(klass) # :nodoc:
@@ -255,14 +257,17 @@ module ActionView
255
257
  # true:: raise an ArgumentError
256
258
  # nil:: Force default layout behavior with inheritance
257
259
  #
258
- # Return value of +Proc+ and +Symbol+ arguments should be +String+, +false+, +true+ or +nil+
260
+ # Return value of +Proc+ and +Symbol+ arguments should be +String+, +false+, +true+, or +nil+
259
261
  # with the same meaning as described above.
262
+ #
260
263
  # ==== Parameters
264
+ #
261
265
  # * <tt>layout</tt> - The layout to use.
262
266
  #
263
267
  # ==== Options (conditions)
264
- # * :only - A list of actions to apply this layout to.
265
- # * :except - Apply this layout to all actions but this one.
268
+ #
269
+ # * +:only+ - A list of actions to apply this layout to.
270
+ # * +:except+ - Apply this layout to all actions but this one.
266
271
  def layout(layout, conditions = {})
267
272
  include LayoutConditions unless conditions.empty?
268
273
 
@@ -5,7 +5,7 @@ require "active_support/log_subscriber"
5
5
  module ActionView
6
6
  # = Action View Log Subscriber
7
7
  #
8
- # Provides functionality so that Rails can output logs from Action View.
8
+ # Provides functionality so that \Rails can output logs from Action View.
9
9
  class LogSubscriber < ActiveSupport::LogSubscriber
10
10
  VIEWS_PATTERN = /^app\/views\//
11
11
 
@@ -21,6 +21,7 @@ module ActionView
21
21
  message << " (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
22
22
  end
23
23
  end
24
+ subscribe_log_level :render_template, :debug
24
25
 
25
26
  def render_partial(event)
26
27
  debug do
@@ -31,6 +32,7 @@ module ActionView
31
32
  message
32
33
  end
33
34
  end
35
+ subscribe_log_level :render_partial, :debug
34
36
 
35
37
  def render_layout(event)
36
38
  info do
@@ -38,6 +40,7 @@ module ActionView
38
40
  message << " (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
39
41
  end
40
42
  end
43
+ subscribe_log_level :render_layout, :info
41
44
 
42
45
  def render_collection(event)
43
46
  identifier = event.payload[:identifier] || "templates"
@@ -49,29 +52,60 @@ module ActionView
49
52
  message
50
53
  end
51
54
  end
55
+ subscribe_log_level :render_collection, :debug
52
56
 
53
- def start(name, id, payload)
54
- log_rendering_start(payload, name)
57
+ module Utils # :nodoc:
58
+ def logger
59
+ ActionView::Base.logger
60
+ end
55
61
 
56
- super
57
- end
62
+ private
63
+ def from_rails_root(string)
64
+ string = string.sub(rails_root, "")
65
+ string.sub!(VIEWS_PATTERN, "")
66
+ string
67
+ end
58
68
 
59
- def logger
60
- ActionView::Base.logger
69
+ def rails_root # :doc:
70
+ @root ||= "#{Rails.root}/"
71
+ end
61
72
  end
62
73
 
63
- private
64
- EMPTY = ""
65
- def from_rails_root(string) # :doc:
66
- string = string.sub(rails_root, EMPTY)
67
- string.sub!(VIEWS_PATTERN, EMPTY)
68
- string
74
+ include Utils
75
+
76
+ class Start # :nodoc:
77
+ include Utils
78
+
79
+ def start(name, id, payload)
80
+ return unless logger
81
+ logger.debug do
82
+ qualifier =
83
+ if name == "render_template.action_view"
84
+ ""
85
+ elsif name == "render_layout.action_view"
86
+ "layout "
87
+ end
88
+
89
+ return unless qualifier
90
+
91
+ message = +" Rendering #{qualifier}#{from_rails_root(payload[:identifier])}"
92
+ message << " within #{from_rails_root(payload[:layout])}" if payload[:layout]
93
+ message
94
+ end
95
+ end
96
+
97
+ def finish(name, id, payload)
98
+ end
69
99
  end
70
100
 
71
- def rails_root # :doc:
72
- @root ||= "#{Rails.root}/"
101
+ def self.attach_to(*)
102
+ ActiveSupport::Notifications.subscribe("render_template.action_view", ActionView::LogSubscriber::Start.new)
103
+ ActiveSupport::Notifications.subscribe("render_layout.action_view", ActionView::LogSubscriber::Start.new)
104
+
105
+ super
73
106
  end
74
107
 
108
+ private
75
109
  def render_count(payload) # :doc:
76
110
  if payload[:cache_hits]
77
111
  "[#{payload[:cache_hits]} / #{payload[:count]} cache hits]"
@@ -88,23 +122,6 @@ module ActionView
88
122
  "[cache miss]"
89
123
  end
90
124
  end
91
-
92
- def log_rendering_start(payload, name)
93
- debug do
94
- qualifier =
95
- if name == "render_template.action_view"
96
- ""
97
- elsif name == "render_layout.action_view"
98
- "layout "
99
- end
100
-
101
- return unless qualifier
102
-
103
- message = +" Rendering #{qualifier}#{from_rails_root(payload[:identifier])}"
104
- message << " within #{from_rails_root(payload[:layout])}" if payload[:layout]
105
- message
106
- end
107
- end
108
125
  end
109
126
  end
110
127
 
@@ -12,12 +12,11 @@ module ActionView
12
12
  # <tt>LookupContext</tt> is also responsible for generating a key, given to
13
13
  # view paths, used in the resolver cache lookup. Since this key is generated
14
14
  # only once during the request, it speeds up all cache accesses.
15
- class LookupContext #:nodoc:
16
- attr_accessor :prefixes, :rendered_format
15
+ class LookupContext # :nodoc:
16
+ attr_accessor :prefixes
17
17
 
18
- mattr_accessor :fallbacks, default: FallbackFileSystemResolver.instances
19
-
20
- mattr_accessor :registered_details, default: []
18
+ singleton_class.attr_accessor :registered_details
19
+ self.registered_details = []
21
20
 
22
21
  def self.register_detail(name, &block)
23
22
  registered_details << name
@@ -37,7 +36,7 @@ module ActionView
37
36
  end
38
37
 
39
38
  # Holds accessors for the registered details.
40
- module Accessors #:nodoc:
39
+ module Accessors # :nodoc:
41
40
  DEFAULT_PROCS = {}
42
41
  end
43
42
 
@@ -52,7 +51,7 @@ module ActionView
52
51
  register_detail(:variants) { [] }
53
52
  register_detail(:handlers) { Template::Handlers.extensions }
54
53
 
55
- class DetailsKey #:nodoc:
54
+ class DetailsKey # :nodoc:
56
55
  alias :eql? :equal?
57
56
 
58
57
  @details_keys = Concurrent::Map.new
@@ -64,18 +63,21 @@ module ActionView
64
63
  end
65
64
 
66
65
  def self.details_cache_key(details)
67
- if details[:formats]
68
- details = details.dup
69
- details[:formats] &= Template::Types.symbols
66
+ @details_keys.fetch(details) do
67
+ if formats = details[:formats]
68
+ unless Template::Types.valid_symbols?(formats)
69
+ details = details.dup
70
+ details[:formats] &= Template::Types.symbols
71
+ end
72
+ end
73
+ @details_keys[details] ||= TemplateDetails::Requested.new(**details)
70
74
  end
71
- @details_keys[details] ||= Object.new
72
75
  end
73
76
 
74
77
  def self.clear
75
- ActionView::ViewPaths.all_view_paths.each do |path_set|
76
- path_set.each(&:clear_cache)
78
+ ActionView::PathRegistry.all_resolvers.each do |resolver|
79
+ resolver.clear_cache
77
80
  end
78
- ActionView::LookupContext.fallbacks.each(&:clear_cache)
79
81
  @view_context_class = nil
80
82
  @details_keys.clear
81
83
  @digest_cache.clear
@@ -85,9 +87,9 @@ module ActionView
85
87
  @digest_cache.values
86
88
  end
87
89
 
88
- def self.view_context_class(klass)
90
+ def self.view_context_class
89
91
  @view_context_mutex.synchronize do
90
- @view_context_class ||= klass.with_empty_template_cache
92
+ @view_context_class ||= ActionView::Base.with_empty_template_cache
91
93
  end
92
94
  end
93
95
  end
@@ -98,7 +100,7 @@ module ActionView
98
100
 
99
101
  # Calculate the details key. Remove the handlers from calculation to improve performance
100
102
  # since the user cannot modify it explicitly.
101
- def details_key #:nodoc:
103
+ def details_key # :nodoc:
102
104
  @details_key ||= DetailsKey.details_cache_key(@details) if @cache
103
105
  end
104
106
 
@@ -124,50 +126,49 @@ module ActionView
124
126
  attr_reader :view_paths, :html_fallback_for_js
125
127
 
126
128
  def find(name, prefixes = [], partial = false, keys = [], options = {})
127
- @view_paths.find(*args_for_lookup(name, prefixes, partial, keys, options))
129
+ name, prefixes = normalize_name(name, prefixes)
130
+ details, details_key = detail_args_for(options)
131
+ @view_paths.find(name, prefixes, partial, details, details_key, keys)
128
132
  end
129
133
  alias :find_template :find
130
134
 
131
135
  def find_all(name, prefixes = [], partial = false, keys = [], options = {})
132
- @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options))
136
+ name, prefixes = normalize_name(name, prefixes)
137
+ details, details_key = detail_args_for(options)
138
+ @view_paths.find_all(name, prefixes, partial, details, details_key, keys)
133
139
  end
134
140
 
135
141
  def exists?(name, prefixes = [], partial = false, keys = [], **options)
136
- @view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys, options))
142
+ name, prefixes = normalize_name(name, prefixes)
143
+ details, details_key = detail_args_for(options)
144
+ @view_paths.exists?(name, prefixes, partial, details, details_key, keys)
137
145
  end
138
146
  alias :template_exists? :exists?
139
147
 
140
148
  def any?(name, prefixes = [], partial = false)
141
- @view_paths.exists?(*args_for_any(name, prefixes, partial))
149
+ name, prefixes = normalize_name(name, prefixes)
150
+ details, details_key = detail_args_for_any
151
+ @view_paths.exists?(name, prefixes, partial, details, details_key, [])
142
152
  end
143
153
  alias :any_templates? :any?
144
154
 
145
- # Adds fallbacks to the view paths. Useful in cases when you are rendering
146
- # a :file.
147
- def with_fallbacks
148
- view_paths = build_view_paths((@view_paths.paths + self.class.fallbacks).uniq)
155
+ def append_view_paths(paths)
156
+ @view_paths = build_view_paths(@view_paths.to_a + paths)
157
+ end
149
158
 
150
- if block_given?
151
- raise ArgumentError, <<~eowarn.squish
152
- Calling `with_fallbacks` with a block is not supported. Call methods on
153
- the lookup context returned by `with_fallbacks` instead.
154
- eowarn
155
- else
156
- ActionView::LookupContext.new(view_paths, @details, @prefixes)
157
- end
159
+ def prepend_view_paths(paths)
160
+ @view_paths = build_view_paths(paths + @view_paths.to_a)
158
161
  end
159
162
 
160
163
  private
161
164
  # Whenever setting view paths, makes a copy so that we can manipulate them in
162
165
  # instance objects as we wish.
163
166
  def build_view_paths(paths)
164
- ActionView::PathSet.new(Array(paths))
165
- end
166
-
167
- def args_for_lookup(name, prefixes, partial, keys, details_options)
168
- name, prefixes = normalize_name(name, prefixes)
169
- details, details_key = detail_args_for(details_options)
170
- [name, prefixes, partial || false, details, details_key, keys]
167
+ if ActionView::PathSet === paths
168
+ paths
169
+ else
170
+ ActionView::PathSet.new(Array(paths))
171
+ end
171
172
  end
172
173
 
173
174
  # Compute details hash and key according to user options (e.g. passed from #render).
@@ -184,17 +185,11 @@ module ActionView
184
185
  [user_details, details_key]
185
186
  end
186
187
 
187
- def args_for_any(name, prefixes, partial)
188
- name, prefixes = normalize_name(name, prefixes)
189
- details, details_key = detail_args_for_any
190
- [name, prefixes, partial || false, details, details_key]
191
- end
192
-
193
188
  def detail_args_for_any
194
189
  @detail_args_for_any ||= begin
195
190
  details = {}
196
191
 
197
- registered_details.each do |k|
192
+ LookupContext.registered_details.each do |k|
198
193
  if k == :variants
199
194
  details[k] = :any
200
195
  else
@@ -210,19 +205,21 @@ module ActionView
210
205
  end
211
206
  end
212
207
 
213
- # Support legacy foo.erb names even though we now ignore .erb
214
- # as well as incorrectly putting part of the path in the template
215
- # name instead of the prefix.
208
+ # Fix when prefix is specified as part of the template name
216
209
  def normalize_name(name, prefixes)
217
- prefixes = prefixes.presence
218
- parts = name.to_s.split("/")
219
- parts.shift if parts.first.empty?
220
- name = parts.pop
210
+ name = name.to_s
211
+ idx = name.rindex("/")
212
+ return name, prefixes.presence || [""] unless idx
221
213
 
222
- return name, prefixes || [""] if parts.empty?
214
+ path_prefix = name[0, idx]
215
+ path_prefix = path_prefix.from(1) if path_prefix.start_with?("/")
216
+ name = name.from(idx + 1)
223
217
 
224
- parts = parts.join("/")
225
- prefixes = prefixes ? prefixes.map { |p| "#{p}/#{parts}" } : [parts]
218
+ if !prefixes || prefixes.empty?
219
+ prefixes = [path_prefix]
220
+ else
221
+ prefixes = prefixes.map { |p| "#{p}/#{path_prefix}" }
222
+ end
226
223
 
227
224
  return name, prefixes
228
225
  end
@@ -254,7 +251,7 @@ module ActionView
254
251
  end
255
252
 
256
253
  def initialize_details(target, details)
257
- registered_details.each do |k|
254
+ LookupContext.registered_details.each do |k|
258
255
  target[k] = details[k] || Accessors::DEFAULT_PROCS[k].call
259
256
  end
260
257
  target
@@ -269,12 +266,12 @@ module ActionView
269
266
  values.concat(default_formats) if values.delete "*/*"
270
267
  values.uniq!
271
268
 
272
- invalid_values = (values - Template::Types.symbols)
273
- unless invalid_values.empty?
269
+ unless Template::Types.valid_symbols?(values)
270
+ invalid_values = values - Template::Types.symbols
274
271
  raise ArgumentError, "Invalid formats: #{invalid_values.map(&:inspect).join(", ")}"
275
272
  end
276
273
 
277
- if values == [:js]
274
+ if (values.length == 1) && (values[0] == :js)
278
275
  values << :html
279
276
  @html_fallback_for_js = true
280
277
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView
4
- module ModelNaming #:nodoc:
5
- # Converts the given object to an ActiveModel compliant one.
4
+ module ModelNaming # :nodoc:
5
+ # Converts the given object to an Active Model compliant one.
6
6
  def convert_to_model(object)
7
7
  object.respond_to?(:to_model) ? object.to_model : object
8
8
  end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView # :nodoc:
4
+ module PathRegistry # :nodoc:
5
+ @view_paths_by_class = {}
6
+ @file_system_resolvers = {}
7
+ @file_system_resolver_mutex = Mutex.new
8
+ @file_system_resolver_hooks = []
9
+
10
+ class << self
11
+ attr_reader :file_system_resolver_hooks
12
+ end
13
+
14
+ def self.get_view_paths(klass)
15
+ @view_paths_by_class[klass] || get_view_paths(klass.superclass)
16
+ end
17
+
18
+ def self.set_view_paths(klass, paths)
19
+ @view_paths_by_class[klass] = paths
20
+ end
21
+
22
+ def self.cast_file_system_resolvers(paths)
23
+ paths = Array(paths)
24
+
25
+ @file_system_resolver_mutex.synchronize do
26
+ built_resolver = false
27
+ paths = paths.map do |path|
28
+ case path
29
+ when String, Pathname
30
+ path = File.expand_path(path)
31
+ @file_system_resolvers[path] ||=
32
+ begin
33
+ built_resolver = true
34
+ FileSystemResolver.new(path)
35
+ end
36
+ else
37
+ path
38
+ end
39
+ end
40
+
41
+ file_system_resolver_hooks.each(&:call) if built_resolver
42
+ end
43
+
44
+ paths
45
+ end
46
+
47
+ def self.all_resolvers
48
+ resolvers = [all_file_system_resolvers]
49
+ resolvers.concat @view_paths_by_class.values.map(&:to_a)
50
+ resolvers.flatten.uniq
51
+ end
52
+
53
+ def self.all_file_system_resolvers
54
+ @file_system_resolvers.values
55
+ end
56
+ end
57
+ end