locomotivecms-liquid 2.6.0 → 4.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +62 -5
  3. data/README.md +4 -4
  4. data/lib/liquid.rb +16 -12
  5. data/lib/liquid/block.rb +37 -118
  6. data/lib/liquid/block_body.rb +131 -0
  7. data/lib/liquid/condition.rb +28 -17
  8. data/lib/liquid/context.rb +94 -146
  9. data/lib/liquid/document.rb +16 -10
  10. data/lib/liquid/drop.rb +8 -5
  11. data/lib/liquid/drops/inherited_block_drop.rb +24 -0
  12. data/lib/liquid/errors.rb +44 -5
  13. data/lib/liquid/expression.rb +33 -0
  14. data/lib/liquid/file_system.rb +17 -6
  15. data/lib/liquid/i18n.rb +2 -2
  16. data/lib/liquid/interrupts.rb +1 -1
  17. data/lib/liquid/lexer.rb +11 -9
  18. data/lib/liquid/locales/en.yml +2 -4
  19. data/lib/liquid/parser.rb +2 -1
  20. data/lib/liquid/parser_switching.rb +31 -0
  21. data/lib/liquid/profiler.rb +162 -0
  22. data/lib/liquid/profiler/hooks.rb +23 -0
  23. data/lib/liquid/range_lookup.rb +22 -0
  24. data/lib/liquid/resource_limits.rb +23 -0
  25. data/lib/liquid/standardfilters.rb +142 -67
  26. data/lib/liquid/strainer.rb +14 -4
  27. data/lib/liquid/tag.rb +22 -41
  28. data/lib/liquid/tags/assign.rb +15 -10
  29. data/lib/liquid/tags/break.rb +1 -1
  30. data/lib/liquid/tags/capture.rb +7 -9
  31. data/lib/liquid/tags/case.rb +28 -19
  32. data/lib/liquid/tags/comment.rb +2 -2
  33. data/lib/liquid/tags/continue.rb +1 -4
  34. data/lib/liquid/tags/cycle.rb +10 -14
  35. data/lib/liquid/tags/decrement.rb +3 -4
  36. data/lib/liquid/tags/extends.rb +28 -44
  37. data/lib/liquid/tags/for.rb +64 -42
  38. data/lib/liquid/tags/if.rb +30 -19
  39. data/lib/liquid/tags/ifchanged.rb +4 -4
  40. data/lib/liquid/tags/include.rb +30 -20
  41. data/lib/liquid/tags/increment.rb +3 -8
  42. data/lib/liquid/tags/inherited_block.rb +54 -56
  43. data/lib/liquid/tags/raw.rb +18 -10
  44. data/lib/liquid/tags/table_row.rb +72 -0
  45. data/lib/liquid/tags/unless.rb +5 -7
  46. data/lib/liquid/template.rb +113 -53
  47. data/lib/liquid/token.rb +18 -0
  48. data/lib/liquid/utils.rb +13 -4
  49. data/lib/liquid/variable.rb +68 -50
  50. data/lib/liquid/variable_lookup.rb +78 -0
  51. data/lib/liquid/version.rb +1 -1
  52. data/test/fixtures/en_locale.yml +9 -0
  53. data/test/integration/assign_test.rb +48 -0
  54. data/test/integration/blank_test.rb +106 -0
  55. data/test/integration/capture_test.rb +50 -0
  56. data/test/integration/context_test.rb +32 -0
  57. data/test/integration/document_test.rb +19 -0
  58. data/test/integration/drop_test.rb +271 -0
  59. data/test/integration/error_handling_test.rb +207 -0
  60. data/test/integration/filter_test.rb +125 -0
  61. data/test/integration/hash_ordering_test.rb +23 -0
  62. data/test/integration/output_test.rb +116 -0
  63. data/test/integration/parsing_quirks_test.rb +119 -0
  64. data/test/integration/render_profiling_test.rb +154 -0
  65. data/test/integration/security_test.rb +64 -0
  66. data/test/integration/standard_filter_test.rb +379 -0
  67. data/test/integration/tags/break_tag_test.rb +16 -0
  68. data/test/integration/tags/continue_tag_test.rb +16 -0
  69. data/test/integration/tags/extends_tag_test.rb +104 -0
  70. data/test/integration/tags/for_tag_test.rb +375 -0
  71. data/test/integration/tags/if_else_tag_test.rb +169 -0
  72. data/test/integration/tags/include_tag_test.rb +234 -0
  73. data/test/integration/tags/increment_tag_test.rb +24 -0
  74. data/test/integration/tags/raw_tag_test.rb +25 -0
  75. data/test/integration/tags/standard_tag_test.rb +297 -0
  76. data/test/integration/tags/statements_test.rb +113 -0
  77. data/test/integration/tags/table_row_test.rb +63 -0
  78. data/test/integration/tags/unless_else_tag_test.rb +26 -0
  79. data/test/integration/template_test.rb +216 -0
  80. data/test/integration/variable_test.rb +82 -0
  81. data/test/test_helper.rb +83 -0
  82. data/test/unit/block_unit_test.rb +55 -0
  83. data/test/unit/condition_unit_test.rb +149 -0
  84. data/test/unit/context_unit_test.rb +482 -0
  85. data/test/unit/file_system_unit_test.rb +35 -0
  86. data/test/unit/i18n_unit_test.rb +37 -0
  87. data/test/unit/lexer_unit_test.rb +51 -0
  88. data/test/unit/module_ex_unit_test.rb +87 -0
  89. data/test/unit/parser_unit_test.rb +82 -0
  90. data/test/unit/regexp_unit_test.rb +44 -0
  91. data/test/unit/strainer_unit_test.rb +71 -0
  92. data/test/unit/tag_unit_test.rb +16 -0
  93. data/test/unit/tags/case_tag_unit_test.rb +10 -0
  94. data/test/unit/tags/for_tag_unit_test.rb +13 -0
  95. data/test/unit/tags/if_tag_unit_test.rb +8 -0
  96. data/test/unit/template_unit_test.rb +70 -0
  97. data/test/unit/tokenizer_unit_test.rb +38 -0
  98. data/test/unit/variable_unit_test.rb +150 -0
  99. metadata +144 -15
  100. data/lib/extras/liquid_view.rb +0 -51
  101. data/lib/liquid/htmltags.rb +0 -74
  102. data/lib/liquid/tags/default_content.rb +0 -21
  103. data/lib/locomotivecms-liquid.rb +0 -1
@@ -0,0 +1,16 @@
1
+ require 'test_helper'
2
+
3
+ class ContinueTagTest < Minitest::Test
4
+ include Liquid
5
+
6
+ # tests that no weird errors are raised if continue is called outside of a
7
+ # block
8
+ def test_continue_with_no_block
9
+ assigns = {}
10
+ markup = '{% continue %}'
11
+ expected = ''
12
+
13
+ assert_template_result(expected, markup, assigns)
14
+ end
15
+
16
+ end
@@ -0,0 +1,104 @@
1
+ require 'test_helper'
2
+
3
+ class LayoutFileSystem
4
+ def read_template_file(template_path, context)
5
+ case template_path
6
+ when "base"
7
+ "<body>base</body>"
8
+
9
+ when "inherited"
10
+ "{% extends base %}"
11
+
12
+ when "page_with_title"
13
+ "<body><h1>{% block title %}Hello{% endblock %}</h1><p>Lorem ipsum</p></body>"
14
+
15
+ when "product"
16
+ "<body><h1>Our product: {{ name }}</h1>{% block info %}{% endblock %}</body>"
17
+
18
+ when "product_with_warranty"
19
+ "{% extends product %}{% block info %}<p>mandatory warranty</p>{% endblock %}"
20
+
21
+ when "product_with_static_price"
22
+ "{% extends product %}{% block info %}<h2>Some info</h2>{% block price %}<p>$42.00</p>{% endblock %}{% endblock %}"
23
+
24
+ else
25
+ template_path
26
+ end
27
+ end
28
+ end
29
+
30
+ class ExtendsTagTest < Minitest::Test
31
+ include Liquid
32
+
33
+ def setup
34
+ Liquid::Template.file_system = LayoutFileSystem.new
35
+ end
36
+
37
+ def test_template_extends_another_template
38
+ assert_template_result "<body>base</body>",
39
+ "{% extends base %}"
40
+ end
41
+
42
+ def test_template_extends_an_inherited_template
43
+ assert_template_result "<body>base</body>",
44
+ "{% extends inherited %}"
45
+ end
46
+
47
+ def test_template_can_pass_variables_to_the_parent_template
48
+ assert_template_result "<body><h1>Our product: Macbook</h1></body>",
49
+ "{% extends product %}", 'name' => 'Macbook'
50
+ end
51
+
52
+ def test_template_can_pass_variables_to_the_inherited_parent_template
53
+ assert_template_result "<body><h1>Our product: PC</h1><p>mandatory warranty</p></body>",
54
+ "{% extends product_with_warranty %}", 'name' => 'PC'
55
+ end
56
+
57
+ def test_template_does_not_render_statements_outside_blocks
58
+ assert_template_result "<body>base</body>",
59
+ "{% extends base %} Hello world"
60
+ end
61
+
62
+ def test_template_extends_another_template_with_a_single_block
63
+ assert_template_result "<body><h1>Hello</h1><p>Lorem ipsum</p></body>",
64
+ "{% extends page_with_title %}"
65
+ end
66
+
67
+ def test_template_overrides_a_block
68
+ assert_template_result "<body><h1>Sweet</h1><p>Lorem ipsum</p></body>",
69
+ "{% extends page_with_title %}{% block title %}Sweet{% endblock %}"
70
+ end
71
+
72
+ def test_template_has_access_to_the_content_of_the_overriden_block
73
+ assert_template_result "<body><h1>Hello world</h1><p>Lorem ipsum</p></body>",
74
+ "{% extends page_with_title %}{% block title %}{{ block.super }} world{% endblock %}"
75
+ end
76
+
77
+ def test_template_accepts_nested_blocks
78
+ assert_template_result "<body><h1>Our product: iPhone</h1><h2>Some info</h2><p>$42.00</p><p>(not on sale)</p></body>",
79
+ "{% extends product_with_static_price %}{% block info/price %}{{ block.super }}<p>(not on sale)</p>{% endblock %}", 'name' => 'iPhone'
80
+ end
81
+
82
+ # def _print(node, depth = 0)
83
+ # offset = ('.' * depth) + ' '
84
+
85
+ # if node.respond_to?(:template_name) # extends
86
+ # puts "#{offset}Extends #{node.template_name}"
87
+ # elsif node.respond_to?(:push_to_stack) # inherited block
88
+ # puts "#{offset}Block #{node.name} (descendant: #{(!node.descendant.nil?).inspect} / parent: #{(!node.parent.nil?).inspect}), nodes? #{node.self_or_first_ascendant.nodelist.size.inspect} / #{node.blank?.inspect}"
89
+ # elsif node.respond_to?(:name)
90
+ # puts "#{offset}#{node.name}"
91
+ # else
92
+ # puts "#{offset} #{node}"
93
+ # end
94
+
95
+ # if node.respond_to?(:nodelist)
96
+ # _node = node.respond_to?(:self_or_first_ascendant) ? node.self_or_first_ascendant : node
97
+
98
+ # _node.nodelist.each_with_index do |__node, index|
99
+ # print(__node, depth + 1)
100
+ # end
101
+ # end
102
+ # end
103
+
104
+ end # ExtendsTagTest
@@ -0,0 +1,375 @@
1
+ require 'test_helper'
2
+
3
+ class ThingWithValue < Liquid::Drop
4
+ def value
5
+ 3
6
+ end
7
+ end
8
+
9
+ class ForTagTest < Minitest::Test
10
+ include Liquid
11
+
12
+ def test_for
13
+ assert_template_result(' yo yo yo yo ','{%for item in array%} yo {%endfor%}','array' => [1,2,3,4])
14
+ assert_template_result('yoyo','{%for item in array%}yo{%endfor%}','array' => [1,2])
15
+ assert_template_result(' yo ','{%for item in array%} yo {%endfor%}','array' => [1])
16
+ assert_template_result('','{%for item in array%}{%endfor%}','array' => [1,2])
17
+ expected = <<HERE
18
+
19
+ yo
20
+
21
+ yo
22
+
23
+ yo
24
+
25
+ HERE
26
+ template = <<HERE
27
+ {%for item in array%}
28
+ yo
29
+ {%endfor%}
30
+ HERE
31
+ assert_template_result(expected,template,'array' => [1,2,3])
32
+ end
33
+
34
+ def test_for_reversed
35
+ assigns = {'array' => [ 1, 2, 3] }
36
+ assert_template_result('321','{%for item in array reversed %}{{item}}{%endfor%}',assigns)
37
+ end
38
+
39
+ def test_for_with_range
40
+ assert_template_result(' 1 2 3 ','{%for item in (1..3) %} {{item}} {%endfor%}')
41
+ end
42
+
43
+ def test_for_with_variable_range
44
+ assert_template_result(' 1 2 3 ','{%for item in (1..foobar) %} {{item}} {%endfor%}', "foobar" => 3)
45
+ end
46
+
47
+ def test_for_with_hash_value_range
48
+ foobar = { "value" => 3 }
49
+ assert_template_result(' 1 2 3 ','{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
50
+ end
51
+
52
+ def test_for_with_drop_value_range
53
+ foobar = ThingWithValue.new
54
+ assert_template_result(' 1 2 3 ','{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
55
+ end
56
+
57
+ def test_for_with_variable
58
+ assert_template_result(' 1 2 3 ','{%for item in array%} {{item}} {%endfor%}','array' => [1,2,3])
59
+ assert_template_result('123','{%for item in array%}{{item}}{%endfor%}','array' => [1,2,3])
60
+ assert_template_result('123','{% for item in array %}{{item}}{% endfor %}','array' => [1,2,3])
61
+ assert_template_result('abcd','{%for item in array%}{{item}}{%endfor%}','array' => ['a','b','c','d'])
62
+ assert_template_result('a b c','{%for item in array%}{{item}}{%endfor%}','array' => ['a',' ','b',' ','c'])
63
+ assert_template_result('abc','{%for item in array%}{{item}}{%endfor%}','array' => ['a','','b','','c'])
64
+ end
65
+
66
+ def test_for_helpers
67
+ assigns = {'array' => [1,2,3] }
68
+ assert_template_result(' 1/3 2/3 3/3 ',
69
+ '{%for item in array%} {{forloop.index}}/{{forloop.length}} {%endfor%}',
70
+ assigns)
71
+ assert_template_result(' 1 2 3 ', '{%for item in array%} {{forloop.index}} {%endfor%}', assigns)
72
+ assert_template_result(' 0 1 2 ', '{%for item in array%} {{forloop.index0}} {%endfor%}', assigns)
73
+ assert_template_result(' 2 1 0 ', '{%for item in array%} {{forloop.rindex0}} {%endfor%}', assigns)
74
+ assert_template_result(' 3 2 1 ', '{%for item in array%} {{forloop.rindex}} {%endfor%}', assigns)
75
+ assert_template_result(' true false false ', '{%for item in array%} {{forloop.first}} {%endfor%}', assigns)
76
+ assert_template_result(' false false true ', '{%for item in array%} {{forloop.last}} {%endfor%}', assigns)
77
+ end
78
+
79
+ def test_for_and_if
80
+ assigns = {'array' => [1,2,3] }
81
+ assert_template_result('+--',
82
+ '{%for item in array%}{% if forloop.first %}+{% else %}-{% endif %}{%endfor%}',
83
+ assigns)
84
+ end
85
+
86
+ def test_for_else
87
+ assert_template_result('+++', '{%for item in array%}+{%else%}-{%endfor%}', 'array'=>[1,2,3])
88
+ assert_template_result('-', '{%for item in array%}+{%else%}-{%endfor%}', 'array'=>[])
89
+ assert_template_result('-', '{%for item in array%}+{%else%}-{%endfor%}', 'array'=>nil)
90
+ end
91
+
92
+ def test_limiting
93
+ assigns = {'array' => [1,2,3,4,5,6,7,8,9,0]}
94
+ assert_template_result('12', '{%for i in array limit:2 %}{{ i }}{%endfor%}', assigns)
95
+ assert_template_result('1234', '{%for i in array limit:4 %}{{ i }}{%endfor%}', assigns)
96
+ assert_template_result('3456', '{%for i in array limit:4 offset:2 %}{{ i }}{%endfor%}', assigns)
97
+ assert_template_result('3456', '{%for i in array limit: 4 offset: 2 %}{{ i }}{%endfor%}', assigns)
98
+ end
99
+
100
+ def test_dynamic_variable_limiting
101
+ assigns = {'array' => [1,2,3,4,5,6,7,8,9,0]}
102
+ assigns['limit'] = 2
103
+ assigns['offset'] = 2
104
+
105
+ assert_template_result('34', '{%for i in array limit: limit offset: offset %}{{ i }}{%endfor%}', assigns)
106
+ end
107
+
108
+ def test_nested_for
109
+ assigns = {'array' => [[1,2],[3,4],[5,6]] }
110
+ assert_template_result('123456', '{%for item in array%}{%for i in item%}{{ i }}{%endfor%}{%endfor%}', assigns)
111
+ end
112
+
113
+ def test_offset_only
114
+ assigns = {'array' => [1,2,3,4,5,6,7,8,9,0]}
115
+ assert_template_result('890', '{%for i in array offset:7 %}{{ i }}{%endfor%}', assigns)
116
+ end
117
+
118
+ def test_pause_resume
119
+ assigns = {'array' => {'items' => [1,2,3,4,5,6,7,8,9,0]}}
120
+ markup = <<-MKUP
121
+ {%for i in array.items limit: 3 %}{{i}}{%endfor%}
122
+ next
123
+ {%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
124
+ next
125
+ {%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
126
+ MKUP
127
+ expected = <<-XPCTD
128
+ 123
129
+ next
130
+ 456
131
+ next
132
+ 789
133
+ XPCTD
134
+ assert_template_result(expected,markup,assigns)
135
+ end
136
+
137
+ def test_pause_resume_limit
138
+ assigns = {'array' => {'items' => [1,2,3,4,5,6,7,8,9,0]}}
139
+ markup = <<-MKUP
140
+ {%for i in array.items limit:3 %}{{i}}{%endfor%}
141
+ next
142
+ {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
143
+ next
144
+ {%for i in array.items offset:continue limit:1 %}{{i}}{%endfor%}
145
+ MKUP
146
+ expected = <<-XPCTD
147
+ 123
148
+ next
149
+ 456
150
+ next
151
+ 7
152
+ XPCTD
153
+ assert_template_result(expected,markup,assigns)
154
+ end
155
+
156
+ def test_pause_resume_BIG_limit
157
+ assigns = {'array' => {'items' => [1,2,3,4,5,6,7,8,9,0]}}
158
+ markup = <<-MKUP
159
+ {%for i in array.items limit:3 %}{{i}}{%endfor%}
160
+ next
161
+ {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
162
+ next
163
+ {%for i in array.items offset:continue limit:1000 %}{{i}}{%endfor%}
164
+ MKUP
165
+ expected = <<-XPCTD
166
+ 123
167
+ next
168
+ 456
169
+ next
170
+ 7890
171
+ XPCTD
172
+ assert_template_result(expected,markup,assigns)
173
+ end
174
+
175
+
176
+ def test_pause_resume_BIG_offset
177
+ assigns = {'array' => {'items' => [1,2,3,4,5,6,7,8,9,0]}}
178
+ markup = %q({%for i in array.items limit:3 %}{{i}}{%endfor%}
179
+ next
180
+ {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
181
+ next
182
+ {%for i in array.items offset:continue limit:3 offset:1000 %}{{i}}{%endfor%})
183
+ expected = %q(123
184
+ next
185
+ 456
186
+ next
187
+ )
188
+ assert_template_result(expected,markup,assigns)
189
+ end
190
+
191
+ def test_for_with_break
192
+ assigns = {'array' => {'items' => [1,2,3,4,5,6,7,8,9,10]}}
193
+
194
+ markup = '{% for i in array.items %}{% break %}{% endfor %}'
195
+ expected = ""
196
+ assert_template_result(expected,markup,assigns)
197
+
198
+ markup = '{% for i in array.items %}{{ i }}{% break %}{% endfor %}'
199
+ expected = "1"
200
+ assert_template_result(expected,markup,assigns)
201
+
202
+ markup = '{% for i in array.items %}{% break %}{{ i }}{% endfor %}'
203
+ expected = ""
204
+ assert_template_result(expected,markup,assigns)
205
+
206
+ markup = '{% for i in array.items %}{{ i }}{% if i > 3 %}{% break %}{% endif %}{% endfor %}'
207
+ expected = "1234"
208
+ assert_template_result(expected,markup,assigns)
209
+
210
+ # tests to ensure it only breaks out of the local for loop
211
+ # and not all of them.
212
+ assigns = {'array' => [[1,2],[3,4],[5,6]] }
213
+ markup = '{% for item in array %}' +
214
+ '{% for i in item %}' +
215
+ '{% if i == 1 %}' +
216
+ '{% break %}' +
217
+ '{% endif %}' +
218
+ '{{ i }}' +
219
+ '{% endfor %}' +
220
+ '{% endfor %}'
221
+ expected = '3456'
222
+ assert_template_result(expected, markup, assigns)
223
+
224
+ # test break does nothing when unreached
225
+ assigns = {'array' => {'items' => [1,2,3,4,5]}}
226
+ markup = '{% for i in array.items %}{% if i == 9999 %}{% break %}{% endif %}{{ i }}{% endfor %}'
227
+ expected = '12345'
228
+ assert_template_result(expected, markup, assigns)
229
+ end
230
+
231
+ def test_for_with_continue
232
+ assigns = {'array' => {'items' => [1,2,3,4,5]}}
233
+
234
+ markup = '{% for i in array.items %}{% continue %}{% endfor %}'
235
+ expected = ""
236
+ assert_template_result(expected,markup,assigns)
237
+
238
+ markup = '{% for i in array.items %}{{ i }}{% continue %}{% endfor %}'
239
+ expected = "12345"
240
+ assert_template_result(expected,markup,assigns)
241
+
242
+ markup = '{% for i in array.items %}{% continue %}{{ i }}{% endfor %}'
243
+ expected = ""
244
+ assert_template_result(expected,markup,assigns)
245
+
246
+ markup = '{% for i in array.items %}{% if i > 3 %}{% continue %}{% endif %}{{ i }}{% endfor %}'
247
+ expected = "123"
248
+ assert_template_result(expected,markup,assigns)
249
+
250
+ markup = '{% for i in array.items %}{% if i == 3 %}{% continue %}{% else %}{{ i }}{% endif %}{% endfor %}'
251
+ expected = "1245"
252
+ assert_template_result(expected,markup,assigns)
253
+
254
+ # tests to ensure it only continues the local for loop and not all of them.
255
+ assigns = {'array' => [[1,2],[3,4],[5,6]] }
256
+ markup = '{% for item in array %}' +
257
+ '{% for i in item %}' +
258
+ '{% if i == 1 %}' +
259
+ '{% continue %}' +
260
+ '{% endif %}' +
261
+ '{{ i }}' +
262
+ '{% endfor %}' +
263
+ '{% endfor %}'
264
+ expected = '23456'
265
+ assert_template_result(expected, markup, assigns)
266
+
267
+ # test continue does nothing when unreached
268
+ assigns = {'array' => {'items' => [1,2,3,4,5]}}
269
+ markup = '{% for i in array.items %}{% if i == 9999 %}{% continue %}{% endif %}{{ i }}{% endfor %}'
270
+ expected = '12345'
271
+ assert_template_result(expected, markup, assigns)
272
+ end
273
+
274
+ def test_for_tag_string
275
+ # ruby 1.8.7 "String".each => Enumerator with single "String" element.
276
+ # ruby 1.9.3 no longer supports .each on String though we mimic
277
+ # the functionality for backwards compatibility
278
+
279
+ assert_template_result('test string',
280
+ '{%for val in string%}{{val}}{%endfor%}',
281
+ 'string' => "test string")
282
+
283
+ assert_template_result('test string',
284
+ '{%for val in string limit:1%}{{val}}{%endfor%}',
285
+ 'string' => "test string")
286
+
287
+ assert_template_result('val-string-1-1-0-1-0-true-true-test string',
288
+ '{%for val in string%}' +
289
+ '{{forloop.name}}-' +
290
+ '{{forloop.index}}-' +
291
+ '{{forloop.length}}-' +
292
+ '{{forloop.index0}}-' +
293
+ '{{forloop.rindex}}-' +
294
+ '{{forloop.rindex0}}-' +
295
+ '{{forloop.first}}-' +
296
+ '{{forloop.last}}-' +
297
+ '{{val}}{%endfor%}',
298
+ 'string' => "test string")
299
+ end
300
+
301
+ def test_blank_string_not_iterable
302
+ assert_template_result('', "{% for char in characters %}I WILL NOT BE OUTPUT{% endfor %}", 'characters' => '')
303
+ end
304
+
305
+ def test_bad_variable_naming_in_for_loop
306
+ assert_raises(Liquid::SyntaxError) do
307
+ Liquid::Template.parse('{% for a/b in x %}{% endfor %}')
308
+ end
309
+ end
310
+
311
+ def test_spacing_with_variable_naming_in_for_loop
312
+ expected = '12345'
313
+ template = '{% for item in items %}{{item}}{% endfor %}'
314
+ assigns = {'items' => [1,2,3,4,5]}
315
+ assert_template_result(expected, template, assigns)
316
+ end
317
+
318
+ class LoaderDrop < Liquid::Drop
319
+ attr_accessor :each_called, :load_slice_called
320
+
321
+ def initialize(data)
322
+ @data = data
323
+ end
324
+
325
+ def each
326
+ @each_called = true
327
+ @data.each { |el| yield el }
328
+ end
329
+
330
+ def load_slice(from, to)
331
+ @load_slice_called = true
332
+ @data[(from..to-1)]
333
+ end
334
+ end
335
+
336
+ def test_iterate_with_each_when_no_limit_applied
337
+ loader = LoaderDrop.new([1,2,3,4,5])
338
+ assigns = {'items' => loader}
339
+ expected = '12345'
340
+ template = '{% for item in items %}{{item}}{% endfor %}'
341
+ assert_template_result(expected, template, assigns)
342
+ assert loader.each_called
343
+ assert !loader.load_slice_called
344
+ end
345
+
346
+ def test_iterate_with_load_slice_when_limit_applied
347
+ loader = LoaderDrop.new([1,2,3,4,5])
348
+ assigns = {'items' => loader}
349
+ expected = '1'
350
+ template = '{% for item in items limit:1 %}{{item}}{% endfor %}'
351
+ assert_template_result(expected, template, assigns)
352
+ assert !loader.each_called
353
+ assert loader.load_slice_called
354
+ end
355
+
356
+ def test_iterate_with_load_slice_when_limit_and_offset_applied
357
+ loader = LoaderDrop.new([1,2,3,4,5])
358
+ assigns = {'items' => loader}
359
+ expected = '34'
360
+ template = '{% for item in items offset:2 limit:2 %}{{item}}{% endfor %}'
361
+ assert_template_result(expected, template, assigns)
362
+ assert !loader.each_called
363
+ assert loader.load_slice_called
364
+ end
365
+
366
+ def test_iterate_with_load_slice_returns_same_results_as_without
367
+ loader = LoaderDrop.new([1,2,3,4,5])
368
+ loader_assigns = {'items' => loader}
369
+ array_assigns = {'items' => [1,2,3,4,5]}
370
+ expected = '34'
371
+ template = '{% for item in items offset:2 limit:2 %}{{item}}{% endfor %}'
372
+ assert_template_result(expected, template, loader_assigns)
373
+ assert_template_result(expected, template, array_assigns)
374
+ end
375
+ end