mirror of
https://github.com/Shopify/liquid.git
synced 2025-09-21 00:00:32 -04:00
rejects variables like a/b in for loops, closes #150
This commit is contained in:
parent
94ff457744
commit
a2df5a421d
@ -1,6 +1,6 @@
|
||||
module Liquid
|
||||
|
||||
# "For" iterates over an array or collection.
|
||||
# "For" iterates over an array or collection.
|
||||
# Several useful variables are available to you within the loop.
|
||||
#
|
||||
# == Basic usage:
|
||||
@ -22,7 +22,7 @@ module Liquid
|
||||
#
|
||||
# {% for item in collection limit:5 offset:10 %}
|
||||
# {{ item.name }}
|
||||
# {% end %}
|
||||
# {% end %}
|
||||
#
|
||||
# To reverse the for loop simply use {% for item in collection reversed %}
|
||||
#
|
||||
@ -31,7 +31,7 @@ module Liquid
|
||||
# forloop.name:: 'item-collection'
|
||||
# forloop.length:: Length of the loop
|
||||
# forloop.index:: The current item's position in the collection;
|
||||
# forloop.index starts at 1.
|
||||
# forloop.index starts at 1.
|
||||
# This is helpful for non-programmers who start believe
|
||||
# the first item in an array is 1, not 0.
|
||||
# forloop.index0:: The current item's position in the collection
|
||||
@ -43,19 +43,19 @@ module Liquid
|
||||
# forloop.first:: Returns true if the item is the first item.
|
||||
# forloop.last:: Returns true if the item is the last item.
|
||||
#
|
||||
class For < Block
|
||||
Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
|
||||
|
||||
class For < Block
|
||||
Syntax = /\A(\w+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
|
||||
|
||||
def initialize(tag_name, markup, tokens)
|
||||
if markup =~ Syntax
|
||||
@variable_name = $1
|
||||
@collection_name = $2
|
||||
@name = "#{$1}-#{$2}"
|
||||
@reversed = $3
|
||||
@name = "#{$1}-#{$2}"
|
||||
@reversed = $3
|
||||
@attributes = {}
|
||||
markup.scan(TagAttributes) do |key, value|
|
||||
@attributes[key] = value
|
||||
end
|
||||
end
|
||||
else
|
||||
raise SyntaxError.new("Syntax Error in 'for loop' - Valid syntax: for [item] in [collection]")
|
||||
end
|
||||
@ -68,51 +68,51 @@ module Liquid
|
||||
return super unless tag == 'else'
|
||||
@nodelist = @else_block = []
|
||||
end
|
||||
|
||||
def render(context)
|
||||
|
||||
def render(context)
|
||||
context.registers[:for] ||= Hash.new(0)
|
||||
|
||||
|
||||
collection = context[@collection_name]
|
||||
collection = collection.to_a if collection.is_a?(Range)
|
||||
|
||||
|
||||
# Maintains Ruby 1.8.7 String#each behaviour on 1.9
|
||||
return render_else(context) unless iterable?(collection)
|
||||
|
||||
|
||||
from = if @attributes['offset'] == 'continue'
|
||||
context.registers[:for][@name].to_i
|
||||
else
|
||||
context[@attributes['offset']].to_i
|
||||
end
|
||||
|
||||
|
||||
limit = context[@attributes['limit']]
|
||||
to = limit ? limit.to_i + from : nil
|
||||
to = limit ? limit.to_i + from : nil
|
||||
|
||||
|
||||
segment = Utils.slice_collection_using_each(collection, from, to)
|
||||
|
||||
return render_else(context) if segment.empty?
|
||||
|
||||
|
||||
segment.reverse! if @reversed
|
||||
|
||||
result = ''
|
||||
|
||||
length = segment.length
|
||||
|
||||
|
||||
length = segment.length
|
||||
|
||||
# Store our progress through the collection for the continue flag
|
||||
context.registers[:for][@name] = from + segment.length
|
||||
|
||||
|
||||
context.stack do
|
||||
segment.each_with_index do |item, index|
|
||||
context[@variable_name] = item
|
||||
context['forloop'] = {
|
||||
'name' => @name,
|
||||
'length' => length,
|
||||
'index' => index + 1,
|
||||
'index0' => index,
|
||||
'index' => index + 1,
|
||||
'index0' => index,
|
||||
'rindex' => length - index,
|
||||
'rindex0' => length - index - 1,
|
||||
'first' => (index == 0),
|
||||
'last' => (index == length - 1) }
|
||||
'last' => (index == length - 1) }
|
||||
|
||||
result << render_all(@for_block, context)
|
||||
|
||||
@ -124,8 +124,8 @@ module Liquid
|
||||
end
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
|
@ -281,4 +281,10 @@ HERE
|
||||
def test_blank_string_not_iterable
|
||||
assert_template_result('', "{% for char in characters %}I WILL NOT BE OUTPUT{% endfor %}", 'characters' => '')
|
||||
end
|
||||
|
||||
def test_bad_variable_naming_in_for_loop
|
||||
assert_raise(Liquid::SyntaxError) do
|
||||
Liquid::Template.parse('{% for a/b in x %}{% endfor %}')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user