liquid 5.1.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +35 -0
  3. data/README.md +4 -4
  4. data/lib/liquid/block_body.rb +6 -6
  5. data/lib/liquid/condition.rb +7 -1
  6. data/lib/liquid/context.rb +6 -2
  7. data/lib/liquid/expression.rb +11 -10
  8. data/lib/liquid/forloop_drop.rb +44 -1
  9. data/lib/liquid/locales/en.yml +6 -5
  10. data/lib/liquid/partial_cache.rb +3 -3
  11. data/lib/liquid/registers.rb +51 -0
  12. data/lib/liquid/standardfilters.rb +463 -75
  13. data/lib/liquid/strainer_factory.rb +15 -10
  14. data/lib/liquid/strainer_template.rb +9 -0
  15. data/lib/liquid/tablerowloop_drop.rb +58 -1
  16. data/lib/liquid/tags/assign.rb +12 -8
  17. data/lib/liquid/tags/break.rb +8 -0
  18. data/lib/liquid/tags/capture.rb +13 -10
  19. data/lib/liquid/tags/case.rb +21 -0
  20. data/lib/liquid/tags/comment.rb +13 -0
  21. data/lib/liquid/tags/continue.rb +8 -9
  22. data/lib/liquid/tags/cycle.rb +12 -11
  23. data/lib/liquid/tags/decrement.rb +16 -17
  24. data/lib/liquid/tags/echo.rb +16 -9
  25. data/lib/liquid/tags/for.rb +22 -43
  26. data/lib/liquid/tags/if.rb +11 -9
  27. data/lib/liquid/tags/include.rb +15 -13
  28. data/lib/liquid/tags/increment.rb +16 -14
  29. data/lib/liquid/tags/inline_comment.rb +43 -0
  30. data/lib/liquid/tags/raw.rb +11 -0
  31. data/lib/liquid/tags/render.rb +29 -4
  32. data/lib/liquid/tags/table_row.rb +22 -0
  33. data/lib/liquid/tags/unless.rb +15 -4
  34. data/lib/liquid/template.rb +2 -3
  35. data/lib/liquid/variable.rb +4 -4
  36. data/lib/liquid/variable_lookup.rb +10 -7
  37. data/lib/liquid/version.rb +1 -1
  38. data/lib/liquid.rb +4 -4
  39. metadata +7 -121
  40. data/lib/liquid/register.rb +0 -6
  41. data/lib/liquid/static_registers.rb +0 -44
  42. data/test/fixtures/en_locale.yml +0 -9
  43. data/test/integration/assign_test.rb +0 -117
  44. data/test/integration/blank_test.rb +0 -109
  45. data/test/integration/block_test.rb +0 -58
  46. data/test/integration/capture_test.rb +0 -58
  47. data/test/integration/context_test.rb +0 -636
  48. data/test/integration/document_test.rb +0 -21
  49. data/test/integration/drop_test.rb +0 -257
  50. data/test/integration/error_handling_test.rb +0 -272
  51. data/test/integration/expression_test.rb +0 -46
  52. data/test/integration/filter_test.rb +0 -189
  53. data/test/integration/hash_ordering_test.rb +0 -25
  54. data/test/integration/output_test.rb +0 -125
  55. data/test/integration/parsing_quirks_test.rb +0 -134
  56. data/test/integration/profiler_test.rb +0 -213
  57. data/test/integration/security_test.rb +0 -89
  58. data/test/integration/standard_filter_test.rb +0 -880
  59. data/test/integration/tag/disableable_test.rb +0 -59
  60. data/test/integration/tag_test.rb +0 -45
  61. data/test/integration/tags/break_tag_test.rb +0 -17
  62. data/test/integration/tags/continue_tag_test.rb +0 -17
  63. data/test/integration/tags/echo_test.rb +0 -13
  64. data/test/integration/tags/for_tag_test.rb +0 -466
  65. data/test/integration/tags/if_else_tag_test.rb +0 -190
  66. data/test/integration/tags/include_tag_test.rb +0 -269
  67. data/test/integration/tags/increment_tag_test.rb +0 -25
  68. data/test/integration/tags/liquid_tag_test.rb +0 -116
  69. data/test/integration/tags/raw_tag_test.rb +0 -34
  70. data/test/integration/tags/render_tag_test.rb +0 -213
  71. data/test/integration/tags/standard_tag_test.rb +0 -303
  72. data/test/integration/tags/statements_test.rb +0 -113
  73. data/test/integration/tags/table_row_test.rb +0 -66
  74. data/test/integration/tags/unless_else_tag_test.rb +0 -28
  75. data/test/integration/template_test.rb +0 -340
  76. data/test/integration/trim_mode_test.rb +0 -563
  77. data/test/integration/variable_test.rb +0 -138
  78. data/test/test_helper.rb +0 -207
  79. data/test/unit/block_unit_test.rb +0 -53
  80. data/test/unit/condition_unit_test.rb +0 -168
  81. data/test/unit/file_system_unit_test.rb +0 -37
  82. data/test/unit/i18n_unit_test.rb +0 -39
  83. data/test/unit/lexer_unit_test.rb +0 -53
  84. data/test/unit/parse_tree_visitor_test.rb +0 -261
  85. data/test/unit/parser_unit_test.rb +0 -84
  86. data/test/unit/partial_cache_unit_test.rb +0 -128
  87. data/test/unit/regexp_unit_test.rb +0 -46
  88. data/test/unit/static_registers_unit_test.rb +0 -156
  89. data/test/unit/strainer_factory_unit_test.rb +0 -100
  90. data/test/unit/strainer_template_unit_test.rb +0 -82
  91. data/test/unit/tag_unit_test.rb +0 -23
  92. data/test/unit/tags/case_tag_unit_test.rb +0 -12
  93. data/test/unit/tags/for_tag_unit_test.rb +0 -15
  94. data/test/unit/tags/if_tag_unit_test.rb +0 -10
  95. data/test/unit/template_factory_unit_test.rb +0 -12
  96. data/test/unit/template_unit_test.rb +0 -87
  97. data/test/unit/tokenizer_unit_test.rb +0 -62
  98. data/test/unit/variable_unit_test.rb +0 -164
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class TagDisableableTest < Minitest::Test
6
- include Liquid
7
-
8
- module RenderTagName
9
- def render(_context)
10
- tag_name
11
- end
12
- end
13
-
14
- class Custom < Tag
15
- prepend Liquid::Tag::Disableable
16
- include RenderTagName
17
- end
18
-
19
- class Custom2 < Tag
20
- prepend Liquid::Tag::Disableable
21
- include RenderTagName
22
- end
23
-
24
- class DisableCustom < Block
25
- disable_tags "custom"
26
- end
27
-
28
- class DisableBoth < Block
29
- disable_tags "custom", "custom2"
30
- end
31
-
32
- def test_block_tag_disabling_nested_tag
33
- with_disableable_tags do
34
- with_custom_tag('disable', DisableCustom) do
35
- output = Template.parse('{% disable %}{% custom %};{% custom2 %}{% enddisable %}').render
36
- assert_equal('Liquid error: custom usage is not allowed in this context;custom2', output)
37
- end
38
- end
39
- end
40
-
41
- def test_block_tag_disabling_multiple_nested_tags
42
- with_disableable_tags do
43
- with_custom_tag('disable', DisableBoth) do
44
- output = Template.parse('{% disable %}{% custom %};{% custom2 %}{% enddisable %}').render
45
- assert_equal('Liquid error: custom usage is not allowed in this context;Liquid error: custom2 usage is not allowed in this context', output)
46
- end
47
- end
48
- end
49
-
50
- private
51
-
52
- def with_disableable_tags
53
- with_custom_tag('custom', Custom) do
54
- with_custom_tag('custom2', Custom2) do
55
- yield
56
- end
57
- end
58
- end
59
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class TagTest < Minitest::Test
6
- include Liquid
7
-
8
- def test_custom_tags_have_a_default_render_to_output_buffer_method_for_backwards_compatibility
9
- klass1 = Class.new(Tag) do
10
- def render(*)
11
- 'hello'
12
- end
13
- end
14
-
15
- with_custom_tag('blabla', klass1) do
16
- template = Liquid::Template.parse("{% blabla %}")
17
-
18
- assert_equal('hello', template.render)
19
-
20
- buf = +''
21
- output = template.render({}, output: buf)
22
- assert_equal('hello', output)
23
- assert_equal('hello', buf)
24
- assert_equal(buf.object_id, output.object_id)
25
- end
26
-
27
- klass2 = Class.new(klass1) do
28
- def render(*)
29
- 'foo' + super + 'bar'
30
- end
31
- end
32
-
33
- with_custom_tag('blabla', klass2) do
34
- template = Liquid::Template.parse("{% blabla %}")
35
-
36
- assert_equal('foohellobar', template.render)
37
-
38
- buf = +''
39
- output = template.render({}, output: buf)
40
- assert_equal('foohellobar', output)
41
- assert_equal('foohellobar', buf)
42
- assert_equal(buf.object_id, output.object_id)
43
- end
44
- end
45
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class BreakTagTest < Minitest::Test
6
- include Liquid
7
-
8
- # tests that no weird errors are raised if break is called outside of a
9
- # block
10
- def test_break_with_no_block
11
- assigns = { 'i' => 1 }
12
- markup = '{% break %}'
13
- expected = ''
14
-
15
- assert_template_result(expected, markup, assigns)
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class ContinueTagTest < Minitest::Test
6
- include Liquid
7
-
8
- # tests that no weird errors are raised if continue is called outside of a
9
- # block
10
- def test_continue_with_no_block
11
- assigns = {}
12
- markup = '{% continue %}'
13
- expected = ''
14
-
15
- assert_template_result(expected, markup, assigns)
16
- end
17
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class EchoTest < Minitest::Test
6
- include Liquid
7
-
8
- def test_echo_outputs_its_input
9
- assert_template_result('BAR', <<~LIQUID, 'variable-name' => 'bar')
10
- {%- echo variable-name | upcase -%}
11
- LIQUID
12
- end
13
- end
@@ -1,466 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class ThingWithValue < Liquid::Drop
6
- def value
7
- 3
8
- end
9
- end
10
-
11
- class ForTagTest < Minitest::Test
12
- include Liquid
13
-
14
- def test_for
15
- assert_template_result(' yo yo yo yo ', '{%for item in array%} yo {%endfor%}', 'array' => [1, 2, 3, 4])
16
- assert_template_result('yoyo', '{%for item in array%}yo{%endfor%}', 'array' => [1, 2])
17
- assert_template_result(' yo ', '{%for item in array%} yo {%endfor%}', 'array' => [1])
18
- assert_template_result('', '{%for item in array%}{%endfor%}', 'array' => [1, 2])
19
- expected = <<HERE
20
-
21
- yo
22
-
23
- yo
24
-
25
- yo
26
-
27
- HERE
28
- template = <<~HERE
29
- {%for item in array%}
30
- yo
31
- {%endfor%}
32
- HERE
33
- assert_template_result(expected, template, 'array' => [1, 2, 3])
34
- end
35
-
36
- def test_for_reversed
37
- assigns = { 'array' => [1, 2, 3] }
38
- assert_template_result('321', '{%for item in array reversed %}{{item}}{%endfor%}', assigns)
39
- end
40
-
41
- def test_for_with_range
42
- assert_template_result(' 1 2 3 ', '{%for item in (1..3) %} {{item}} {%endfor%}')
43
-
44
- assert_raises(Liquid::ArgumentError) do
45
- Template.parse('{% for i in (a..2) %}{% endfor %}').render!("a" => [1, 2])
46
- end
47
-
48
- assert_template_result(' 0 1 2 3 ', '{% for item in (a..3) %} {{item}} {% endfor %}', "a" => "invalid integer")
49
- end
50
-
51
- def test_for_with_variable_range
52
- assert_template_result(' 1 2 3 ', '{%for item in (1..foobar) %} {{item}} {%endfor%}', "foobar" => 3)
53
- end
54
-
55
- def test_for_with_hash_value_range
56
- foobar = { "value" => 3 }
57
- assert_template_result(' 1 2 3 ', '{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
58
- end
59
-
60
- def test_for_with_drop_value_range
61
- foobar = ThingWithValue.new
62
- assert_template_result(' 1 2 3 ', '{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
63
- end
64
-
65
- def test_for_with_variable
66
- assert_template_result(' 1 2 3 ', '{%for item in array%} {{item}} {%endfor%}', 'array' => [1, 2, 3])
67
- assert_template_result('123', '{%for item in array%}{{item}}{%endfor%}', 'array' => [1, 2, 3])
68
- assert_template_result('123', '{% for item in array %}{{item}}{% endfor %}', 'array' => [1, 2, 3])
69
- assert_template_result('abcd', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', 'b', 'c', 'd'])
70
- assert_template_result('a b c', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', ' ', 'b', ' ', 'c'])
71
- assert_template_result('abc', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', '', 'b', '', 'c'])
72
- end
73
-
74
- def test_for_helpers
75
- assigns = { 'array' => [1, 2, 3] }
76
- assert_template_result(' 1/3 2/3 3/3 ',
77
- '{%for item in array%} {{forloop.index}}/{{forloop.length}} {%endfor%}',
78
- assigns)
79
- assert_template_result(' 1 2 3 ', '{%for item in array%} {{forloop.index}} {%endfor%}', assigns)
80
- assert_template_result(' 0 1 2 ', '{%for item in array%} {{forloop.index0}} {%endfor%}', assigns)
81
- assert_template_result(' 2 1 0 ', '{%for item in array%} {{forloop.rindex0}} {%endfor%}', assigns)
82
- assert_template_result(' 3 2 1 ', '{%for item in array%} {{forloop.rindex}} {%endfor%}', assigns)
83
- assert_template_result(' true false false ', '{%for item in array%} {{forloop.first}} {%endfor%}', assigns)
84
- assert_template_result(' false false true ', '{%for item in array%} {{forloop.last}} {%endfor%}', assigns)
85
- end
86
-
87
- def test_for_and_if
88
- assigns = { 'array' => [1, 2, 3] }
89
- assert_template_result('+--',
90
- '{%for item in array%}{% if forloop.first %}+{% else %}-{% endif %}{%endfor%}',
91
- assigns)
92
- end
93
-
94
- def test_for_else
95
- assert_template_result('+++', '{%for item in array%}+{%else%}-{%endfor%}', 'array' => [1, 2, 3])
96
- assert_template_result('-', '{%for item in array%}+{%else%}-{%endfor%}', 'array' => [])
97
- assert_template_result('-', '{%for item in array%}+{%else%}-{%endfor%}', 'array' => nil)
98
- end
99
-
100
- def test_limiting
101
- assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
102
- assert_template_result('12', '{%for i in array limit:2 %}{{ i }}{%endfor%}', assigns)
103
- assert_template_result('1234', '{%for i in array limit:4 %}{{ i }}{%endfor%}', assigns)
104
- assert_template_result('3456', '{%for i in array limit:4 offset:2 %}{{ i }}{%endfor%}', assigns)
105
- assert_template_result('3456', '{%for i in array limit: 4 offset: 2 %}{{ i }}{%endfor%}', assigns)
106
- end
107
-
108
- def test_limiting_with_invalid_limit
109
- assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
110
- template = <<-MKUP
111
- {% for i in array limit: true offset: 1 %}
112
- {{ i }}
113
- {% endfor %}
114
- MKUP
115
-
116
- exception = assert_raises(Liquid::ArgumentError) do
117
- Template.parse(template).render!(assigns)
118
- end
119
- assert_equal("Liquid error: invalid integer", exception.message)
120
- end
121
-
122
- def test_limiting_with_invalid_offset
123
- assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
124
- template = <<-MKUP
125
- {% for i in array limit: 1 offset: true %}
126
- {{ i }}
127
- {% endfor %}
128
- MKUP
129
-
130
- exception = assert_raises(Liquid::ArgumentError) do
131
- Template.parse(template).render!(assigns)
132
- end
133
- assert_equal("Liquid error: invalid integer", exception.message)
134
- end
135
-
136
- def test_dynamic_variable_limiting
137
- assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
138
- assigns['limit'] = 2
139
- assigns['offset'] = 2
140
-
141
- assert_template_result('34', '{%for i in array limit: limit offset: offset %}{{ i }}{%endfor%}', assigns)
142
- end
143
-
144
- def test_nested_for
145
- assigns = { 'array' => [[1, 2], [3, 4], [5, 6]] }
146
- assert_template_result('123456', '{%for item in array%}{%for i in item%}{{ i }}{%endfor%}{%endfor%}', assigns)
147
- end
148
-
149
- def test_offset_only
150
- assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
151
- assert_template_result('890', '{%for i in array offset:7 %}{{ i }}{%endfor%}', assigns)
152
- end
153
-
154
- def test_pause_resume
155
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } }
156
- markup = <<-MKUP
157
- {%for i in array.items limit: 3 %}{{i}}{%endfor%}
158
- next
159
- {%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
160
- next
161
- {%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
162
- MKUP
163
- expected = <<-XPCTD
164
- 123
165
- next
166
- 456
167
- next
168
- 789
169
- XPCTD
170
- assert_template_result(expected, markup, assigns)
171
- end
172
-
173
- def test_pause_resume_limit
174
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } }
175
- markup = <<-MKUP
176
- {%for i in array.items limit:3 %}{{i}}{%endfor%}
177
- next
178
- {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
179
- next
180
- {%for i in array.items offset:continue limit:1 %}{{i}}{%endfor%}
181
- MKUP
182
- expected = <<-XPCTD
183
- 123
184
- next
185
- 456
186
- next
187
- 7
188
- XPCTD
189
- assert_template_result(expected, markup, assigns)
190
- end
191
-
192
- def test_pause_resume_big_limit
193
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } }
194
- markup = <<-MKUP
195
- {%for i in array.items limit:3 %}{{i}}{%endfor%}
196
- next
197
- {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
198
- next
199
- {%for i in array.items offset:continue limit:1000 %}{{i}}{%endfor%}
200
- MKUP
201
- expected = <<-XPCTD
202
- 123
203
- next
204
- 456
205
- next
206
- 7890
207
- XPCTD
208
- assert_template_result(expected, markup, assigns)
209
- end
210
-
211
- def test_pause_resume_big_offset
212
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } }
213
- markup = '{%for i in array.items limit:3 %}{{i}}{%endfor%}
214
- next
215
- {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
216
- next
217
- {%for i in array.items offset:continue limit:3 offset:1000 %}{{i}}{%endfor%}'
218
- expected = '123
219
- next
220
- 456
221
- next
222
- '
223
- assert_template_result(expected, markup, assigns)
224
- end
225
-
226
- def test_for_with_break
227
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] } }
228
-
229
- markup = '{% for i in array.items %}{% break %}{% endfor %}'
230
- expected = ""
231
- assert_template_result(expected, markup, assigns)
232
-
233
- markup = '{% for i in array.items %}{{ i }}{% break %}{% endfor %}'
234
- expected = "1"
235
- assert_template_result(expected, markup, assigns)
236
-
237
- markup = '{% for i in array.items %}{% break %}{{ i }}{% endfor %}'
238
- expected = ""
239
- assert_template_result(expected, markup, assigns)
240
-
241
- markup = '{% for i in array.items %}{{ i }}{% if i > 3 %}{% break %}{% endif %}{% endfor %}'
242
- expected = "1234"
243
- assert_template_result(expected, markup, assigns)
244
-
245
- # tests to ensure it only breaks out of the local for loop
246
- # and not all of them.
247
- assigns = { 'array' => [[1, 2], [3, 4], [5, 6]] }
248
- markup = '{% for item in array %}' \
249
- '{% for i in item %}' \
250
- '{% if i == 1 %}' \
251
- '{% break %}' \
252
- '{% endif %}' \
253
- '{{ i }}' \
254
- '{% endfor %}' \
255
- '{% endfor %}'
256
- expected = '3456'
257
- assert_template_result(expected, markup, assigns)
258
-
259
- # test break does nothing when unreached
260
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5] } }
261
- markup = '{% for i in array.items %}{% if i == 9999 %}{% break %}{% endif %}{{ i }}{% endfor %}'
262
- expected = '12345'
263
- assert_template_result(expected, markup, assigns)
264
- end
265
-
266
- def test_for_with_continue
267
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5] } }
268
-
269
- markup = '{% for i in array.items %}{% continue %}{% endfor %}'
270
- expected = ""
271
- assert_template_result(expected, markup, assigns)
272
-
273
- markup = '{% for i in array.items %}{{ i }}{% continue %}{% endfor %}'
274
- expected = "12345"
275
- assert_template_result(expected, markup, assigns)
276
-
277
- markup = '{% for i in array.items %}{% continue %}{{ i }}{% endfor %}'
278
- expected = ""
279
- assert_template_result(expected, markup, assigns)
280
-
281
- markup = '{% for i in array.items %}{% if i > 3 %}{% continue %}{% endif %}{{ i }}{% endfor %}'
282
- expected = "123"
283
- assert_template_result(expected, markup, assigns)
284
-
285
- markup = '{% for i in array.items %}{% if i == 3 %}{% continue %}{% else %}{{ i }}{% endif %}{% endfor %}'
286
- expected = "1245"
287
- assert_template_result(expected, markup, assigns)
288
-
289
- # tests to ensure it only continues the local for loop and not all of them.
290
- assigns = { 'array' => [[1, 2], [3, 4], [5, 6]] }
291
- markup = '{% for item in array %}' \
292
- '{% for i in item %}' \
293
- '{% if i == 1 %}' \
294
- '{% continue %}' \
295
- '{% endif %}' \
296
- '{{ i }}' \
297
- '{% endfor %}' \
298
- '{% endfor %}'
299
- expected = '23456'
300
- assert_template_result(expected, markup, assigns)
301
-
302
- # test continue does nothing when unreached
303
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5] } }
304
- markup = '{% for i in array.items %}{% if i == 9999 %}{% continue %}{% endif %}{{ i }}{% endfor %}'
305
- expected = '12345'
306
- assert_template_result(expected, markup, assigns)
307
- end
308
-
309
- def test_for_tag_string
310
- # ruby 1.8.7 "String".each => Enumerator with single "String" element.
311
- # ruby 1.9.3 no longer supports .each on String though we mimic
312
- # the functionality for backwards compatibility
313
-
314
- assert_template_result('test string',
315
- '{%for val in string%}{{val}}{%endfor%}',
316
- 'string' => "test string")
317
-
318
- assert_template_result('test string',
319
- '{%for val in string limit:1%}{{val}}{%endfor%}',
320
- 'string' => "test string")
321
-
322
- assert_template_result('val-string-1-1-0-1-0-true-true-test string',
323
- '{%for val in string%}' \
324
- '{{forloop.name}}-' \
325
- '{{forloop.index}}-' \
326
- '{{forloop.length}}-' \
327
- '{{forloop.index0}}-' \
328
- '{{forloop.rindex}}-' \
329
- '{{forloop.rindex0}}-' \
330
- '{{forloop.first}}-' \
331
- '{{forloop.last}}-' \
332
- '{{val}}{%endfor%}',
333
- 'string' => "test string")
334
- end
335
-
336
- def test_for_parentloop_references_parent_loop
337
- assert_template_result('1.1 1.2 1.3 2.1 2.2 2.3 ',
338
- '{% for inner in outer %}{% for k in inner %}' \
339
- '{{ forloop.parentloop.index }}.{{ forloop.index }} ' \
340
- '{% endfor %}{% endfor %}',
341
- 'outer' => [[1, 1, 1], [1, 1, 1]])
342
- end
343
-
344
- def test_for_parentloop_nil_when_not_present
345
- assert_template_result('.1 .2 ',
346
- '{% for inner in outer %}' \
347
- '{{ forloop.parentloop.index }}.{{ forloop.index }} ' \
348
- '{% endfor %}',
349
- 'outer' => [[1, 1, 1], [1, 1, 1]])
350
- end
351
-
352
- def test_inner_for_over_empty_input
353
- assert_template_result('oo', '{% for a in (1..2) %}o{% for b in empty %}{% endfor %}{% endfor %}')
354
- end
355
-
356
- def test_blank_string_not_iterable
357
- assert_template_result('', "{% for char in characters %}I WILL NOT BE OUTPUT{% endfor %}", 'characters' => '')
358
- end
359
-
360
- def test_bad_variable_naming_in_for_loop
361
- assert_raises(Liquid::SyntaxError) do
362
- Liquid::Template.parse('{% for a/b in x %}{% endfor %}')
363
- end
364
- end
365
-
366
- def test_spacing_with_variable_naming_in_for_loop
367
- expected = '12345'
368
- template = '{% for item in items %}{{item}}{% endfor %}'
369
- assigns = { 'items' => [1, 2, 3, 4, 5] }
370
- assert_template_result(expected, template, assigns)
371
- end
372
-
373
- class LoaderDrop < Liquid::Drop
374
- attr_accessor :each_called, :load_slice_called
375
-
376
- def initialize(data)
377
- @data = data
378
- end
379
-
380
- def each
381
- @each_called = true
382
- @data.each { |el| yield el }
383
- end
384
-
385
- def load_slice(from, to)
386
- @load_slice_called = true
387
- @data[(from..to - 1)]
388
- end
389
- end
390
-
391
- def test_iterate_with_each_when_no_limit_applied
392
- loader = LoaderDrop.new([1, 2, 3, 4, 5])
393
- assigns = { 'items' => loader }
394
- expected = '12345'
395
- template = '{% for item in items %}{{item}}{% endfor %}'
396
- assert_template_result(expected, template, assigns)
397
- assert(loader.each_called)
398
- assert(!loader.load_slice_called)
399
- end
400
-
401
- def test_iterate_with_load_slice_when_limit_applied
402
- loader = LoaderDrop.new([1, 2, 3, 4, 5])
403
- assigns = { 'items' => loader }
404
- expected = '1'
405
- template = '{% for item in items limit:1 %}{{item}}{% endfor %}'
406
- assert_template_result(expected, template, assigns)
407
- assert(!loader.each_called)
408
- assert(loader.load_slice_called)
409
- end
410
-
411
- def test_iterate_with_load_slice_when_limit_and_offset_applied
412
- loader = LoaderDrop.new([1, 2, 3, 4, 5])
413
- assigns = { 'items' => loader }
414
- expected = '34'
415
- template = '{% for item in items offset:2 limit:2 %}{{item}}{% endfor %}'
416
- assert_template_result(expected, template, assigns)
417
- assert(!loader.each_called)
418
- assert(loader.load_slice_called)
419
- end
420
-
421
- def test_iterate_with_load_slice_returns_same_results_as_without
422
- loader = LoaderDrop.new([1, 2, 3, 4, 5])
423
- loader_assigns = { 'items' => loader }
424
- array_assigns = { 'items' => [1, 2, 3, 4, 5] }
425
- expected = '34'
426
- template = '{% for item in items offset:2 limit:2 %}{{item}}{% endfor %}'
427
- assert_template_result(expected, template, loader_assigns)
428
- assert_template_result(expected, template, array_assigns)
429
- end
430
-
431
- def test_for_cleans_up_registers
432
- context = Context.new(ErrorDrop.new)
433
-
434
- assert_raises(StandardError) do
435
- Liquid::Template.parse('{% for i in (1..2) %}{{ standard_error }}{% endfor %}').render!(context)
436
- end
437
-
438
- assert(context.registers[:for_stack].empty?)
439
- end
440
-
441
- def test_instrument_for_offset_continue
442
- assert_usage_increment('for_offset_continue') do
443
- Template.parse('{% for item in items offset:continue %}{{item}}{% endfor %}')
444
- end
445
-
446
- assert_usage_increment('for_offset_continue', times: 0) do
447
- Template.parse('{% for item in items offset:2 %}{{item}}{% endfor %}')
448
- end
449
- end
450
-
451
- def test_instrument_forloop_drop_name
452
- assigns = { 'items' => [1, 2, 3, 4, 5] }
453
-
454
- assert_usage_increment('forloop_drop_name', times: 5) do
455
- Template.parse('{% for item in items %}{{forloop.name}}{% endfor %}').render!(assigns)
456
- end
457
-
458
- assert_usage_increment('forloop_drop_name', times: 0) do
459
- Template.parse('{% for item in items %}{{forloop.index}}{% endfor %}').render!(assigns)
460
- end
461
-
462
- assert_usage_increment('forloop_drop_name', times: 0) do
463
- Template.parse('{% for item in items %}{{item}}{% endfor %}').render!(assigns)
464
- end
465
- end
466
- end