Also pass local_assigns to strict locals templates

If one of the locals conflict with a keyword, typically `class`.

The potentially confusing part however is that if you define a default
value, `local_assigns` won't respect it.
This commit is contained in:
Jean Boussier 2024-06-20 08:51:47 +02:00
parent 770b353896
commit 9ea92d4cda
3 changed files with 11 additions and 5 deletions

@ -265,7 +265,7 @@ def _run(method, template, locals, buffer, add_to_stack: true, has_strict_locals
if has_strict_locals
begin
public_send(method, buffer, **locals, &block)
public_send(method, locals, buffer, **locals, &block)
rescue ArgumentError => argument_error
raise(
ArgumentError,

@ -439,9 +439,9 @@ def compiled_source
method_arguments =
if set_strict_locals
if set_strict_locals.include?("&")
"output_buffer, #{set_strict_locals}"
"local_assigns, output_buffer, #{set_strict_locals}"
else
"output_buffer, #{set_strict_locals}, &_"
"local_assigns, output_buffer, #{set_strict_locals}, &_"
end
else
"local_assigns, output_buffer, &_"
@ -500,11 +500,12 @@ def compile(mod)
return unless strict_locals?
parameters = mod.instance_method(method_name).parameters - [[:req, :output_buffer]]
parameters = mod.instance_method(method_name).parameters
parameters -= [[:req, :local_assigns], [:req, :output_buffer]]
# Check compiled method parameters to ensure that only kwargs
# were provided as strict locals, preventing `locals: (foo, *foo)` etc
# and allowing `locals: (foo:)`.
non_kwarg_parameters = parameters.select do |parameter|
![:keyreq, :key, :keyrest, :nokey].include?(parameter[0])
end

@ -238,6 +238,11 @@ def test_rails_injected_locals_can_be_specified
assert_equal "Hello", render(message: "Hello", implicit_locals: %i[message])
end
def test_rails_local_assigns_and_strict_locals
@template = new_template("<%# locals: (class: ) -%>\n<%= local_assigns[:class] %>")
assert_equal "some-class", render(class: "some-class", implicit_locals: %i[message])
end
def test_rails_injected_locals_can_be_specified_as_kwargs
@template = new_template("<%# locals: (message: 'Hello', **kwargs) -%>\n<%= kwargs[:message_counter] %>-<%= kwargs[:message_iteration] %>")
assert_equal "1-2", render(message: "Hello", message_counter: 1, message_iteration: 2, implicit_locals: %i[message_counter message_iteration])