Refactor compiled_source

This is a continuation of #46706 to make sure we don't need to set an
instance variable to `@original_source` for the `compile` method to use.

We can't call `strict_locals!` after encode so we need to set it to a
local variable in `complile`. We changed the `strict_locals!` method to
check `NONE` instead of lazily defining instance variables which let us
simplify `strict_locals?` to return the value of `strict_locals!`. This
simplifies and clarifies the code.

Co-authored-by: Aaron Patterson tenderlove@ruby-lang.org
This commit is contained in:
eileencodes 2022-12-14 14:12:25 -05:00
parent 06a872fd27
commit 334fa122b7
No known key found for this signature in database
GPG Key ID: BA5C575120BBE8DF
1 changed files with 20 additions and 18 deletions

View File

@ -122,6 +122,8 @@ module ActionView
attr_reader :identifier, :handler
attr_reader :variable, :format, :variant, :virtual_path
NONE = Object.new
def initialize(source, identifier, handler, locals:, format: nil, variant: nil, virtual_path: nil)
@source = source.dup
@identifier = identifier
@ -139,6 +141,7 @@ module ActionView
@format = format
@variant = variant
@compile_mutex = Mutex.new
@strict_locals = NONE
end
# The locals this template has been or will be compiled for, or nil if this
@ -177,10 +180,10 @@ module ActionView
instrument_render_template do
compile!(view)
if buffer
view._run(method_name, self, locals, buffer, add_to_stack: add_to_stack, has_strict_locals: @strict_locals, &block)
view._run(method_name, self, locals, buffer, add_to_stack: add_to_stack, has_strict_locals: strict_locals?, &block)
nil
else
view._run(method_name, self, locals, OutputBuffer.new, add_to_stack: add_to_stack, has_strict_locals: @strict_locals, &block)&.to_s
view._run(method_name, self, locals, OutputBuffer.new, add_to_stack: add_to_stack, has_strict_locals: strict_locals?, &block)&.to_s
end
end
rescue => e
@ -256,20 +259,20 @@ module ActionView
# and extracting any arguments declared in the format
# locals: (message:, label: "My Message")
def strict_locals!
self.source.sub!(STRICT_LOCALS_REGEX, "")
@strict_locals = $1
if @strict_locals == NONE
self.source.sub!(STRICT_LOCALS_REGEX, "")
@strict_locals = $1
return if @strict_locals.nil? # Magic comment not found
return if @strict_locals.nil? # Magic comment not found
@strict_locals = "**nil" if @strict_locals.blank?
@strict_locals = "**nil" if @strict_locals.blank?
end
@strict_locals
end
def strict_locals?
if defined?(@strict_locals)
@strict_locals
else
STRICT_LOCALS_REGEX === self.source
end
strict_locals!
end
# Exceptions are marshalled when using the parallel test runner with DRb, so we need
@ -321,20 +324,19 @@ module ActionView
# involves setting strict_locals! if applicable, encoding the template, and setting
# frozen string literal.
def compiled_source
strict_locals!
set_strict_locals = strict_locals!
source = encode!
code = @handler.call(self, source)
method_arguments =
if @strict_locals
"output_buffer, #{@strict_locals}"
if set_strict_locals
"output_buffer, #{set_strict_locals}"
else
"local_assigns, output_buffer"
end
# Make sure that the resulting String to be eval'd is in the
# encoding of the code
@original_source = source
source = +<<-end_src
def #{method_name}(#{method_arguments})
@virtual_path = #{@virtual_path.inspect};#{locals_code};#{code}
@ -381,10 +383,10 @@ module ActionView
# Account for when code in the template is not syntactically valid; e.g. if we're using
# ERB and the user writes <%= foo( %>, attempting to call a helper `foo` and interpolate
# the result into the template, but missing an end parenthesis.
raise SyntaxErrorInTemplate.new(self, @original_source)
raise SyntaxErrorInTemplate.new(self, encode!)
end
return unless @strict_locals
return unless strict_locals?
# Check compiled method parameters to ensure that only kwargs
# were provided as strict locals, preventing `locals: (foo, *foo)` etc
@ -423,7 +425,7 @@ module ActionView
end
def locals_code
return "" if @strict_locals
return "" if strict_locals?
# Only locals with valid variable names get set directly. Others will
# still be available in local_assigns.