lib/liquid/context.rb in locomotive_liquid-2.1.3 vs lib/liquid/context.rb in locomotive_liquid-2.2.2
- old
+ new
@@ -26,12 +26,13 @@
def strainer
@strainer ||= Strainer.create(self)
end
- # adds filters to this context.
- # this does not register the filters with the main Template object. see <tt>Template.register_filter</tt>
+ # Adds filters to this context.
+ #
+ # Note that this does not register the filters with the main Template object. see <tt>Template.register_filter</tt>
# for that
def add_filters(filters)
filters = [filters].flatten.compact
filters.each do |f|
@@ -50,56 +51,56 @@
else
"Liquid error: #{e.message}"
end
end
-
def invoke(method, *args)
if strainer.respond_to?(method)
strainer.__send__(method, *args)
else
args.first
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(new_scope={})
raise StackLevelError, "Nesting too deep" if @scopes.length > 100
@scopes.unshift(new_scope)
end
- # merge a hash of variables in the current local scope
+ # Merge a hash of variables in the current local scope
def merge(new_scopes)
@scopes[0].merge!(new_scopes)
end
- # pop from the stack. use <tt>Context#stack</tt> instead
+ # Pop from the stack. use <tt>Context#stack</tt> instead
def pop
raise ContextError if @scopes.size == 1
@scopes.shift
end
- # pushes a new local scope on the stack, pops it at the end of the block
+ # Pushes a new local scope on the stack, pops it at the end of the block
#
# Example:
- #
# context.stack do
# context['var'] = 'hi'
# end
- # context['var] #=> nil
#
+ # context['var] #=> nil
def stack(new_scope={},&block)
result = nil
push(new_scope)
+
begin
result = yield
ensure
pop
end
+
result
end
-
+
def clear_instance_assigns
@scopes[0] = {}
end
# Only allow String, Numeric, Hash, Array, Proc, Boolean or <tt>Liquid::Drop</tt>
@@ -114,141 +115,135 @@
def has_key?(key)
resolve(key) != nil
end
private
-
- # Look up variable, either resolve directly after considering the name. We can directly handle
- # Strings, digits, floats and booleans (true,false). If no match is made we lookup the variable in the current scope and
- # later move up to the parent blocks to see if we can resolve the variable somewhere up the tree.
- # Some special keywords return symbols. Those symbols are to be called on the rhs object in expressions
- #
- # Example:
- #
- # products == empty #=> products.empty?
- #
- def resolve(key)
- case key
- when nil, 'nil', 'null', ''
- nil
- when 'true'
- true
- when 'false'
- false
- when 'blank'
- :blank?
- when 'empty'
- :empty?
- # Single quoted strings
- when /^'(.*)'$/
- $1.to_s
- # Double quoted strings
- when /^"(.*)"$/
- $1.to_s
- # Integer and floats
- when /^(\d+)$/
- $1.to_i
- # Ranges
- when /^\((\S+)\.\.(\S+)\)$/
- (resolve($1).to_i..resolve($2).to_i)
- # Floats
- when /^(\d[\d\.]+)$/
- $1.to_f
- else
- variable(key)
+ # Look up variable, either resolve directly after considering the name. We can directly handle
+ # Strings, digits, floats and booleans (true,false).
+ # If no match is made we lookup the variable in the current scope and
+ # later move up to the parent blocks to see if we can resolve the variable somewhere up the tree.
+ # Some special keywords return symbols. Those symbols are to be called on the rhs object in expressions
+ #
+ # Example:
+ # products == empty #=> products.empty?
+ def resolve(key)
+ case key
+ when nil, 'nil', 'null', ''
+ nil
+ when 'true'
+ true
+ when 'false'
+ false
+ when 'blank'
+ :blank?
+ when 'empty' # Single quoted strings
+ :empty?
+ when /^'(.*)'$/ # Double quoted strings
+ $1.to_s
+ when /^"(.*)"$/ # Integer and floats
+ $1.to_s
+ when /^(\d+)$/ # Ranges
+ $1.to_i
+ when /^\((\S+)\.\.(\S+)\)$/ # Floats
+ (resolve($1).to_i..resolve($2).to_i)
+ when /^(\d[\d\.]+)$/
+ $1.to_f
+ else
+ variable(key)
+ end
end
- end
- # fetches an object starting at the local scope and then moving up
- # the hierachy
- def find_variable(key)
- scope = @scopes.find { |s| s.has_key?(key) }
- if scope.nil?
- @environments.each do |e|
- if variable = lookup_and_evaluate(e, key)
- scope = e
- break
+ # Fetches an object starting at the local scope and then moving up the hierachy
+ def find_variable(key)
+ scope = @scopes.find { |s| s.has_key?(key) }
+
+ if scope.nil?
+ @environments.each do |e|
+ if variable = lookup_and_evaluate(e, key)
+ scope = e
+ break
+ end
end
end
- end
- scope ||= @environments.last || @scopes.last
- variable ||= lookup_and_evaluate(scope, key)
-
- variable = variable.to_liquid
- variable.context = self if variable.respond_to?(:context=)
- return variable
- end
- # resolves namespaced queries gracefully.
- #
- # Example
- #
- # @context['hash'] = {"name" => 'tobi'}
- # assert_equal 'tobi', @context['hash.name']
- # assert_equal 'tobi', @context['hash["name"]']
- #
- def variable(markup)
- parts = markup.scan(VariableParser)
- square_bracketed = /^\[(.*)\]$/
+ scope ||= @environments.last || @scopes.last
+ variable ||= lookup_and_evaluate(scope, key)
- first_part = parts.shift
- if first_part =~ square_bracketed
- first_part = resolve($1)
+ variable = variable.to_liquid
+ variable.context = self if variable.respond_to?(:context=)
+
+ return variable
end
- if object = find_variable(first_part)
+ # Resolves namespaced queries gracefully.
+ #
+ # Example
+ # @context['hash'] = {"name" => 'tobi'}
+ # assert_equal 'tobi', @context['hash.name']
+ # assert_equal 'tobi', @context['hash["name"]']
+ def variable(markup)
+ parts = markup.scan(VariableParser)
+ square_bracketed = /^\[(.*)\]$/
- parts.each do |part|
- part = resolve($1) if part_resolved = (part =~ square_bracketed)
+ first_part = parts.shift
- # If object is a hash- or array-like object we look for the
- # presence of the key and if its available we return it
- if object.respond_to?(:[]) and
- ((object.respond_to?(:has_key?) and object.has_key?(part)) or
- (object.respond_to?(:fetch) and part.is_a?(Integer)))
+ if first_part =~ square_bracketed
+ first_part = resolve($1)
+ end
- # if its a proc we will replace the entry with the proc
- res = lookup_and_evaluate(object, part)
- object = res.to_liquid
+ if object = find_variable(first_part)
- # Some special cases. If the part wasn't in square brackets and
- # no key with the same name was found we interpret following calls
- # as commands and call them on the current object
- elsif !part_resolved and object.respond_to?(part) and ['size', 'first', 'last'].include?(part)
+ parts.each do |part|
+ part = resolve($1) if part_resolved = (part =~ square_bracketed)
- object = object.send(part.intern).to_liquid
+ # If object is a hash- or array-like object we look for the
+ # presence of the key and if its available we return it
+ if object.respond_to?(:[]) and
+ ((object.respond_to?(:has_key?) and object.has_key?(part)) or
+ (object.respond_to?(:fetch) and part.is_a?(Integer)))
- # No key was present with the desired value and it wasn't one of the directly supported
- # keywords either. The only thing we got left is to return nil
- else
- return nil
+ # if its a proc we will replace the entry with the proc
+ res = lookup_and_evaluate(object, part)
+ object = res.to_liquid
+
+ # Some special cases. If the part wasn't in square brackets and
+ # no key with the same name was found we interpret following calls
+ # as commands and call them on the current object
+ elsif !part_resolved and object.respond_to?(part) and ['size', 'first', 'last'].include?(part)
+
+ object = object.send(part.intern).to_liquid
+
+ # No key was present with the desired value and it wasn't one of the directly supported
+ # keywords either. The only thing we got left is to return nil
+ else
+ return nil
+ end
+
+ # If we are dealing with a drop here we have to
+ object.context = self if object.respond_to?(:context=)
end
+ end
- # If we are dealing with a drop here we have to
- object.context = self if object.respond_to?(:context=)
+ object
+ end # variable
+
+ def lookup_and_evaluate(obj, key)
+ if (value = obj[key]).is_a?(Proc) && obj.respond_to?(:[]=)
+ obj[key] = (value.arity == 0) ? value.call : value.call(self)
+ else
+ value
end
- end
+ end # lookup_and_evaluate
- object
- end
-
- def lookup_and_evaluate(obj, key)
- if (value = obj[key]).is_a?(Proc) && obj.respond_to?(:[]=)
- obj[key] = value.call(self)
- else
- value
- end
- end
-
- def squash_instance_assigns_with_environments
- @scopes.last.each_key do |k|
- @environments.each do |env|
- if env.has_key?(k)
- scopes.last[k] = lookup_and_evaluate(env, k)
- break
+ def squash_instance_assigns_with_environments
+ @scopes.last.each_key do |k|
+ @environments.each do |env|
+ if env.has_key?(k)
+ scopes.last[k] = lookup_and_evaluate(env, k)
+ break
+ end
end
end
- end
- end
-
- end
-end
+ end # squash_instance_assigns_with_environments
+ end # Context
+
+end # Liquid