class Liquid::For
“For” iterates over an array or collection. Several useful variables are available to you within the loop.
Basic usage:¶ ↑
{% for item in collection %} {{ forloop.index }}: {{ item.name }} {% endfor %}
Advanced usage:¶ ↑
{% for item in collection %} <div {% if forloop.first %}class="first"{% endif %}> Item {{ forloop.index }}: {{ item.name }} </div> {% else %} There is nothing in the collection. {% endfor %}
You can also define a limit and offset much like SQL. Remember that offset starts at 0 for the first item.
{% for item in collection limit:5 offset:10 %} {{ item.name }} {% end %} To reverse the for loop simply use {% for item in collection reversed %}
Available variables:¶ ↑
- 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. 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 where the first item is 0
- forloop.rindex
-
Number of items remaining in the loop (length - index) where 1 is the last item.
- forloop.rindex0
-
Number of items remaining in the loop where 0 is the last item.
- forloop.first
-
Returns true if the item is the first item.
- forloop.last
-
Returns true if the item is the last item.
- forloop.parentloop
-
Provides access to the parent loop, if present.
Constants
- Syntax
Public Class Methods
Liquid::Block::new
# File lib/liquid/tags/for.rb, line 49 def initialize(tag_name, markup, options) super @from = @limit = nil parse_with_selected_parser(markup) @for_block = BlockBody.new @else_block = nil end
Public Instance Methods
# File lib/liquid/tags/for.rb, line 62 def nodelist @else_block ? [@for_block, @else_block] : [@for_block] end
# File lib/liquid/tags/for.rb, line 57 def parse(tokens) return unless parse_body(@for_block, tokens) parse_body(@else_block, tokens) end
# File lib/liquid/tags/for.rb, line 71 def render(context) segment = collection_segment(context) if segment.empty? render_else(context) else render_segment(context, segment) end end
Liquid::Block#unknown_tag
# File lib/liquid/tags/for.rb, line 66 def unknown_tag(tag, markup, tokens) return super unless tag == 'else'.freeze @else_block = BlockBody.new end
Protected Instance Methods
# File lib/liquid/tags/for.rb, line 83 def lax_parse(markup) if markup =~ Syntax @variable_name = $1 collection_name = $2 @reversed = !!$3 @name = "#{@variable_name}-#{collection_name}" @collection_name = Expression.parse(collection_name) markup.scan(TagAttributes) do |key, value| set_attribute(key, value) end else raise SyntaxError.new(options[:locale].t("errors.syntax.for".freeze)) end end
# File lib/liquid/tags/for.rb, line 98 def strict_parse(markup) p = Parser.new(markup) @variable_name = p.consume(:id) raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_in".freeze)) unless p.id?('in'.freeze) collection_name = p.expression @name = "#{@variable_name}-#{collection_name}" @collection_name = Expression.parse(collection_name) @reversed = p.id?('reversed'.freeze) while p.look(:id) && p.look(:colon, 1) unless attribute = p.id?('limit'.freeze) || p.id?('offset'.freeze) raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_attribute".freeze)) end p.consume set_attribute(attribute, p.expression) end p.consume(:end_of_string) end
Private Instance Methods
# File lib/liquid/tags/for.rb, line 119 def collection_segment(context) offsets = context.registers[:for] ||= Hash.new(0) from = if @from == :continue offsets[@name].to_i else context.evaluate(@from).to_i end collection = context.evaluate(@collection_name) collection = collection.to_a if collection.is_a?(Range) limit = context.evaluate(@limit) to = limit ? limit.to_i + from : nil segment = Utils.slice_collection(collection, from, to) segment.reverse! if @reversed offsets[@name] = from + segment.length segment end
# File lib/liquid/tags/for.rb, line 189 def render_else(context) @else_block ? @else_block.render(context) : ''.freeze end
# File lib/liquid/tags/for.rb, line 142 def render_segment(context, segment) for_stack = context.registers[:for_stack] ||= [] length = segment.length result = '' context.stack do loop_vars = Liquid::ForloopDrop.new(@name, length, for_stack[-1]) for_stack.push(loop_vars) begin context['forloop'.freeze] = loop_vars segment.each_with_index do |item, index| context[@variable_name] = item result << @for_block.render(context) loop_vars.send(:increment!) # Handle any interrupts if they exist. if context.interrupt? interrupt = context.pop_interrupt break if interrupt.is_a? BreakInterrupt next if interrupt.is_a? ContinueInterrupt end end ensure for_stack.pop end end result end
# File lib/liquid/tags/for.rb, line 176 def set_attribute(key, expr) case key when 'offset'.freeze @from = if expr == 'continue'.freeze :continue else Expression.parse(expr) end when 'limit'.freeze @limit = Expression.parse(expr) end end