actionview 7.0.8.3 → 7.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +235 -372
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/app/assets/javascripts/rails-ujs.esm.js +668 -0
  6. data/app/assets/javascripts/rails-ujs.js +606 -0
  7. data/lib/action_view/base.rb +28 -7
  8. data/lib/action_view/buffers.rb +106 -8
  9. data/lib/action_view/cache_expiry.rb +40 -43
  10. data/lib/action_view/context.rb +1 -1
  11. data/lib/action_view/deprecator.rb +7 -0
  12. data/lib/action_view/digestor.rb +1 -1
  13. data/lib/action_view/gem_version.rb +4 -4
  14. data/lib/action_view/helpers/active_model_helper.rb +1 -1
  15. data/lib/action_view/helpers/asset_tag_helper.rb +130 -46
  16. data/lib/action_view/helpers/asset_url_helper.rb +6 -5
  17. data/lib/action_view/helpers/atom_feed_helper.rb +5 -5
  18. data/lib/action_view/helpers/cache_helper.rb +3 -9
  19. data/lib/action_view/helpers/capture_helper.rb +24 -10
  20. data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
  21. data/lib/action_view/helpers/controller_helper.rb +6 -0
  22. data/lib/action_view/helpers/csp_helper.rb +2 -2
  23. data/lib/action_view/helpers/csrf_helper.rb +2 -2
  24. data/lib/action_view/helpers/date_helper.rb +17 -19
  25. data/lib/action_view/helpers/debug_helper.rb +3 -3
  26. data/lib/action_view/helpers/form_helper.rb +43 -18
  27. data/lib/action_view/helpers/form_options_helper.rb +2 -1
  28. data/lib/action_view/helpers/form_tag_helper.rb +43 -9
  29. data/lib/action_view/helpers/javascript_helper.rb +1 -0
  30. data/lib/action_view/helpers/number_helper.rb +2 -1
  31. data/lib/action_view/helpers/output_safety_helper.rb +2 -2
  32. data/lib/action_view/helpers/rendering_helper.rb +1 -1
  33. data/lib/action_view/helpers/sanitize_helper.rb +33 -14
  34. data/lib/action_view/helpers/tag_helper.rb +5 -27
  35. data/lib/action_view/helpers/tags/base.rb +11 -52
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
  37. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
  38. data/lib/action_view/helpers/tags/collection_select.rb +3 -0
  39. data/lib/action_view/helpers/tags/date_field.rb +1 -1
  40. data/lib/action_view/helpers/tags/date_select.rb +2 -0
  41. data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
  42. data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
  43. data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
  44. data/lib/action_view/helpers/tags/month_field.rb +1 -1
  45. data/lib/action_view/helpers/tags/select.rb +3 -0
  46. data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
  47. data/lib/action_view/helpers/tags/time_field.rb +1 -1
  48. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
  49. data/lib/action_view/helpers/tags/week_field.rb +1 -1
  50. data/lib/action_view/helpers/tags/weekday_select.rb +3 -0
  51. data/lib/action_view/helpers/tags.rb +2 -0
  52. data/lib/action_view/helpers/text_helper.rb +32 -16
  53. data/lib/action_view/helpers/translation_helper.rb +3 -3
  54. data/lib/action_view/helpers/url_helper.rb +41 -14
  55. data/lib/action_view/helpers.rb +2 -0
  56. data/lib/action_view/layouts.rb +4 -2
  57. data/lib/action_view/log_subscriber.rb +49 -32
  58. data/lib/action_view/lookup_context.rb +29 -13
  59. data/lib/action_view/path_registry.rb +57 -0
  60. data/lib/action_view/path_set.rb +13 -14
  61. data/lib/action_view/railtie.rb +26 -3
  62. data/lib/action_view/record_identifier.rb +15 -8
  63. data/lib/action_view/renderer/abstract_renderer.rb +1 -1
  64. data/lib/action_view/renderer/collection_renderer.rb +9 -1
  65. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +2 -1
  66. data/lib/action_view/renderer/partial_renderer.rb +2 -1
  67. data/lib/action_view/renderer/renderer.rb +2 -0
  68. data/lib/action_view/renderer/streaming_template_renderer.rb +3 -2
  69. data/lib/action_view/renderer/template_renderer.rb +3 -2
  70. data/lib/action_view/rendering.rb +22 -4
  71. data/lib/action_view/ripper_ast_parser.rb +5 -5
  72. data/lib/action_view/template/error.rb +14 -1
  73. data/lib/action_view/template/handlers/builder.rb +4 -4
  74. data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
  75. data/lib/action_view/template/handlers/erb.rb +73 -1
  76. data/lib/action_view/template/handlers.rb +1 -1
  77. data/lib/action_view/template/html.rb +1 -1
  78. data/lib/action_view/template/raw_file.rb +1 -1
  79. data/lib/action_view/template/renderable.rb +1 -1
  80. data/lib/action_view/template/resolver.rb +10 -2
  81. data/lib/action_view/template/text.rb +1 -1
  82. data/lib/action_view/template/types.rb +25 -34
  83. data/lib/action_view/template.rb +179 -52
  84. data/lib/action_view/template_path.rb +2 -0
  85. data/lib/action_view/test_case.rb +8 -5
  86. data/lib/action_view/unbound_template.rb +15 -5
  87. data/lib/action_view/version.rb +1 -1
  88. data/lib/action_view/view_paths.rb +15 -24
  89. data/lib/action_view.rb +4 -1
  90. metadata +26 -26
@@ -10,8 +10,7 @@ require "concurrent/map"
10
10
  module ActionView
11
11
  # = Action View Resolver
12
12
  class Resolver
13
- Path = ActionView::TemplatePath
14
- deprecate_constant :Path
13
+ include ActiveSupport::Deprecation::DeprecatedConstantAccessor
15
14
 
16
15
  class PathParser # :nodoc:
17
16
  ParsedPath = Struct.new(:path, :details)
@@ -65,6 +64,11 @@ module ActionView
65
64
  _find_all(name, prefix, partial, details, key, locals)
66
65
  end
67
66
 
67
+ def built_templates # :nodoc:
68
+ # Used for error pages
69
+ []
70
+ end
71
+
68
72
  def all_template_paths # :nodoc:
69
73
  # Not implemented by default
70
74
  []
@@ -122,6 +126,10 @@ module ActionView
122
126
  end
123
127
  end
124
128
 
129
+ def built_templates # :nodoc:
130
+ @unbound_templates.values.flatten.flat_map(&:built_templates)
131
+ end
132
+
125
133
  private
126
134
  def _find_all(name, prefix, partial, details, key, locals)
127
135
  requested_details = key || TemplateDetails::Requested.new(**details)
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView # :nodoc:
4
- # = Action View Text Template
5
4
  class Template # :nodoc:
5
+ # = Action View Text Template
6
6
  class Text # :nodoc:
7
7
  attr_accessor :type
8
8
 
@@ -4,11 +4,14 @@ require "active_support/core_ext/module/attribute_accessors"
4
4
 
5
5
  module ActionView
6
6
  class Template # :nodoc:
7
- module Types
8
- class Type
9
- SET = Struct.new(:symbols).new([ :html, :text, :js, :css, :xml, :json ])
7
+ # SimpleType is mostly just a stub implementation for when Action View
8
+ # is used without Action Dispatch.
9
+ class SimpleType # :nodoc:
10
+ @symbols = [ :html, :text, :js, :css, :xml, :json ]
11
+ class << self
12
+ attr_reader :symbols
10
13
 
11
- def self.[](type)
14
+ def [](type)
12
15
  if type.is_a?(self)
13
16
  type
14
17
  else
@@ -16,44 +19,32 @@ module ActionView
16
19
  end
17
20
  end
18
21
 
19
- attr_reader :symbol
20
-
21
- def initialize(symbol)
22
- @symbol = symbol.to_sym
23
- end
24
-
25
- def to_s
26
- @symbol.to_s
27
- end
28
- alias to_str to_s
29
-
30
- def ref
31
- @symbol
32
- end
33
- alias to_sym ref
34
-
35
- def ==(type)
36
- @symbol == type.to_sym unless type.blank?
22
+ def valid_symbols?(symbols) # :nodoc
23
+ symbols.all? { |s| @symbols.include?(s) }
37
24
  end
38
25
  end
39
26
 
40
- class << self
41
- attr_accessor :type_klass
27
+ attr_reader :symbol
42
28
 
43
- def delegate_to(klass)
44
- self.type_klass = klass
45
- end
29
+ def initialize(symbol)
30
+ @symbol = symbol.to_sym
31
+ end
46
32
 
47
- def [](type)
48
- type_klass[type]
49
- end
33
+ def to_s
34
+ @symbol.to_s
35
+ end
36
+ alias to_str to_s
50
37
 
51
- def symbols
52
- type_klass::SET.symbols
53
- end
38
+ def ref
39
+ @symbol
54
40
  end
41
+ alias to_sym ref
55
42
 
56
- delegate_to Type
43
+ def ==(type)
44
+ @symbol == type.to_sym unless type.blank?
45
+ end
57
46
  end
47
+
48
+ Types = SimpleType # :nodoc:
58
49
  end
59
50
  end
@@ -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).
@@ -107,6 +109,7 @@ module ActionView
107
109
  autoload :Handlers
108
110
  autoload :HTML
109
111
  autoload :Inline
112
+ autoload :Types
110
113
  autoload :Sources
111
114
  autoload :Text
112
115
  autoload :Types
@@ -117,11 +120,24 @@ module ActionView
117
120
  singleton_class.attr_accessor :frozen_string_literal
118
121
  @frozen_string_literal = false
119
122
 
123
+ class << self # :nodoc:
124
+ def mime_types_implementation=(implementation)
125
+ # This method isn't thread-safe, but it's not supposed
126
+ # to be called after initialization
127
+ if self::Types != implementation
128
+ remove_const(:Types)
129
+ const_set(:Types, implementation)
130
+ end
131
+ end
132
+ end
133
+
120
134
  attr_reader :identifier, :handler
121
- attr_reader :variable, :format, :variant, :locals, :virtual_path
135
+ attr_reader :variable, :format, :variant, :virtual_path
136
+
137
+ NONE = Object.new
122
138
 
123
139
  def initialize(source, identifier, handler, locals:, format: nil, variant: nil, virtual_path: nil)
124
- @source = source
140
+ @source = source.dup
125
141
  @identifier = identifier
126
142
  @handler = handler
127
143
  @compiled = false
@@ -137,6 +153,36 @@ module ActionView
137
153
  @format = format
138
154
  @variant = variant
139
155
  @compile_mutex = Mutex.new
156
+ @strict_locals = NONE
157
+ @type = nil
158
+ end
159
+
160
+ # The locals this template has been or will be compiled for, or nil if this
161
+ # is a strict locals template.
162
+ def locals
163
+ if strict_locals?
164
+ nil
165
+ else
166
+ @locals
167
+ end
168
+ end
169
+
170
+ def spot(location) # :nodoc:
171
+ ast = RubyVM::AbstractSyntaxTree.parse(compiled_source, keep_script_lines: true)
172
+ node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location)
173
+ node = find_node_by_id(ast, node_id)
174
+
175
+ ErrorHighlight.spot(node)
176
+ end
177
+
178
+ # Translate an error location returned by ErrorHighlight to the correct
179
+ # source location inside the template.
180
+ def translate_location(backtrace_location, spot)
181
+ if handler.respond_to?(:translate_location)
182
+ handler.translate_location(spot, backtrace_location, encode!) || spot
183
+ else
184
+ spot
185
+ end
140
186
  end
141
187
 
142
188
  # Returns whether the underlying handler supports streaming. If so,
@@ -151,10 +197,15 @@ module ActionView
151
197
  # This method is instrumented as "!render_template.action_view". Notice that
152
198
  # we use a bang in this instrumentation because you don't want to
153
199
  # 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)
200
+ def render(view, locals, buffer = nil, add_to_stack: true, &block)
155
201
  instrument_render_template do
156
202
  compile!(view)
157
- view._run(method_name, self, locals, buffer, add_to_stack: add_to_stack, &block)
203
+ if buffer
204
+ view._run(method_name, self, locals, buffer, add_to_stack: add_to_stack, has_strict_locals: strict_locals?, &block)
205
+ nil
206
+ else
207
+ view._run(method_name, self, locals, OutputBuffer.new, add_to_stack: add_to_stack, has_strict_locals: strict_locals?, &block)&.to_s
208
+ end
158
209
  end
159
210
  rescue => e
160
211
  handle_render_error(view, e)
@@ -169,13 +220,16 @@ module ActionView
169
220
  end
170
221
 
171
222
  def inspect
172
- "#<#{self.class.name} #{short_identifier} locals=#{@locals.inspect}>"
223
+ "#<#{self.class.name} #{short_identifier} locals=#{locals.inspect}>"
173
224
  end
174
225
 
175
226
  def source
176
227
  @source.to_s
177
228
  end
178
229
 
230
+ LEADING_ENCODING_REGEXP = /\A#{ENCODING_FLAG}/
231
+ private_constant :LEADING_ENCODING_REGEXP
232
+
179
233
  # This method is responsible for properly setting the encoding of the
180
234
  # source. Until this point, we assume that the source is BINARY data.
181
235
  # If no additional information is supplied, we assume the encoding is
@@ -194,7 +248,7 @@ module ActionView
194
248
  # Look for # encoding: *. If we find one, we'll encode the
195
249
  # String in that encoding, otherwise, we'll use the
196
250
  # default external encoding.
197
- if source.sub!(/\A#{ENCODING_FLAG}/, "")
251
+ if source.sub!(LEADING_ENCODING_REGEXP, "")
198
252
  encoding = magic_encoding = $1
199
253
  else
200
254
  encoding = Encoding.default_external
@@ -222,6 +276,32 @@ module ActionView
222
276
  end
223
277
  end
224
278
 
279
+ # This method is responsible for marking a template as having strict locals
280
+ # which means the template can only accept the locals defined in a magic
281
+ # comment. For example, if your template acceps the locals +title+ and
282
+ # +comment_count+, add the following to your template file:
283
+ #
284
+ # <%# locals: (title: "Default title", comment_count: 0) %>
285
+ #
286
+ # Strict locals are useful for validating template arguments and for
287
+ # specifying defaults.
288
+ def strict_locals!
289
+ if @strict_locals == NONE
290
+ self.source.sub!(STRICT_LOCALS_REGEX, "")
291
+ @strict_locals = $1
292
+
293
+ return if @strict_locals.nil? # Magic comment not found
294
+
295
+ @strict_locals = "**nil" if @strict_locals.blank?
296
+ end
297
+
298
+ @strict_locals
299
+ end
300
+
301
+ # Returns whether a template is using strict locals.
302
+ def strict_locals?
303
+ strict_locals!
304
+ end
225
305
 
226
306
  # Exceptions are marshalled when using the parallel test runner with DRb, so we need
227
307
  # to ensure that references to the template object can be marshalled as well. This means forgoing
@@ -235,7 +315,26 @@ module ActionView
235
315
  @compile_mutex = Mutex.new
236
316
  end
237
317
 
318
+ def method_name # :nodoc:
319
+ @method_name ||= begin
320
+ m = +"_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
321
+ m.tr!("-", "_")
322
+ m
323
+ end
324
+ end
325
+
238
326
  private
327
+ def find_node_by_id(node, node_id)
328
+ return node if node.node_id == node_id
329
+
330
+ node.children.grep(node.class).each do |child|
331
+ found = find_node_by_id(child, node_id)
332
+ return found if found
333
+ end
334
+
335
+ false
336
+ end
337
+
239
338
  # Compile a template. This method ensures a template is compiled
240
339
  # just once and removes the source after it is compiled.
241
340
  def compile!(view)
@@ -260,27 +359,25 @@ module ActionView
260
359
  end
261
360
  end
262
361
 
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)
362
+ # This method compiles the source of the template. The compilation of templates
363
+ # involves setting strict_locals! if applicable, encoding the template, and setting
364
+ # frozen string literal.
365
+ def compiled_source
366
+ set_strict_locals = strict_locals!
276
367
  source = encode!
277
368
  code = @handler.call(self, source)
278
369
 
370
+ method_arguments =
371
+ if set_strict_locals
372
+ "output_buffer, #{set_strict_locals}"
373
+ else
374
+ "local_assigns, output_buffer"
375
+ end
376
+
279
377
  # Make sure that the resulting String to be eval'd is in the
280
378
  # encoding of the code
281
- original_source = source
282
379
  source = +<<-end_src
283
- def #{method_name}(local_assigns, output_buffer)
380
+ def #{method_name}(#{method_arguments})
284
381
  @virtual_path = #{@virtual_path.inspect};#{locals_code};#{code}
285
382
  end
286
383
  end_src
@@ -299,17 +396,61 @@ module ActionView
299
396
  raise WrongEncodingError.new(source, Encoding.default_internal)
300
397
  end
301
398
 
399
+ if Template.frozen_string_literal
400
+ "# frozen_string_literal: true\n#{source}"
401
+ else
402
+ source
403
+ end
404
+ end
405
+
406
+ # Among other things, this method is responsible for properly setting
407
+ # the encoding of the compiled template.
408
+ #
409
+ # If the template engine handles encodings, we send the encoded
410
+ # String to the engine without further processing. This allows
411
+ # the template engine to support additional mechanisms for
412
+ # specifying the encoding. For instance, ERB supports <%# encoding: %>
413
+ #
414
+ # Otherwise, after we figure out the correct encoding, we then
415
+ # encode the source into <tt>Encoding.default_internal</tt>.
416
+ # In general, this means that templates will be UTF-8 inside of Rails,
417
+ # regardless of the original source encoding.
418
+ def compile(mod)
302
419
  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
420
+ mod.module_eval(compiled_source, identifier, offset)
308
421
  rescue SyntaxError
309
422
  # Account for when code in the template is not syntactically valid; e.g. if we're using
310
423
  # ERB and the user writes <%= foo( %>, attempting to call a helper `foo` and interpolate
311
424
  # the result into the template, but missing an end parenthesis.
312
- raise SyntaxErrorInTemplate.new(self, original_source)
425
+ raise SyntaxErrorInTemplate.new(self, encode!)
426
+ end
427
+
428
+ return unless strict_locals?
429
+
430
+ # Check compiled method parameters to ensure that only kwargs
431
+ # were provided as strict locals, preventing `locals: (foo, *foo)` etc
432
+ # and allowing `locals: (foo:)`.
433
+
434
+ non_kwarg_parameters =
435
+ (mod.instance_method(method_name).parameters - [[:req, :output_buffer]]).
436
+ select { |parameter| ![:keyreq, :key, :keyrest, :nokey].include?(parameter[0]) }
437
+
438
+ return unless non_kwarg_parameters.any?
439
+
440
+ mod.undef_method(method_name)
441
+
442
+ raise ArgumentError.new(
443
+ "#{non_kwarg_parameters.map { |_, name| "`#{name}`" }.to_sentence} set as non-keyword " \
444
+ "#{'argument'.pluralize(non_kwarg_parameters.length)} for #{short_identifier}. " \
445
+ "Locals can only be set as keyword arguments."
446
+ )
447
+ end
448
+
449
+ def offset
450
+ if Template.frozen_string_literal
451
+ -1
452
+ else
453
+ 0
313
454
  end
314
455
  end
315
456
 
@@ -323,32 +464,18 @@ module ActionView
323
464
  end
324
465
 
325
466
  def locals_code
467
+ return "" if strict_locals?
468
+
326
469
  # Only locals with valid variable names get set directly. Others will
327
470
  # still be available in local_assigns.
328
471
  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
472
+
473
+ locals = locals.grep(/\A(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
339
474
 
340
475
  # Assign for the same variable is to suppress unused variable warning
341
476
  locals.each_with_object(+"") { |key, code| code << "#{key} = local_assigns[:#{key}]; #{key} = #{key};" }
342
477
  end
343
478
 
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
479
  def identifier_method_name
353
480
  short_identifier.tr("^a-z_", "_")
354
481
  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
  #
@@ -110,9 +110,7 @@ module ActionView
110
110
  @controller = controller_class.new
111
111
  @request = @controller.request
112
112
  @view_flow = ActionView::OutputFlow.new
113
- # empty string ensures buffer has UTF-8 encoding as
114
- # new without arguments returns ASCII-8BIT encoded buffer like String#new
115
- @output_buffer = ActiveSupport::SafeBuffer.new ""
113
+ @output_buffer = ActionView::OutputBuffer.new
116
114
  @rendered = +""
117
115
 
118
116
  test_case_instance = self
@@ -181,7 +179,7 @@ module ActionView
181
179
  private
182
180
  # Need to experiment if this priority is the best one: rendered => output_buffer
183
181
  def document_root_element
184
- Nokogiri::HTML::Document.parse(@rendered.blank? ? @output_buffer : @rendered).root
182
+ Rails::Dom::Testing.html_document.parse(@rendered.blank? ? @output_buffer.to_str : @rendered).root
185
183
  end
186
184
 
187
185
  module Locals
@@ -227,6 +225,10 @@ module ActionView
227
225
  :@_result,
228
226
  :@_routes,
229
227
  :@controller,
228
+ :@_controller,
229
+ :@_request,
230
+ :@_config,
231
+ :@_default_form_builder,
230
232
  :@_layouts,
231
233
  :@_files,
232
234
  :@_rendered_views,
@@ -245,7 +247,7 @@ module ActionView
245
247
  :@view_context_class,
246
248
  :@view_flow,
247
249
  :@_subscribers,
248
- :@html_document
250
+ :@html_document,
249
251
  ]
250
252
 
251
253
  def _user_defined_ivars
@@ -277,6 +279,7 @@ module ActionView
277
279
  super
278
280
  end
279
281
  end
282
+ ruby2_keywords(:method_missing)
280
283
 
281
284
  def respond_to_missing?(name, include_private = false)
282
285
  begin
@@ -18,21 +18,31 @@ module ActionView
18
18
  end
19
19
 
20
20
  def bind_locals(locals)
21
- if template = @templates[locals]
22
- template
23
- else
21
+ unless template = @templates[locals]
24
22
  @write_lock.synchronize do
25
23
  normalized_locals = normalize_locals(locals)
26
24
 
27
25
  # We need ||=, both to dedup on the normalized locals and to check
28
26
  # while holding the lock.
29
- @templates[normalized_locals] ||= build_template(normalized_locals)
27
+ template = (@templates[normalized_locals] ||= build_template(normalized_locals))
30
28
 
31
29
  # This may have already been assigned, but we've already de-dup'd so
32
30
  # reassignment is fine.
33
- @templates[locals.dup] = @templates[normalized_locals]
31
+ @templates[locals.dup] = template
32
+
33
+ if template.strict_locals?
34
+ # Under strict locals, we only need one template.
35
+ # This replaces the @templates Concurrent::Map with a hash which
36
+ # returns this template for every key.
37
+ @templates = Hash.new(template).freeze
38
+ end
34
39
  end
35
40
  end
41
+ template
42
+ end
43
+
44
+ def built_templates # :nodoc:
45
+ @templates.values
36
46
  end
37
47
 
38
48
  private
@@ -3,7 +3,7 @@
3
3
  require_relative "gem_version"
4
4
 
5
5
  module ActionView
6
- # Returns the currently loaded version of Action View as a <tt>Gem::Version</tt>.
6
+ # Returns the currently loaded version of Action View as a +Gem::Version+.
7
7
  def self.version
8
8
  gem_version
9
9
  end