Compare commits

...

4 Commits

Author SHA1 Message Date
Mike Angell
10f7ed4b9c Tidy instance variables 2019-09-17 02:33:02 +10:00
Mike Angell
3bf8470a49 Avoid deep flatten 2019-09-17 02:30:20 +10:00
Mike Angell
740241a997 Enable Instance Assigns to survive many renders 2019-09-17 01:59:55 +10:00
Mike Angell
29dfe2aea4 Prevent needing to squash instance assigns
Instead of needing to squash instance assigns, we instead just put them at the bottom of the enviornment stack.

This simplifies the code base and gains extra performance by not needing to loop over scopes and environments.
2019-09-16 21:42:51 +10:00
3 changed files with 33 additions and 23 deletions

View File

@@ -21,9 +21,7 @@ module Liquid
end
def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil, static_registers = {}, static_environments = {})
@environments = [environments]
@environments.flatten!
@environments = environments.is_a?(Array) ? environments : [environments]
@static_environments = [static_environments].flat_map(&:freeze).freeze
@scopes = [(outer_scope || {})]
@registers = registers
@@ -33,16 +31,14 @@ module Liquid
@strict_variables = false
@resource_limits = resource_limits || ResourceLimits.new(Template.default_resource_limits)
@base_scope_depth = 0
squash_instance_assigns_with_environments
@interrupts = []
@filters = []
@global_filter = nil
self.exception_renderer = Template.default_exception_renderer
if rethrow_errors
self.exception_renderer = ->(_e) { raise }
end
@interrupts = []
@filters = []
@global_filter = nil
end
# rubocop:enable Metrics/ParameterLists
@@ -245,16 +241,5 @@ module Liquid
rescue Liquid::InternalError => exc
exc
end
def squash_instance_assigns_with_environments
@scopes.last.each_key do |k|
@environments.each do |env|
if env.key?(k)
scopes.last[k] = lookup_and_evaluate(env, k)
break
end
end
end
end # squash_instance_assigns_with_environments
end # Context
end # Liquid

View File

@@ -143,7 +143,12 @@ module Liquid
end
def instance_assigns
@instance_assigns ||= {}
@instance_assigns ||= []
end
def new_outer_scope
@instance_assigns.unshift(last = {})
last
end
def errors
@@ -178,11 +183,11 @@ module Liquid
c
when Liquid::Drop
drop = args.shift
drop.context = Context.new([drop, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits)
drop.context = Context.new([drop, assigns].concat(instance_assigns), new_outer_scope, registers, @rethrow_errors, @resource_limits)
when Hash
Context.new([args.shift, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits)
Context.new([args.shift, assigns].concat(instance_assigns), new_outer_scope, registers, @rethrow_errors, @resource_limits)
when nil
Context.new(assigns, instance_assigns, registers, @rethrow_errors, @resource_limits)
Context.new([assigns].concat(instance_assigns), new_outer_scope, registers, @rethrow_errors, @resource_limits)
else
raise ArgumentError, "Expected Hash or Liquid::Context as parameter"
end

View File

@@ -42,6 +42,18 @@ class TemplateTest < Minitest::Test
assert_equal 'from instance assigns', t.parse("{{ foo }}").render!
end
def test_instance_assigns_persist_on_same_template_object_between_many_parses
t = Template.new
assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!
assert_equal 'from instance assigns', t.parse("{{ foo }}").render!
assert_equal 'from instance assigns', t.parse("{{ foo }}").render!
assert_equal 'from instance assigns', t.parse("{{ foo }}").render!
assert_equal 'from instance assigns second', t.parse("{% assign foo = 'from instance assigns second' %}{{ foo }}").render!
assert_equal 'from instance assigns second', t.parse("{{ foo }}").render!
assert_equal 'from instance assigns second', t.parse("{{ foo }}").render!
assert_equal 'from instance assigns second', t.parse("{{ foo }}").render!
end
def test_warnings_is_not_exponential_time
str = "false"
100.times do
@@ -58,6 +70,14 @@ class TemplateTest < Minitest::Test
assert_equal 'foofoo', t.render!
end
def test_instance_assigns_persist_on_same_template_parsing_between_many_renders
t = Template.new.parse("{{ foo }}{% assign foo = 'foo' %}{{ foo }}")
assert_equal 'foo', t.render!
assert_equal 'foofoo', t.render!
assert_equal 'foofoo', t.render!
assert_equal 'foofoo', t.render!
end
def test_custom_assigns_do_not_persist_on_same_template
t = Template.new
assert_equal 'from custom assigns', t.parse("{{ foo }}").render!('foo' => 'from custom assigns')