Class: Liquid::For
Overview
“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 %}
You can also specify an order for the collection items
{% for item in collection order:ascending %}
{{ item.name }}
{% end %}
You can also specify which attribute to sort by.
{% for item in collection sort_by:name order:descending %}
{{ 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.
Constant Summary collapse
- Syntax =
/(\w+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/
Constants inherited from Block
Block::ContentOfVariable, Block::FullToken, Block::IsTag, Block::IsVariable
Instance Attribute Summary
Attributes inherited from Tag
Instance Method Summary collapse
-
#initialize(tag_name, markup, tokens) ⇒ For
constructor
A new instance of For.
- #render(context) ⇒ Object
- #slice_collection_using_each(collection, from, to) ⇒ Object
- #unknown_tag(tag, markup, tokens) ⇒ Object
Methods inherited from Block
#block_delimiter, #block_name, #create_variable, #end_tag, #parse
Methods inherited from Tag
Constructor Details
#initialize(tag_name, markup, tokens) ⇒ For
Returns a new instance of For.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/liquid/tags/for.rb', line 61 def initialize(tag_name, markup, tokens) if markup =~ Syntax @variable_name = $1 @collection_name = $2 @name = "#{$1}-#{$2}" @reversed = $3 @attributes = {} markup.scan(TagAttributes) do |key, value| @attributes[key] = value end @reversed = 'reversed' if @attributes['order'] == 'descending' else raise SyntaxError.new("Syntax Error in 'for loop' - Valid syntax: for [item] in [collection]") end @nodelist = @for_block = [] super end |
Instance Method Details
#render(context) ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/liquid/tags/for.rb', line 85 def render(context) context.registers[:for] ||= Hash.new(0) # Dup so reverse! doesn't hit the real object collection = context[@collection_name].dup 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) sort_property = @attributes['sort_by'] order_property = @attributes['order'] if sort_property || order_property collection = if sort_property.nil? && (@attributes['order'] == 'ascending' || @attributes['order'] == 'descending') collection.sort elsif collection.first.respond_to?('[]') and !collection.first[sort_property].nil? collection.sort {|a,b| a[sort_property] <=> b[sort_property] } elsif collection.first.respond_to?(sort_property) collection.sort {|a,b| a.send(sort_property) <=> b.send(sort_property) } elsif collection.first.respond_to?(:to_liquid) and collection.first.to_liquid.respond_to?('[]') and !collection.first.to_liquid[sort_property].nil? collection.sort {|a,b| "#{a.to_liquid[sort_property]}" <=> "#{b.to_liquid[sort_property]}" }; else collection end end collection.reverse! if @reversed 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 segment = slice_collection_using_each(collection, from, to) return render_else(context) if segment.empty? result = '' 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, 'rindex' => length - index, 'rindex0' => length - index -1, 'first' => (index == 0), 'last' => (index == length - 1) } result << render_all(@for_block, context) end end result end |
#slice_collection_using_each(collection, from, to) ⇒ Object
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/liquid/tags/for.rb', line 153 def slice_collection_using_each(collection, from, to) segments = [] index = 0 yielded = 0 # Maintains Ruby 1.8.7 String#each behaviour on 1.9 return [collection] if non_blank_string?(collection) collection.each do |item| if to && to <= index break end if from <= index segments << item end index += 1 end segments end |
#unknown_tag(tag, markup, tokens) ⇒ Object
80 81 82 83 |
# File 'lib/liquid/tags/for.rb', line 80 def unknown_tag(tag, markup, tokens) return super unless tag == 'else' @nodelist = @else_block = [] end |