actionview 7.0.8.1 → 7.2.2.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.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -425
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  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 +52 -14
  8. data/lib/action_view/buffers.rb +106 -8
  9. data/lib/action_view/cache_expiry.rb +44 -41
  10. data/lib/action_view/context.rb +1 -1
  11. data/lib/action_view/dependency_tracker/{ripper_tracker.rb → ruby_tracker.rb} +4 -3
  12. data/lib/action_view/dependency_tracker.rb +1 -1
  13. data/lib/action_view/deprecator.rb +7 -0
  14. data/lib/action_view/digestor.rb +1 -1
  15. data/lib/action_view/gem_version.rb +3 -3
  16. data/lib/action_view/helpers/active_model_helper.rb +1 -1
  17. data/lib/action_view/helpers/asset_tag_helper.rb +151 -55
  18. data/lib/action_view/helpers/asset_url_helper.rb +6 -5
  19. data/lib/action_view/helpers/atom_feed_helper.rb +5 -5
  20. data/lib/action_view/helpers/cache_helper.rb +7 -13
  21. data/lib/action_view/helpers/capture_helper.rb +30 -10
  22. data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
  23. data/lib/action_view/helpers/controller_helper.rb +6 -0
  24. data/lib/action_view/helpers/csp_helper.rb +2 -2
  25. data/lib/action_view/helpers/csrf_helper.rb +3 -3
  26. data/lib/action_view/helpers/date_helper.rb +17 -19
  27. data/lib/action_view/helpers/debug_helper.rb +3 -3
  28. data/lib/action_view/helpers/form_helper.rb +248 -214
  29. data/lib/action_view/helpers/form_options_helper.rb +2 -1
  30. data/lib/action_view/helpers/form_tag_helper.rb +125 -58
  31. data/lib/action_view/helpers/javascript_helper.rb +1 -0
  32. data/lib/action_view/helpers/number_helper.rb +37 -330
  33. data/lib/action_view/helpers/output_safety_helper.rb +6 -6
  34. data/lib/action_view/helpers/rendering_helper.rb +1 -1
  35. data/lib/action_view/helpers/sanitize_helper.rb +51 -21
  36. data/lib/action_view/helpers/tag_helper.rb +210 -42
  37. data/lib/action_view/helpers/tags/base.rb +11 -52
  38. data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
  39. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
  40. data/lib/action_view/helpers/tags/collection_select.rb +3 -0
  41. data/lib/action_view/helpers/tags/date_field.rb +1 -1
  42. data/lib/action_view/helpers/tags/date_select.rb +2 -0
  43. data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
  45. data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
  46. data/lib/action_view/helpers/tags/month_field.rb +1 -1
  47. data/lib/action_view/helpers/tags/select.rb +3 -0
  48. data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
  49. data/lib/action_view/helpers/tags/time_field.rb +1 -1
  50. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
  51. data/lib/action_view/helpers/tags/week_field.rb +1 -1
  52. data/lib/action_view/helpers/tags/weekday_select.rb +3 -0
  53. data/lib/action_view/helpers/tags.rb +2 -0
  54. data/lib/action_view/helpers/text_helper.rb +157 -85
  55. data/lib/action_view/helpers/translation_helper.rb +3 -3
  56. data/lib/action_view/helpers/url_helper.rb +35 -80
  57. data/lib/action_view/helpers.rb +2 -0
  58. data/lib/action_view/layouts.rb +8 -8
  59. data/lib/action_view/log_subscriber.rb +57 -36
  60. data/lib/action_view/lookup_context.rb +29 -13
  61. data/lib/action_view/path_registry.rb +57 -0
  62. data/lib/action_view/path_set.rb +13 -14
  63. data/lib/action_view/railtie.rb +25 -3
  64. data/lib/action_view/record_identifier.rb +15 -8
  65. data/lib/action_view/render_parser/prism_render_parser.rb +127 -0
  66. data/lib/action_view/render_parser/ripper_render_parser.rb +341 -0
  67. data/lib/action_view/render_parser.rb +21 -169
  68. data/lib/action_view/renderer/abstract_renderer.rb +2 -2
  69. data/lib/action_view/renderer/collection_renderer.rb +10 -2
  70. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +2 -1
  71. data/lib/action_view/renderer/partial_renderer.rb +2 -1
  72. data/lib/action_view/renderer/renderer.rb +34 -38
  73. data/lib/action_view/renderer/streaming_template_renderer.rb +3 -2
  74. data/lib/action_view/renderer/template_renderer.rb +3 -2
  75. data/lib/action_view/rendering.rb +26 -8
  76. data/lib/action_view/template/error.rb +14 -1
  77. data/lib/action_view/template/handlers/builder.rb +4 -4
  78. data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
  79. data/lib/action_view/template/handlers/erb.rb +73 -1
  80. data/lib/action_view/template/handlers.rb +1 -1
  81. data/lib/action_view/template/html.rb +1 -1
  82. data/lib/action_view/template/raw_file.rb +1 -1
  83. data/lib/action_view/template/renderable.rb +8 -2
  84. data/lib/action_view/template/resolver.rb +9 -3
  85. data/lib/action_view/template/text.rb +1 -1
  86. data/lib/action_view/template/types.rb +25 -34
  87. data/lib/action_view/template.rb +278 -55
  88. data/lib/action_view/template_path.rb +2 -0
  89. data/lib/action_view/test_case.rb +181 -28
  90. data/lib/action_view/unbound_template.rb +17 -7
  91. data/lib/action_view/version.rb +1 -1
  92. data/lib/action_view/view_paths.rb +15 -24
  93. data/lib/action_view.rb +4 -1
  94. metadata +31 -31
  95. data/lib/action_view/ripper_ast_parser.rb +0 -198
  96. data/lib/assets/compiled/rails-ujs.js +0 -777
@@ -4,18 +4,20 @@ require "thread"
4
4
  require "delegate"
5
5
 
6
6
  module ActionView
7
- # = Action View Template
7
+ # = Action View \Template
8
8
  class Template
9
9
  extend ActiveSupport::Autoload
10
10
 
11
+ STRICT_LOCALS_REGEX = /\#\s+locals:\s+\((.*)\)/
12
+
11
13
  # === Encodings in ActionView::Template
12
14
  #
13
15
  # ActionView::Template is one of a few sources of potential
14
- # encoding issues in Rails. This is because the source for
16
+ # encoding issues in \Rails. This is because the source for
15
17
  # templates are usually read from disk, and Ruby (like most
16
18
  # encoding-aware programming languages) assumes that the
17
19
  # String retrieved through File IO is encoded in the
18
- # <tt>default_external</tt> encoding. In Rails, the default
20
+ # <tt>default_external</tt> encoding. In \Rails, the default
19
21
  # <tt>default_external</tt> encoding is UTF-8.
20
22
  #
21
23
  # As a result, if a user saves their template as ISO-8859-1
@@ -34,13 +36,13 @@ module ActionView
34
36
  # to the problem.
35
37
  # 2. The user can specify the encoding using Ruby-style
36
38
  # encoding comments in any template engine. If such
37
- # a comment is supplied, Rails will apply that encoding
39
+ # a comment is supplied, \Rails will apply that encoding
38
40
  # to the resulting compiled source returned by the
39
41
  # template handler.
40
42
  # 3. In all cases, we transcode the resulting String to
41
43
  # the UTF-8.
42
44
  #
43
- # This means that other parts of Rails can always assume
45
+ # This means that other parts of \Rails can always assume
44
46
  # that templates are encoded in UTF-8, even if the original
45
47
  # source of the template was not UTF-8.
46
48
  #
@@ -51,7 +53,7 @@ module ActionView
51
53
  # === Instructions for template handlers
52
54
  #
53
55
  # The easiest thing for you to do is to simply ignore
54
- # encodings. Rails will hand you the template source
56
+ # encodings. \Rails will hand you the template source
55
57
  # as the default_internal (generally UTF-8), raising
56
58
  # an exception for the user before sending the template
57
59
  # to you if it could not determine the original encoding.
@@ -68,7 +70,7 @@ module ActionView
68
70
  # you may indicate that you will handle encodings yourself
69
71
  # by implementing <tt>handles_encoding?</tt> on your handler.
70
72
  #
71
- # If you do, Rails will not try to encode the String
73
+ # If you do, \Rails will not try to encode the String
72
74
  # into the default_internal, passing you the unaltered
73
75
  # bytes tagged with the assumed encoding (from
74
76
  # default_external).
@@ -94,11 +96,72 @@ module ActionView
94
96
  #
95
97
  # Given this sub template rendering:
96
98
  #
97
- # <%= render "shared/header", { headline: "Welcome", person: person } %>
99
+ # <%= render "application/header", { headline: "Welcome", person: person } %>
98
100
  #
99
101
  # You can use +local_assigns+ in the sub templates to access the local variables:
100
102
  #
101
103
  # local_assigns[:headline] # => "Welcome"
104
+ #
105
+ # Each key in +local_assigns+ is available as a partial-local variable:
106
+ #
107
+ # local_assigns[:headline] # => "Welcome"
108
+ # headline # => "Welcome"
109
+ #
110
+ # Since +local_assigns+ is a +Hash+, it's compatible with Ruby 3.1's pattern
111
+ # matching assignment operator:
112
+ #
113
+ # local_assigns => { headline:, **options }
114
+ # headline # => "Welcome"
115
+ # options # => {}
116
+ #
117
+ # Pattern matching assignment also supports variable renaming:
118
+ #
119
+ # local_assigns => { headline: title }
120
+ # title # => "Welcome"
121
+ #
122
+ # If a template refers to a variable that isn't passed into the view as part
123
+ # of the <tt>locals: { ... }</tt> Hash, the template will raise an
124
+ # +ActionView::Template::Error+:
125
+ #
126
+ # <%# => raises ActionView::Template::Error %>
127
+ # <% alerts.each do |alert| %>
128
+ # <p><%= alert %></p>
129
+ # <% end %>
130
+ #
131
+ # Since +local_assigns+ returns a +Hash+ instance, you can conditionally
132
+ # read a variable, then fall back to a default value when
133
+ # the key isn't part of the <tt>locals: { ... }</tt> options:
134
+ #
135
+ # <% local_assigns.fetch(:alerts, []).each do |alert| %>
136
+ # <p><%= alert %></p>
137
+ # <% end %>
138
+ #
139
+ # Combining Ruby 3.1's pattern matching assignment with calls to
140
+ # +Hash#with_defaults+ enables compact partial-local variable
141
+ # assignments:
142
+ #
143
+ # <% local_assigns.with_defaults(alerts: []) => { headline:, alerts: } %>
144
+ #
145
+ # <h1><%= headline %></h1>
146
+ #
147
+ # <% alerts.each do |alert| %>
148
+ # <p><%= alert %></p>
149
+ # <% end %>
150
+ #
151
+ # By default, templates will accept any <tt>locals</tt> as keyword arguments
152
+ # and make them available to <tt>local_assigns</tt>. To restrict what
153
+ # <tt>local_assigns</tt> a template will accept, add a <tt>locals:</tt> magic comment:
154
+ #
155
+ # <%# locals: (headline:, alerts: []) %>
156
+ #
157
+ # <h1><%= headline %></h1>
158
+ #
159
+ # <% alerts.each do |alert| %>
160
+ # <p><%= alert %></p>
161
+ # <% end %>
162
+ #
163
+ # Read more about strict locals in {Action View Overview}[https://guides.rubyonrails.org/action_view_overview.html#strict-locals]
164
+ # in the guides.
102
165
 
103
166
  eager_autoload do
104
167
  autoload :Error
@@ -107,6 +170,7 @@ module ActionView
107
170
  autoload :Handlers
108
171
  autoload :HTML
109
172
  autoload :Inline
173
+ autoload :Types
110
174
  autoload :Sources
111
175
  autoload :Text
112
176
  autoload :Types
@@ -117,11 +181,24 @@ module ActionView
117
181
  singleton_class.attr_accessor :frozen_string_literal
118
182
  @frozen_string_literal = false
119
183
 
184
+ class << self # :nodoc:
185
+ def mime_types_implementation=(implementation)
186
+ # This method isn't thread-safe, but it's not supposed
187
+ # to be called after initialization
188
+ if self::Types != implementation
189
+ remove_const(:Types)
190
+ const_set(:Types, implementation)
191
+ end
192
+ end
193
+ end
194
+
120
195
  attr_reader :identifier, :handler
121
- attr_reader :variable, :format, :variant, :locals, :virtual_path
196
+ attr_reader :variable, :format, :variant, :virtual_path
197
+
198
+ NONE = Object.new
122
199
 
123
200
  def initialize(source, identifier, handler, locals:, format: nil, variant: nil, virtual_path: nil)
124
- @source = source
201
+ @source = source.dup
125
202
  @identifier = identifier
126
203
  @handler = handler
127
204
  @compiled = false
@@ -137,6 +214,47 @@ module ActionView
137
214
  @format = format
138
215
  @variant = variant
139
216
  @compile_mutex = Mutex.new
217
+ @strict_locals = NONE
218
+ @strict_local_keys = nil
219
+ @type = nil
220
+ end
221
+
222
+ # The locals this template has been or will be compiled for, or nil if this
223
+ # is a strict locals template.
224
+ def locals
225
+ if strict_locals?
226
+ nil
227
+ else
228
+ @locals
229
+ end
230
+ end
231
+
232
+ def spot(location) # :nodoc:
233
+ node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location)
234
+ found =
235
+ if RubyVM::InstructionSequence.compile("").to_a[4][:parser] == :prism
236
+ require "prism"
237
+
238
+ if Prism::VERSION >= "1.0.0"
239
+ result = Prism.parse(compiled_source).value
240
+ result.breadth_first_search { |node| node.node_id == node_id }
241
+ end
242
+ else
243
+ node = RubyVM::AbstractSyntaxTree.parse(compiled_source, keep_script_lines: true)
244
+ find_node_by_id(node, node_id)
245
+ end
246
+
247
+ ErrorHighlight.spot(found) if found
248
+ end
249
+
250
+ # Translate an error location returned by ErrorHighlight to the correct
251
+ # source location inside the template.
252
+ def translate_location(backtrace_location, spot)
253
+ if handler.respond_to?(:translate_location)
254
+ handler.translate_location(spot, backtrace_location, encode!) || spot
255
+ else
256
+ spot
257
+ end
140
258
  end
141
259
 
142
260
  # Returns whether the underlying handler supports streaming. If so,
@@ -151,10 +269,22 @@ module ActionView
151
269
  # This method is instrumented as "!render_template.action_view". Notice that
152
270
  # we use a bang in this instrumentation because you don't want to
153
271
  # consume this in production. This is only slow if it's being listened to.
154
- def render(view, locals, buffer = ActionView::OutputBuffer.new, add_to_stack: true, &block)
272
+ def render(view, locals, buffer = nil, implicit_locals: [], add_to_stack: true, &block)
155
273
  instrument_render_template do
156
274
  compile!(view)
157
- view._run(method_name, self, locals, buffer, add_to_stack: add_to_stack, &block)
275
+
276
+ if strict_locals? && @strict_local_keys && !implicit_locals.empty?
277
+ locals_to_ignore = implicit_locals - @strict_local_keys
278
+ locals.except!(*locals_to_ignore)
279
+ end
280
+
281
+ if buffer
282
+ view._run(method_name, self, locals, buffer, add_to_stack: add_to_stack, has_strict_locals: strict_locals?, &block)
283
+ nil
284
+ else
285
+ result = view._run(method_name, self, locals, OutputBuffer.new, add_to_stack: add_to_stack, has_strict_locals: strict_locals?, &block)
286
+ result.is_a?(OutputBuffer) ? result.to_s : result
287
+ end
158
288
  end
159
289
  rescue => e
160
290
  handle_render_error(view, e)
@@ -169,20 +299,23 @@ module ActionView
169
299
  end
170
300
 
171
301
  def inspect
172
- "#<#{self.class.name} #{short_identifier} locals=#{@locals.inspect}>"
302
+ "#<#{self.class.name} #{short_identifier} locals=#{locals.inspect}>"
173
303
  end
174
304
 
175
305
  def source
176
306
  @source.to_s
177
307
  end
178
308
 
309
+ LEADING_ENCODING_REGEXP = /\A#{ENCODING_FLAG}/
310
+ private_constant :LEADING_ENCODING_REGEXP
311
+
179
312
  # This method is responsible for properly setting the encoding of the
180
313
  # source. Until this point, we assume that the source is BINARY data.
181
314
  # If no additional information is supplied, we assume the encoding is
182
315
  # the same as <tt>Encoding.default_external</tt>.
183
316
  #
184
317
  # The user can also specify the encoding via a comment on the first
185
- # line of the template (# encoding: NAME-OF-ENCODING). This will work
318
+ # line of the template (<tt># encoding: NAME-OF-ENCODING</tt>). This will work
186
319
  # with any template engine, as we process out the encoding comment
187
320
  # before passing the source on to the template engine, leaving a
188
321
  # blank line in its stead.
@@ -194,7 +327,7 @@ module ActionView
194
327
  # Look for # encoding: *. If we find one, we'll encode the
195
328
  # String in that encoding, otherwise, we'll use the
196
329
  # default external encoding.
197
- if source.sub!(/\A#{ENCODING_FLAG}/, "")
330
+ if source.sub!(LEADING_ENCODING_REGEXP, "")
198
331
  encoding = magic_encoding = $1
199
332
  else
200
333
  encoding = Encoding.default_external
@@ -222,6 +355,32 @@ module ActionView
222
355
  end
223
356
  end
224
357
 
358
+ # This method is responsible for marking a template as having strict locals
359
+ # which means the template can only accept the locals defined in a magic
360
+ # comment. For example, if your template acceps the locals +title+ and
361
+ # +comment_count+, add the following to your template file:
362
+ #
363
+ # <%# locals: (title: "Default title", comment_count: 0) %>
364
+ #
365
+ # Strict locals are useful for validating template arguments and for
366
+ # specifying defaults.
367
+ def strict_locals!
368
+ if @strict_locals == NONE
369
+ self.source.sub!(STRICT_LOCALS_REGEX, "")
370
+ @strict_locals = $1
371
+
372
+ return if @strict_locals.nil? # Magic comment not found
373
+
374
+ @strict_locals = "**nil" if @strict_locals.blank?
375
+ end
376
+
377
+ @strict_locals
378
+ end
379
+
380
+ # Returns whether a template is using strict locals.
381
+ def strict_locals?
382
+ strict_locals!
383
+ end
225
384
 
226
385
  # Exceptions are marshalled when using the parallel test runner with DRb, so we need
227
386
  # to ensure that references to the template object can be marshalled as well. This means forgoing
@@ -235,7 +394,26 @@ module ActionView
235
394
  @compile_mutex = Mutex.new
236
395
  end
237
396
 
397
+ def method_name # :nodoc:
398
+ @method_name ||= begin
399
+ m = +"_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
400
+ m.tr!("-", "_")
401
+ m
402
+ end
403
+ end
404
+
238
405
  private
406
+ def find_node_by_id(node, node_id)
407
+ return node if node.node_id == node_id
408
+
409
+ node.children.grep(node.class).each do |child|
410
+ found = find_node_by_id(child, node_id)
411
+ return found if found
412
+ end
413
+
414
+ false
415
+ end
416
+
239
417
  # Compile a template. This method ensures a template is compiled
240
418
  # just once and removes the source after it is compiled.
241
419
  def compile!(view)
@@ -260,27 +438,29 @@ module ActionView
260
438
  end
261
439
  end
262
440
 
263
- # Among other things, this method is responsible for properly setting
264
- # the encoding of the compiled template.
265
- #
266
- # If the template engine handles encodings, we send the encoded
267
- # String to the engine without further processing. This allows
268
- # the template engine to support additional mechanisms for
269
- # specifying the encoding. For instance, ERB supports <%# encoding: %>
270
- #
271
- # Otherwise, after we figure out the correct encoding, we then
272
- # encode the source into <tt>Encoding.default_internal</tt>.
273
- # In general, this means that templates will be UTF-8 inside of Rails,
274
- # regardless of the original source encoding.
275
- def compile(mod)
441
+ # This method compiles the source of the template. The compilation of templates
442
+ # involves setting strict_locals! if applicable, encoding the template, and setting
443
+ # frozen string literal.
444
+ def compiled_source
445
+ set_strict_locals = strict_locals!
276
446
  source = encode!
277
447
  code = @handler.call(self, source)
278
448
 
449
+ method_arguments =
450
+ if set_strict_locals
451
+ if set_strict_locals.include?("&")
452
+ "local_assigns, output_buffer, #{set_strict_locals}"
453
+ else
454
+ "local_assigns, output_buffer, #{set_strict_locals}, &_"
455
+ end
456
+ else
457
+ "local_assigns, output_buffer, &_"
458
+ end
459
+
279
460
  # Make sure that the resulting String to be eval'd is in the
280
461
  # encoding of the code
281
- original_source = source
282
462
  source = +<<-end_src
283
- def #{method_name}(local_assigns, output_buffer)
463
+ def #{method_name}(#{method_arguments})
284
464
  @virtual_path = #{@virtual_path.inspect};#{locals_code};#{code}
285
465
  end
286
466
  end_src
@@ -299,17 +479,71 @@ module ActionView
299
479
  raise WrongEncodingError.new(source, Encoding.default_internal)
300
480
  end
301
481
 
482
+ if Template.frozen_string_literal
483
+ "# frozen_string_literal: true\n#{source}"
484
+ else
485
+ source
486
+ end
487
+ end
488
+
489
+ # Among other things, this method is responsible for properly setting
490
+ # the encoding of the compiled template.
491
+ #
492
+ # If the template engine handles encodings, we send the encoded
493
+ # String to the engine without further processing. This allows
494
+ # the template engine to support additional mechanisms for
495
+ # specifying the encoding. For instance, ERB supports <%# encoding: %>
496
+ #
497
+ # Otherwise, after we figure out the correct encoding, we then
498
+ # encode the source into <tt>Encoding.default_internal</tt>.
499
+ # In general, this means that templates will be UTF-8 inside of Rails,
500
+ # regardless of the original source encoding.
501
+ def compile(mod)
302
502
  begin
303
- if Template.frozen_string_literal
304
- mod.module_eval("# frozen_string_literal: true\n#{source}", identifier, -1)
305
- else
306
- mod.module_eval(source, identifier, 0)
307
- end
503
+ mod.module_eval(compiled_source, identifier, offset)
308
504
  rescue SyntaxError
309
505
  # Account for when code in the template is not syntactically valid; e.g. if we're using
310
506
  # ERB and the user writes <%= foo( %>, attempting to call a helper `foo` and interpolate
311
507
  # the result into the template, but missing an end parenthesis.
312
- raise SyntaxErrorInTemplate.new(self, original_source)
508
+ raise SyntaxErrorInTemplate.new(self, encode!)
509
+ end
510
+
511
+ return unless strict_locals?
512
+
513
+ parameters = mod.instance_method(method_name).parameters
514
+ parameters -= [[:req, :local_assigns], [:req, :output_buffer]]
515
+
516
+ # Check compiled method parameters to ensure that only kwargs
517
+ # were provided as strict locals, preventing `locals: (foo, *foo)` etc
518
+ # and allowing `locals: (foo:)`.
519
+ non_kwarg_parameters = parameters.select do |parameter|
520
+ ![:keyreq, :key, :keyrest, :nokey].include?(parameter[0])
521
+ end
522
+
523
+ non_kwarg_parameters.pop if non_kwarg_parameters.last == %i(block _)
524
+
525
+ unless non_kwarg_parameters.empty?
526
+ mod.undef_method(method_name)
527
+
528
+ raise ArgumentError.new(
529
+ "#{non_kwarg_parameters.map { |_, name| "`#{name}`" }.to_sentence} set as non-keyword " \
530
+ "#{'argument'.pluralize(non_kwarg_parameters.length)} for #{short_identifier}. " \
531
+ "Locals can only be set as keyword arguments."
532
+ )
533
+ end
534
+
535
+ unless parameters.any? { |type, _| type == :keyrest }
536
+ parameters.map!(&:last)
537
+ parameters.sort!
538
+ @strict_local_keys = parameters.freeze
539
+ end
540
+ end
541
+
542
+ def offset
543
+ if Template.frozen_string_literal
544
+ -1
545
+ else
546
+ 0
313
547
  end
314
548
  end
315
549
 
@@ -322,33 +556,22 @@ module ActionView
322
556
  end
323
557
  end
324
558
 
559
+ RUBY_RESERVED_KEYWORDS = ::ActiveSupport::Delegation::RUBY_RESERVED_KEYWORDS
560
+ private_constant :RUBY_RESERVED_KEYWORDS
561
+
325
562
  def locals_code
563
+ return "" if strict_locals?
564
+
326
565
  # Only locals with valid variable names get set directly. Others will
327
566
  # still be available in local_assigns.
328
- locals = @locals - Module::RUBY_RESERVED_KEYWORDS
329
- deprecated_locals = locals.grep(/\A@+/)
330
- if deprecated_locals.any?
331
- ActiveSupport::Deprecation.warn(<<~MSG)
332
- Passing instance variables to `render` is deprecated.
333
- In Rails 7.1, #{deprecated_locals.to_sentence} will be ignored.
334
- MSG
335
- locals = locals.grep(/\A@?(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
336
- else
337
- locals = locals.grep(/\A(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
338
- end
567
+ locals = @locals - RUBY_RESERVED_KEYWORDS
568
+
569
+ locals = locals.grep(/\A(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
339
570
 
340
571
  # Assign for the same variable is to suppress unused variable warning
341
572
  locals.each_with_object(+"") { |key, code| code << "#{key} = local_assigns[:#{key}]; #{key} = #{key};" }
342
573
  end
343
574
 
344
- def method_name
345
- @method_name ||= begin
346
- m = +"_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
347
- m.tr!("-", "_")
348
- m
349
- end
350
- end
351
-
352
575
  def identifier_method_name
353
576
  short_identifier.tr("^a-z_", "_")
354
577
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView
4
+ # = Action View \TemplatePath
5
+ #
4
6
  # Represents a template path within ActionView's lookup and rendering system,
5
7
  # like "users/show"
6
8
  #