actionview 6.0.0 → 6.1.0

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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +169 -162
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/action_view/base.rb +21 -52
  6. data/lib/action_view/cache_expiry.rb +1 -3
  7. data/lib/action_view/context.rb +0 -1
  8. data/lib/action_view/dependency_tracker.rb +10 -4
  9. data/lib/action_view/digestor.rb +3 -2
  10. data/lib/action_view/flows.rb +0 -1
  11. data/lib/action_view/gem_version.rb +1 -1
  12. data/lib/action_view/helpers/active_model_helper.rb +0 -1
  13. data/lib/action_view/helpers/asset_tag_helper.rb +41 -16
  14. data/lib/action_view/helpers/asset_url_helper.rb +6 -4
  15. data/lib/action_view/helpers/atom_feed_helper.rb +2 -1
  16. data/lib/action_view/helpers/cache_helper.rb +11 -18
  17. data/lib/action_view/helpers/date_helper.rb +5 -6
  18. data/lib/action_view/helpers/form_helper.rb +61 -19
  19. data/lib/action_view/helpers/form_options_helper.rb +7 -16
  20. data/lib/action_view/helpers/form_tag_helper.rb +9 -7
  21. data/lib/action_view/helpers/javascript_helper.rb +7 -5
  22. data/lib/action_view/helpers/number_helper.rb +9 -8
  23. data/lib/action_view/helpers/rendering_helper.rb +11 -3
  24. data/lib/action_view/helpers/sanitize_helper.rb +2 -2
  25. data/lib/action_view/helpers/tag_helper.rb +94 -19
  26. data/lib/action_view/helpers/tags/base.rb +9 -6
  27. data/lib/action_view/helpers/tags/check_box.rb +0 -1
  28. data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -1
  29. data/lib/action_view/helpers/tags/collection_helpers.rb +0 -1
  30. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -1
  31. data/lib/action_view/helpers/tags/color_field.rb +0 -1
  32. data/lib/action_view/helpers/tags/date_field.rb +1 -2
  33. data/lib/action_view/helpers/tags/date_select.rb +2 -3
  34. data/lib/action_view/helpers/tags/datetime_field.rb +0 -1
  35. data/lib/action_view/helpers/tags/datetime_local_field.rb +1 -2
  36. data/lib/action_view/helpers/tags/label.rb +4 -1
  37. data/lib/action_view/helpers/tags/month_field.rb +1 -2
  38. data/lib/action_view/helpers/tags/radio_button.rb +0 -1
  39. data/lib/action_view/helpers/tags/select.rb +1 -2
  40. data/lib/action_view/helpers/tags/text_field.rb +0 -1
  41. data/lib/action_view/helpers/tags/time_field.rb +1 -2
  42. data/lib/action_view/helpers/tags/week_field.rb +1 -2
  43. data/lib/action_view/helpers/text_helper.rb +1 -2
  44. data/lib/action_view/helpers/translation_helper.rb +98 -53
  45. data/lib/action_view/helpers/url_helper.rb +107 -13
  46. data/lib/action_view/layouts.rb +3 -5
  47. data/lib/action_view/log_subscriber.rb +26 -11
  48. data/lib/action_view/lookup_context.rb +7 -21
  49. data/lib/action_view/path_set.rb +0 -4
  50. data/lib/action_view/railtie.rb +35 -46
  51. data/lib/action_view/record_identifier.rb +0 -1
  52. data/lib/action_view/renderer/abstract_renderer.rb +92 -14
  53. data/lib/action_view/renderer/collection_renderer.rb +192 -0
  54. data/lib/action_view/renderer/object_renderer.rb +34 -0
  55. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +25 -26
  56. data/lib/action_view/renderer/partial_renderer.rb +20 -283
  57. data/lib/action_view/renderer/renderer.rb +44 -1
  58. data/lib/action_view/renderer/streaming_template_renderer.rb +5 -3
  59. data/lib/action_view/renderer/template_renderer.rb +16 -14
  60. data/lib/action_view/rendering.rb +3 -2
  61. data/lib/action_view/routing_url_for.rb +1 -1
  62. data/lib/action_view/template/error.rb +9 -14
  63. data/lib/action_view/template/handlers/erb/erubi.rb +9 -7
  64. data/lib/action_view/template/handlers/erb.rb +10 -15
  65. data/lib/action_view/template/handlers.rb +0 -26
  66. data/lib/action_view/template/html.rb +1 -11
  67. data/lib/action_view/template/raw_file.rb +0 -3
  68. data/lib/action_view/template/renderable.rb +24 -0
  69. data/lib/action_view/template/resolver.rb +83 -45
  70. data/lib/action_view/template/text.rb +0 -3
  71. data/lib/action_view/template.rb +9 -50
  72. data/lib/action_view/test_case.rb +20 -28
  73. data/lib/action_view/testing/resolvers.rb +10 -32
  74. data/lib/action_view/unbound_template.rb +4 -5
  75. data/lib/action_view/view_paths.rb +34 -37
  76. data/lib/action_view.rb +5 -1
  77. data/lib/assets/compiled/rails-ujs.js +3 -3
  78. metadata +17 -11
@@ -81,19 +81,19 @@ module ActionView
81
81
  end
82
82
  end
83
83
 
84
- def source_extract(indentation = 0, output = :console)
85
- return unless num = line_number
84
+ def source_extract(indentation = 0)
85
+ return [] unless num = line_number
86
86
  num = num.to_i
87
87
 
88
- source_code = @template.source.split("\n")
88
+ source_code = @template.encode!.split("\n")
89
89
 
90
90
  start_on_line = [ num - SOURCE_CODE_RADIUS - 1, 0 ].max
91
91
  end_on_line = [ num + SOURCE_CODE_RADIUS - 1, source_code.length].min
92
92
 
93
93
  indent = end_on_line.to_s.size + indentation
94
- return unless source_code = source_code[start_on_line..end_on_line]
94
+ return [] unless source_code = source_code[start_on_line..end_on_line]
95
95
 
96
- formatted_code_for(source_code, start_on_line, indent, output)
96
+ formatted_code_for(source_code, start_on_line, indent)
97
97
  end
98
98
 
99
99
  def sub_template_of(template_path)
@@ -114,7 +114,6 @@ module ActionView
114
114
  end
115
115
 
116
116
  private
117
-
118
117
  def source_location
119
118
  if line_number
120
119
  "on line ##{line_number} of "
@@ -123,15 +122,11 @@ module ActionView
123
122
  end + file_name
124
123
  end
125
124
 
126
- def formatted_code_for(source_code, line_counter, indent, output)
127
- start_value = (output == :html) ? {} : []
128
- source_code.inject(start_value) do |result, line|
125
+ def formatted_code_for(source_code, line_counter, indent)
126
+ indent_template = "%#{indent}s: %s"
127
+ source_code.map do |line|
129
128
  line_counter += 1
130
- if output == :html
131
- result.update(line_counter.to_s => "%#{indent}s %s\n" % ["", line])
132
- else
133
- result << "%#{indent}s: %s" % [line_counter, line]
134
- end
129
+ indent_template % [line_counter, line]
135
130
  end
136
131
  end
137
132
  end
@@ -13,9 +13,11 @@ module ActionView
13
13
 
14
14
  # Dup properties so that we don't modify argument
15
15
  properties = Hash[properties]
16
- properties[:preamble] = ""
17
- properties[:postamble] = "@output_buffer.to_s"
18
- properties[:bufvar] = "@output_buffer"
16
+
17
+ properties[:bufvar] ||= "@output_buffer"
18
+ properties[:preamble] ||= ""
19
+ properties[:postamble] ||= "#{properties[:bufvar]}.to_s"
20
+
19
21
  properties[:escapefunc] = ""
20
22
 
21
23
  super
@@ -37,7 +39,7 @@ module ActionView
37
39
  if text == "\n"
38
40
  @newline_pending += 1
39
41
  else
40
- src << "@output_buffer.safe_append='"
42
+ src << bufvar << ".safe_append='"
41
43
  src << "\n" * @newline_pending if @newline_pending > 0
42
44
  src << text.gsub(/['\\]/, '\\\\\&')
43
45
  src << "'.freeze;"
@@ -52,9 +54,9 @@ module ActionView
52
54
  flush_newline_if_pending(src)
53
55
 
54
56
  if (indicator == "==") || @escape
55
- src << "@output_buffer.safe_expr_append="
57
+ src << bufvar << ".safe_expr_append="
56
58
  else
57
- src << "@output_buffer.append="
59
+ src << bufvar << ".append="
58
60
  end
59
61
 
60
62
  if BLOCK_EXPR.match?(code)
@@ -76,7 +78,7 @@ module ActionView
76
78
 
77
79
  def flush_newline_if_pending(src)
78
80
  if @newline_pending > 0
79
- src << "@output_buffer.safe_append='#{"\n" * @newline_pending}'.freeze;"
81
+ src << bufvar << ".safe_append='#{"\n" * @newline_pending}'.freeze;"
80
82
  @newline_pending = 0
81
83
  end
82
84
  end
@@ -16,16 +16,6 @@ module ActionView
16
16
  # Do not escape templates of these mime types.
17
17
  class_attribute :escape_ignore_list, default: ["text/plain"]
18
18
 
19
- [self, singleton_class].each do |base|
20
- base.alias_method :escape_whitelist, :escape_ignore_list
21
- base.alias_method :escape_whitelist=, :escape_ignore_list=
22
-
23
- base.deprecate(
24
- escape_whitelist: "use #escape_ignore_list instead",
25
- :escape_whitelist= => "use #escape_ignore_list= instead"
26
- )
27
- end
28
-
29
19
  ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*")
30
20
 
31
21
  def self.call(template, source)
@@ -45,7 +35,7 @@ module ActionView
45
35
  # wrong, we can still find an encoding tag
46
36
  # (<%# encoding %>) inside the String using a regular
47
37
  # expression
48
- template_source = source.dup.force_encoding(Encoding::ASCII_8BIT)
38
+ template_source = source.b
49
39
 
50
40
  erb = template_source.gsub(ENCODING_TAG, "")
51
41
  encoding = $2
@@ -55,15 +45,20 @@ module ActionView
55
45
  # Always make sure we return a String in the default_internal
56
46
  erb.encode!
57
47
 
58
- self.class.erb_implementation.new(
59
- erb,
48
+ options = {
60
49
  escape: (self.class.escape_ignore_list.include? template.type),
61
50
  trim: (self.class.erb_trim_mode == "-")
62
- ).src
51
+ }
52
+
53
+ if ActionView::Base.annotate_rendered_view_with_filenames && template.format == :html
54
+ options[:preamble] = "@output_buffer.safe_append='<!-- BEGIN #{template.short_identifier} -->';"
55
+ options[:postamble] = "@output_buffer.safe_append='<!-- END #{template.short_identifier} -->';@output_buffer.to_s"
56
+ end
57
+
58
+ self.class.erb_implementation.new(erb, options).src
63
59
  end
64
60
 
65
61
  private
66
-
67
62
  def valid_encoding(string, encoding)
68
63
  # If a magic encoding comment was found, tag the
69
64
  # String with this encoding. This is for a case
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/deprecation"
4
-
5
3
  module ActionView #:nodoc:
6
4
  # = Action View Template Handlers
7
5
  class Template #:nodoc:
@@ -26,35 +24,11 @@ module ActionView #:nodoc:
26
24
  @@template_extensions ||= @@template_handlers.keys
27
25
  end
28
26
 
29
- class LegacyHandlerWrapper < SimpleDelegator # :nodoc:
30
- def call(view, source)
31
- __getobj__.call(ActionView::Template::LegacyTemplate.new(view, source))
32
- end
33
- end
34
-
35
27
  # Register an object that knows how to handle template files with the given
36
28
  # extensions. This can be used to implement new template types.
37
29
  # The handler must respond to +:call+, which will be passed the template
38
30
  # and should return the rendered template as a String.
39
31
  def register_template_handler(*extensions, handler)
40
- params = if handler.is_a?(Proc)
41
- handler.parameters
42
- else
43
- handler.method(:call).parameters
44
- end
45
-
46
- unless params.find_all { |type, _| type == :req || type == :opt }.length >= 2
47
- ActiveSupport::Deprecation.warn <<~eowarn
48
- Single arity template handlers are deprecated. Template handlers must
49
- now accept two parameters, the view object and the source for the view object.
50
- Change:
51
- >> #{handler}.call(#{params.map(&:last).join(", ")})
52
- To:
53
- >> #{handler}.call(#{params.map(&:last).join(", ")}, source)
54
- eowarn
55
- handler = LegacyHandlerWrapper.new(handler)
56
- end
57
-
58
32
  raise(ArgumentError, "Extension is required") if extensions.empty?
59
33
  extensions.each do |extension|
60
34
  @@template_handlers[extension.to_sym] = handler
@@ -1,19 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/deprecation"
4
-
5
3
  module ActionView #:nodoc:
6
4
  # = Action View HTML Template
7
5
  class Template #:nodoc:
8
6
  class HTML #:nodoc:
9
7
  attr_reader :type
10
8
 
11
- def initialize(string, type = nil)
12
- unless type
13
- ActiveSupport::Deprecation.warn "ActionView::Template::HTML#initialize requires a type parameter"
14
- type = :html
15
- end
16
-
9
+ def initialize(string, type)
17
10
  @string = string.to_s
18
11
  @type = type
19
12
  end
@@ -35,9 +28,6 @@ module ActionView #:nodoc:
35
28
  def format
36
29
  @type
37
30
  end
38
-
39
- def formats; Array(format); end
40
- deprecate :formats
41
31
  end
42
32
  end
43
33
  end
@@ -20,9 +20,6 @@ module ActionView #:nodoc:
20
20
  def render(*args)
21
21
  ::File.read(@filename)
22
22
  end
23
-
24
- def formats; Array(format); end
25
- deprecate :formats
26
23
  end
27
24
  end
28
25
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ # = Action View Renderable Template for objects that respond to #render_in
5
+ class Template
6
+ class Renderable # :nodoc:
7
+ def initialize(renderable)
8
+ @renderable = renderable
9
+ end
10
+
11
+ def identifier
12
+ @renderable.class.name
13
+ end
14
+
15
+ def render(context, *args)
16
+ @renderable.render_in(context)
17
+ end
18
+
19
+ def format
20
+ @renderable.format
21
+ end
22
+ end
23
+ end
24
+ end
@@ -35,6 +35,41 @@ module ActionView
35
35
  alias :to_s :to_str
36
36
  end
37
37
 
38
+ class PathParser # :nodoc:
39
+ def build_path_regex
40
+ handlers = Template::Handlers.extensions.map { |x| Regexp.escape(x) }.join("|")
41
+ formats = Template::Types.symbols.map { |x| Regexp.escape(x) }.join("|")
42
+ locales = "[a-z]{2}(?:-[A-Z]{2})?"
43
+ variants = "[^.]*"
44
+
45
+ %r{
46
+ \A
47
+ (?:(?<prefix>.*)/)?
48
+ (?<partial>_)?
49
+ (?<action>.*?)
50
+ (?:\.(?<locale>#{locales}))??
51
+ (?:\.(?<format>#{formats}))??
52
+ (?:\+(?<variant>#{variants}))??
53
+ (?:\.(?<handler>#{handlers}))?
54
+ \z
55
+ }x
56
+ end
57
+
58
+ def parse(path)
59
+ @regex ||= build_path_regex
60
+ match = @regex.match(path)
61
+ {
62
+ prefix: match[:prefix] || "",
63
+ action: match[:action],
64
+ partial: !!match[:partial],
65
+ locale: match[:locale]&.to_sym,
66
+ handler: match[:handler]&.to_sym,
67
+ format: match[:format]&.to_sym,
68
+ variant: match[:variant]
69
+ }
70
+ end
71
+ end
72
+
38
73
  # Threadsafe template cache
39
74
  class Cache #:nodoc:
40
75
  class SmallCache < Concurrent::Map
@@ -43,13 +78,13 @@ module ActionView
43
78
  end
44
79
  end
45
80
 
46
- # preallocate all the default blocks for performance/memory consumption reasons
81
+ # Preallocate all the default blocks for performance/memory consumption reasons
47
82
  PARTIAL_BLOCK = lambda { |cache, partial| cache[partial] = SmallCache.new }
48
83
  PREFIX_BLOCK = lambda { |cache, prefix| cache[prefix] = SmallCache.new(&PARTIAL_BLOCK) }
49
84
  NAME_BLOCK = lambda { |cache, name| cache[name] = SmallCache.new(&PREFIX_BLOCK) }
50
85
  KEY_BLOCK = lambda { |cache, key| cache[key] = SmallCache.new(&NAME_BLOCK) }
51
86
 
52
- # usually a majority of template look ups return nothing, use this canonical preallocated array to save memory
87
+ # Usually a majority of template look ups return nothing, use this canonical preallocated array to save memory
53
88
  NO_TEMPLATES = [].freeze
54
89
 
55
90
  def initialize
@@ -58,7 +93,7 @@ module ActionView
58
93
  end
59
94
 
60
95
  def inspect
61
- "#<#{self.class.name}:0x#{(object_id << 1).to_s(16)} keys=#{@data.size} queries=#{@query_cache.size}>"
96
+ "#{to_s[0..-2]} keys=#{@data.size} queries=#{@query_cache.size}>"
62
97
  end
63
98
 
64
99
  # Cache the templates returned by the block
@@ -75,7 +110,7 @@ module ActionView
75
110
  @query_cache.clear
76
111
  end
77
112
 
78
- # Get the cache size. Do not call this
113
+ # Get the cache size. Do not call this
79
114
  # method. This method is not guaranteed to be here ever.
80
115
  def size # :nodoc:
81
116
  size = 0
@@ -93,7 +128,6 @@ module ActionView
93
128
  end
94
129
 
95
130
  private
96
-
97
131
  def canonical_no_templates(templates)
98
132
  templates.empty? ? NO_TEMPLATES : templates
99
133
  end
@@ -122,15 +156,11 @@ module ActionView
122
156
  end
123
157
  end
124
158
 
125
- alias :find_all_anywhere :find_all
126
- deprecate :find_all_anywhere
127
-
128
159
  def find_all_with_query(query) # :nodoc:
129
160
  @cache.cache_query(query) { find_template_paths(File.join(@path, query)) }
130
161
  end
131
162
 
132
163
  private
133
-
134
164
  def _find_all(name, prefix, partial, details, key, locals)
135
165
  find_templates(name, prefix, partial, details, locals)
136
166
  end
@@ -166,24 +196,20 @@ module ActionView
166
196
  EXTENSIONS = { locale: ".", formats: ".", variants: "+", handlers: "." }
167
197
  DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}"
168
198
 
169
- def initialize(pattern = nil)
170
- if pattern
171
- ActiveSupport::Deprecation.warn "Specifying a custom path for #{self.class} is deprecated. Implement a custom Resolver subclass instead."
172
- @pattern = pattern
173
- else
174
- @pattern = DEFAULT_PATTERN
175
- end
199
+ def initialize
200
+ @pattern = DEFAULT_PATTERN
176
201
  @unbound_templates = Concurrent::Map.new
177
- super()
202
+ @path_parser = PathParser.new
203
+ super
178
204
  end
179
205
 
180
206
  def clear_cache
181
207
  @unbound_templates.clear
182
- super()
208
+ @path_parser = PathParser.new
209
+ super
183
210
  end
184
211
 
185
212
  private
186
-
187
213
  def _find_all(name, prefix, partial, details, key, locals)
188
214
  path = Path.build(name, prefix, partial)
189
215
  query(path, details, details[:formats], locals, cache: !!key)
@@ -207,9 +233,13 @@ module ActionView
207
233
  end
208
234
  end
209
235
 
236
+ def source_for_template(template)
237
+ Template::Sources::File.new(template)
238
+ end
239
+
210
240
  def build_unbound_template(template, virtual_path)
211
241
  handler, format, variant = extract_handler_and_format_and_variant(template)
212
- source = Template::Sources::File.new(template)
242
+ source = source_for_template(template)
213
243
 
214
244
  UnboundTemplate.new(
215
245
  source,
@@ -226,6 +256,10 @@ module ActionView
226
256
  end
227
257
 
228
258
  def find_template_paths_from_details(path, details)
259
+ if path.name.include?(".")
260
+ ActiveSupport::Deprecation.warn("Rendering actions with '.' in the name is deprecated: #{path}")
261
+ end
262
+
229
263
  query = build_query(path, details)
230
264
  find_template_paths(query)
231
265
  end
@@ -252,7 +286,7 @@ module ActionView
252
286
  query.gsub!(/:prefix(\/)?/, prefix)
253
287
 
254
288
  partial = escape_entry(path.partial? ? "_#{path.name}" : path.name)
255
- query.gsub!(/:action/, partial)
289
+ query.gsub!(":action", partial)
256
290
 
257
291
  details.each do |ext, candidates|
258
292
  if ext == :variants && candidates == :any
@@ -273,22 +307,11 @@ module ActionView
273
307
  # from the path, or the handler, we should return the array of formats given
274
308
  # to the resolver.
275
309
  def extract_handler_and_format_and_variant(path)
276
- pieces = File.basename(path).split(".")
277
- pieces.shift
278
-
279
- extension = pieces.pop
280
-
281
- handler = Template.handler_for_extension(extension)
282
- format, variant = pieces.last.split(EXTENSIONS[:variants], 2) if pieces.last
283
- format = if format
284
- Template::Types[format]&.ref
285
- else
286
- if handler.respond_to?(:default_format) # default_format can return nil
287
- handler.default_format
288
- else
289
- nil
290
- end
291
- end
310
+ details = @path_parser.parse(path)
311
+
312
+ handler = Template.handler_for_extension(details[:handler])
313
+ format = details[:format] || handler.try(:default_format)
314
+ variant = details[:variant]
292
315
 
293
316
  # Template::Types[format] and handler.default_format can return nil
294
317
  [handler, format, variant]
@@ -299,9 +322,9 @@ module ActionView
299
322
  class FileSystemResolver < PathResolver
300
323
  attr_reader :path
301
324
 
302
- def initialize(path, pattern = nil)
325
+ def initialize(path)
303
326
  raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
304
- super(pattern)
327
+ super()
305
328
  @path = File.expand_path(path)
306
329
  end
307
330
 
@@ -323,15 +346,27 @@ module ActionView
323
346
  end
324
347
 
325
348
  private
326
-
327
- def find_template_paths_from_details(path, details)
349
+ def find_candidate_template_paths(path)
328
350
  # Instead of checking for every possible path, as our other globs would
329
351
  # do, scan the directory for files with the right prefix.
330
352
  query = "#{escape_entry(File.join(@path, path))}*"
331
353
 
354
+ Dir[query].reject do |filename|
355
+ File.directory?(filename)
356
+ end
357
+ end
358
+
359
+ def find_template_paths_from_details(path, details)
360
+ if path.name.include?(".")
361
+ # Fall back to the unoptimized resolver, which will warn
362
+ return super
363
+ end
364
+
365
+ candidates = find_candidate_template_paths(path)
366
+
332
367
  regex = build_regex(path, details)
333
368
 
334
- Dir[query].uniq.reject do |filename|
369
+ candidates.uniq.reject do |filename|
335
370
  # This regex match does double duty of finding only files which match
336
371
  # details (instead of just matching the prefix) and also filtering for
337
372
  # case-insensitive file systems.
@@ -343,7 +378,7 @@ module ActionView
343
378
  # We can use the matches found by the regex and sort by their index in
344
379
  # details.
345
380
  match = filename.match(regex)
346
- EXTENSIONS.keys.reverse.map do |ext|
381
+ EXTENSIONS.keys.map do |ext|
347
382
  if ext == :variants && details[ext] == :any
348
383
  match[ext].nil? ? 0 : 1
349
384
  elsif match[ext].nil?
@@ -358,13 +393,16 @@ module ActionView
358
393
  end
359
394
 
360
395
  def build_regex(path, details)
361
- query = escape_entry(File.join(@path, path))
396
+ query = Regexp.escape(File.join(@path, path))
362
397
  exts = EXTENSIONS.map do |ext, prefix|
363
398
  match =
364
399
  if ext == :variants && details[ext] == :any
365
400
  ".*?"
366
401
  else
367
- details[ext].compact.uniq.map { |e| Regexp.escape(e) }.join("|")
402
+ arr = details[ext].compact
403
+ arr.uniq!
404
+ arr.map! { |e| Regexp.escape(e) }
405
+ arr.join("|")
368
406
  end
369
407
  prefix = Regexp.escape(prefix)
370
408
  "(#{prefix}(?<#{ext}>#{match}))?"
@@ -27,9 +27,6 @@ module ActionView #:nodoc:
27
27
  def format
28
28
  :text
29
29
  end
30
-
31
- def formats; Array(format); end
32
- deprecate :formats
33
30
  end
34
31
  end
35
32
  end
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/object/try"
4
- require "active_support/core_ext/kernel/singleton_class"
5
- require "active_support/deprecation"
6
3
  require "thread"
7
4
  require "delegate"
8
5
 
@@ -11,14 +8,6 @@ module ActionView
11
8
  class Template
12
9
  extend ActiveSupport::Autoload
13
10
 
14
- def self.finalize_compiled_template_methods
15
- ActiveSupport::Deprecation.warn "ActionView::Template.finalize_compiled_template_methods is deprecated and has no effect"
16
- end
17
-
18
- def self.finalize_compiled_template_methods=(_)
19
- ActiveSupport::Deprecation.warn "ActionView::Template.finalize_compiled_template_methods= is deprecated and has no effect"
20
- end
21
-
22
11
  # === Encodings in ActionView::Template
23
12
  #
24
13
  # ActionView::Template is one of a few sources of potential
@@ -114,6 +103,7 @@ module ActionView
114
103
  eager_autoload do
115
104
  autoload :Error
116
105
  autoload :RawFile
106
+ autoload :Renderable
117
107
  autoload :Handlers
118
108
  autoload :HTML
119
109
  autoload :Inline
@@ -124,15 +114,10 @@ module ActionView
124
114
 
125
115
  extend Template::Handlers
126
116
 
127
- attr_reader :identifier, :handler, :original_encoding, :updated_at
117
+ attr_reader :identifier, :handler
128
118
  attr_reader :variable, :format, :variant, :locals, :virtual_path
129
119
 
130
- def initialize(source, identifier, handler, format: nil, variant: nil, locals: nil, virtual_path: nil, updated_at: nil)
131
- unless locals
132
- ActiveSupport::Deprecation.warn "ActionView::Template#initialize requires a locals parameter"
133
- locals = []
134
- end
135
-
120
+ def initialize(source, identifier, handler, locals:, format: nil, variant: nil, virtual_path: nil)
136
121
  @source = source
137
122
  @identifier = identifier
138
123
  @handler = handler
@@ -141,32 +126,16 @@ module ActionView
141
126
  @virtual_path = virtual_path
142
127
 
143
128
  @variable = if @virtual_path
144
- base = @virtual_path[-1] == "/" ? "" : ::File.basename(@virtual_path)
129
+ base = @virtual_path.end_with?("/") ? "" : ::File.basename(@virtual_path)
145
130
  base =~ /\A_?(.*?)(?:\.\w+)*\z/
146
131
  $1.to_sym
147
132
  end
148
133
 
149
- if updated_at
150
- ActiveSupport::Deprecation.warn "ActionView::Template#updated_at is deprecated"
151
- @updated_at = updated_at
152
- else
153
- @updated_at = Time.now
154
- end
155
134
  @format = format
156
135
  @variant = variant
157
136
  @compile_mutex = Mutex.new
158
137
  end
159
138
 
160
- deprecate :original_encoding
161
- deprecate :updated_at
162
- deprecate def virtual_path=(_); end
163
- deprecate def locals=(_); end
164
- deprecate def formats=(_); end
165
- deprecate def formats; Array(format); end
166
- deprecate def variants=(_); end
167
- deprecate def variants; [variant]; end
168
- deprecate def refresh(_); self; end
169
-
170
139
  # Returns whether the underlying handler supports streaming. If so,
171
140
  # a streaming buffer *may* be passed when it starts rendering.
172
141
  def supports_streaming?
@@ -179,10 +148,10 @@ module ActionView
179
148
  # This method is instrumented as "!render_template.action_view". Notice that
180
149
  # we use a bang in this instrumentation because you don't want to
181
150
  # consume this in production. This is only slow if it's being listened to.
182
- def render(view, locals, buffer = ActionView::OutputBuffer.new, &block)
151
+ def render(view, locals, buffer = ActionView::OutputBuffer.new, add_to_stack: true, &block)
183
152
  instrument_render_template do
184
153
  compile!(view)
185
- view._run(method_name, self, locals, buffer, &block)
154
+ view._run(method_name, self, locals, buffer, add_to_stack: add_to_stack, &block)
186
155
  end
187
156
  rescue => e
188
157
  handle_render_error(view, e)
@@ -193,7 +162,7 @@ module ActionView
193
162
  end
194
163
 
195
164
  def short_identifier
196
- @short_identifier ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", "") : identifier
165
+ @short_identifier ||= defined?(Rails.root) ? identifier.delete_prefix("#{Rails.root}/") : identifier
197
166
  end
198
167
 
199
168
  def inspect
@@ -255,16 +224,15 @@ module ActionView
255
224
  # to ensure that references to the template object can be marshalled as well. This means forgoing
256
225
  # the marshalling of the compiler mutex and instantiating that again on unmarshalling.
257
226
  def marshal_dump # :nodoc:
258
- [ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @updated_at, @format, @variant ]
227
+ [ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @format, @variant ]
259
228
  end
260
229
 
261
230
  def marshal_load(array) # :nodoc:
262
- @source, @identifier, @handler, @compiled, @locals, @virtual_path, @updated_at, @format, @variant = *array
231
+ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @format, @variant = *array
263
232
  @compile_mutex = Mutex.new
264
233
  end
265
234
 
266
235
  private
267
-
268
236
  # Compile a template. This method ensures a template is compiled
269
237
  # just once and removes the source after it is compiled.
270
238
  def compile!(view)
@@ -289,15 +257,6 @@ module ActionView
289
257
  end
290
258
  end
291
259
 
292
- class LegacyTemplate < DelegateClass(Template) # :nodoc:
293
- attr_reader :source
294
-
295
- def initialize(template, source)
296
- super(template)
297
- @source = source
298
- end
299
- end
300
-
301
260
  # Among other things, this method is responsible for properly setting
302
261
  # the encoding of the compiled template.
303
262
  #