mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-20 19:30:47 -07:00
Templates and Contexts differentiate between different sources of assigns
This commit is contained in:
+32
-12
@@ -14,13 +14,15 @@ module Liquid
|
|||||||
# context['bob'] #=> nil class Context
|
# context['bob'] #=> nil class Context
|
||||||
class Context
|
class Context
|
||||||
attr_reader :scopes
|
attr_reader :scopes
|
||||||
attr_reader :errors, :registers
|
attr_reader :errors, :registers, :environment
|
||||||
|
|
||||||
def initialize(assigns = {}, registers = {}, rethrow_errors = false)
|
def initialize(environment = {}, instance_assigns = {}, registers = {}, rethrow_errors = false)
|
||||||
@scopes = [(assigns || {})]
|
@environment = environment
|
||||||
@registers = registers
|
@scopes = [(instance_assigns || {})]
|
||||||
@errors = []
|
@registers = registers
|
||||||
|
@errors = []
|
||||||
@rethrow_errors = rethrow_errors
|
@rethrow_errors = rethrow_errors
|
||||||
|
squash_instance_assigns_with_environment
|
||||||
end
|
end
|
||||||
|
|
||||||
def strainer
|
def strainer
|
||||||
@@ -61,9 +63,9 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
# push new local scope on the stack. use <tt>Context#stack</tt> instead
|
# push new local scope on the stack. use <tt>Context#stack</tt> instead
|
||||||
def push
|
def push(new_scope={})
|
||||||
raise StackLevelError, "Nesting too deep" if @scopes.length > 100
|
raise StackLevelError, "Nesting too deep" if @scopes.length > 100
|
||||||
@scopes.unshift({})
|
@scopes.unshift(new_scope)
|
||||||
end
|
end
|
||||||
|
|
||||||
# merge a hash of variables in the current local scope
|
# merge a hash of variables in the current local scope
|
||||||
@@ -86,9 +88,9 @@ module Liquid
|
|||||||
# end
|
# end
|
||||||
# context['var] #=> nil
|
# context['var] #=> nil
|
||||||
#
|
#
|
||||||
def stack(&block)
|
def stack(new_scope={},&block)
|
||||||
result = nil
|
result = nil
|
||||||
push
|
push(new_scope)
|
||||||
begin
|
begin
|
||||||
result = yield
|
result = yield
|
||||||
ensure
|
ensure
|
||||||
@@ -97,6 +99,10 @@ module Liquid
|
|||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clear_instance_assigns
|
||||||
|
@scopes[0] = {}
|
||||||
|
end
|
||||||
|
|
||||||
# Only allow String, Numeric, Hash, Array, Proc, Boolean or <tt>Liquid::Drop</tt>
|
# Only allow String, Numeric, Hash, Array, Proc, Boolean or <tt>Liquid::Drop</tt>
|
||||||
def []=(key, value)
|
def []=(key, value)
|
||||||
@scopes[0][key] = value
|
@scopes[0][key] = value
|
||||||
@@ -156,9 +162,14 @@ module Liquid
|
|||||||
# fetches an object starting at the local scope and then moving up
|
# fetches an object starting at the local scope and then moving up
|
||||||
# the hierachy
|
# the hierachy
|
||||||
def find_variable(key)
|
def find_variable(key)
|
||||||
scope = @scopes[0..-2].find { |s| s.has_key?(key) } || @scopes.last
|
scope = @scopes.find { |s| s.has_key?(key) } || environment
|
||||||
variable = scope[key]
|
|
||||||
variable = scope[key] = variable.call(self) if variable.is_a?(Proc)
|
if scope[key].is_a?(Proc)
|
||||||
|
variable = scope[key] = scope[key].call(self)
|
||||||
|
else
|
||||||
|
variable = scope[key]
|
||||||
|
end
|
||||||
|
|
||||||
variable = variable.to_liquid
|
variable = variable.to_liquid
|
||||||
variable.context = self if variable.respond_to?(:context=)
|
variable.context = self if variable.respond_to?(:context=)
|
||||||
return variable
|
return variable
|
||||||
@@ -217,5 +228,14 @@ module Liquid
|
|||||||
|
|
||||||
object
|
object
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def squash_instance_assigns_with_environment
|
||||||
|
scopes[0].each_key do |k|
|
||||||
|
if environment.has_key?(k)
|
||||||
|
scopes[0][k] = environment[k]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -67,6 +67,10 @@ module Liquid
|
|||||||
@assigns ||= {}
|
@assigns ||= {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def instance_assigns
|
||||||
|
@instance_assigns ||= {}
|
||||||
|
end
|
||||||
|
|
||||||
def errors
|
def errors
|
||||||
@errors ||= []
|
@errors ||= []
|
||||||
end
|
end
|
||||||
@@ -89,11 +93,12 @@ module Liquid
|
|||||||
when Liquid::Context
|
when Liquid::Context
|
||||||
args.shift
|
args.shift
|
||||||
when Hash
|
when Hash
|
||||||
a = args.shift
|
environment = args.shift
|
||||||
assigns.each { |k,v| a[k] = v unless a.has_key?(k) }
|
environment.merge!(assigns) {|k,v1,v2| v1}
|
||||||
Context.new(a, registers, @rethrow_errors)
|
Context.new(environment, instance_assigns, registers, @rethrow_errors)
|
||||||
when nil
|
when nil
|
||||||
Context.new(assigns.dup, registers, @rethrow_errors)
|
environment = assigns.dup
|
||||||
|
Context.new(environment, instance_assigns, registers, @rethrow_errors)
|
||||||
else
|
else
|
||||||
raise ArgumentError, "Expect Hash or Liquid::Context as parameter"
|
raise ArgumentError, "Expect Hash or Liquid::Context as parameter"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -23,4 +23,35 @@ class TemplateTest < Test::Unit::TestCase
|
|||||||
assert_equal [' ', '{% comment %}', ' ', '{% endcomment %}', ' '], Template.new.send(:tokenize, " {% comment %} {% endcomment %} ")
|
assert_equal [' ', '{% comment %}', ' ', '{% endcomment %}', ' '], Template.new.send(:tokenize, " {% comment %} {% endcomment %} ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_instance_assigns_persist_on_same_template_object_between_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
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_instance_assigns_persist_on_same_template_parsing_between_renders
|
||||||
|
t = Template.new.parse("{{ foo }}{% assign foo = 'foo' %}{{ foo }}")
|
||||||
|
assert_equal 'foo', 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')
|
||||||
|
assert_equal '', t.parse("{{ foo }}").render
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_custom_assigns_squash_instance_assigns
|
||||||
|
t = Template.new
|
||||||
|
assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render
|
||||||
|
assert_equal 'from custom assigns', t.parse("{{ foo }}").render('foo' => 'from custom assigns')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_persistent_assigns_squash_instance_assigns
|
||||||
|
t = Template.new
|
||||||
|
assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render
|
||||||
|
t.assigns['foo'] = 'from persistent assigns'
|
||||||
|
assert_equal 'from persistent assigns', t.parse("{{ foo }}").render
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
Reference in New Issue
Block a user