liquid 4.0.3 → 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 (115) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +89 -0
  3. data/README.md +10 -4
  4. data/lib/liquid/block.rb +31 -14
  5. data/lib/liquid/block_body.rb +169 -57
  6. data/lib/liquid/condition.rb +48 -21
  7. data/lib/liquid/context.rb +111 -52
  8. data/lib/liquid/document.rb +47 -9
  9. data/lib/liquid/drop.rb +4 -2
  10. data/lib/liquid/errors.rb +20 -18
  11. data/lib/liquid/expression.rb +28 -32
  12. data/lib/liquid/extensions.rb +2 -0
  13. data/lib/liquid/file_system.rb +6 -4
  14. data/lib/liquid/forloop_drop.rb +54 -4
  15. data/lib/liquid/i18n.rb +5 -3
  16. data/lib/liquid/interrupts.rb +3 -1
  17. data/lib/liquid/lexer.rb +30 -23
  18. data/lib/liquid/locales/en.yml +8 -5
  19. data/lib/liquid/parse_context.rb +20 -4
  20. data/lib/liquid/parse_tree_visitor.rb +2 -2
  21. data/lib/liquid/parser.rb +30 -18
  22. data/lib/liquid/parser_switching.rb +17 -3
  23. data/lib/liquid/partial_cache.rb +24 -0
  24. data/lib/liquid/profiler/hooks.rb +26 -14
  25. data/lib/liquid/profiler.rb +67 -86
  26. data/lib/liquid/range_lookup.rb +13 -3
  27. data/lib/liquid/registers.rb +51 -0
  28. data/lib/liquid/resource_limits.rb +47 -8
  29. data/lib/liquid/standardfilters.rb +551 -114
  30. data/lib/liquid/strainer_factory.rb +41 -0
  31. data/lib/liquid/strainer_template.rb +62 -0
  32. data/lib/liquid/tablerowloop_drop.rb +64 -5
  33. data/lib/liquid/tag/disableable.rb +22 -0
  34. data/lib/liquid/tag/disabler.rb +21 -0
  35. data/lib/liquid/tag.rb +28 -6
  36. data/lib/liquid/tags/assign.rb +36 -18
  37. data/lib/liquid/tags/break.rb +16 -3
  38. data/lib/liquid/tags/capture.rb +24 -18
  39. data/lib/liquid/tags/case.rb +61 -27
  40. data/lib/liquid/tags/comment.rb +18 -3
  41. data/lib/liquid/tags/continue.rb +16 -12
  42. data/lib/liquid/tags/cycle.rb +37 -25
  43. data/lib/liquid/tags/decrement.rb +22 -20
  44. data/lib/liquid/tags/echo.rb +41 -0
  45. data/lib/liquid/tags/for.rb +90 -87
  46. data/lib/liquid/tags/if.rb +50 -32
  47. data/lib/liquid/tags/ifchanged.rb +11 -10
  48. data/lib/liquid/tags/include.rb +49 -60
  49. data/lib/liquid/tags/increment.rb +23 -17
  50. data/lib/liquid/tags/inline_comment.rb +43 -0
  51. data/lib/liquid/tags/raw.rb +25 -11
  52. data/lib/liquid/tags/render.rb +109 -0
  53. data/lib/liquid/tags/table_row.rb +45 -19
  54. data/lib/liquid/tags/unless.rb +38 -19
  55. data/lib/liquid/template.rb +52 -72
  56. data/lib/liquid/template_factory.rb +9 -0
  57. data/lib/liquid/tokenizer.rb +18 -10
  58. data/lib/liquid/usage.rb +8 -0
  59. data/lib/liquid/utils.rb +13 -3
  60. data/lib/liquid/variable.rb +49 -44
  61. data/lib/liquid/variable_lookup.rb +18 -10
  62. data/lib/liquid/version.rb +2 -1
  63. data/lib/liquid.rb +18 -6
  64. metadata +20 -108
  65. data/lib/liquid/strainer.rb +0 -66
  66. data/lib/liquid/truffle.rb +0 -5
  67. data/test/fixtures/en_locale.yml +0 -9
  68. data/test/integration/assign_test.rb +0 -48
  69. data/test/integration/blank_test.rb +0 -106
  70. data/test/integration/block_test.rb +0 -12
  71. data/test/integration/capture_test.rb +0 -50
  72. data/test/integration/context_test.rb +0 -32
  73. data/test/integration/document_test.rb +0 -19
  74. data/test/integration/drop_test.rb +0 -273
  75. data/test/integration/error_handling_test.rb +0 -260
  76. data/test/integration/filter_test.rb +0 -178
  77. data/test/integration/hash_ordering_test.rb +0 -23
  78. data/test/integration/output_test.rb +0 -123
  79. data/test/integration/parse_tree_visitor_test.rb +0 -247
  80. data/test/integration/parsing_quirks_test.rb +0 -122
  81. data/test/integration/render_profiling_test.rb +0 -154
  82. data/test/integration/security_test.rb +0 -80
  83. data/test/integration/standard_filter_test.rb +0 -776
  84. data/test/integration/tags/break_tag_test.rb +0 -15
  85. data/test/integration/tags/continue_tag_test.rb +0 -15
  86. data/test/integration/tags/for_tag_test.rb +0 -410
  87. data/test/integration/tags/if_else_tag_test.rb +0 -188
  88. data/test/integration/tags/include_tag_test.rb +0 -253
  89. data/test/integration/tags/increment_tag_test.rb +0 -23
  90. data/test/integration/tags/raw_tag_test.rb +0 -31
  91. data/test/integration/tags/standard_tag_test.rb +0 -296
  92. data/test/integration/tags/statements_test.rb +0 -111
  93. data/test/integration/tags/table_row_test.rb +0 -64
  94. data/test/integration/tags/unless_else_tag_test.rb +0 -26
  95. data/test/integration/template_test.rb +0 -332
  96. data/test/integration/trim_mode_test.rb +0 -529
  97. data/test/integration/variable_test.rb +0 -96
  98. data/test/test_helper.rb +0 -116
  99. data/test/truffle/truffle_test.rb +0 -9
  100. data/test/unit/block_unit_test.rb +0 -58
  101. data/test/unit/condition_unit_test.rb +0 -166
  102. data/test/unit/context_unit_test.rb +0 -489
  103. data/test/unit/file_system_unit_test.rb +0 -35
  104. data/test/unit/i18n_unit_test.rb +0 -37
  105. data/test/unit/lexer_unit_test.rb +0 -51
  106. data/test/unit/parser_unit_test.rb +0 -82
  107. data/test/unit/regexp_unit_test.rb +0 -44
  108. data/test/unit/strainer_unit_test.rb +0 -164
  109. data/test/unit/tag_unit_test.rb +0 -21
  110. data/test/unit/tags/case_tag_unit_test.rb +0 -10
  111. data/test/unit/tags/for_tag_unit_test.rb +0 -13
  112. data/test/unit/tags/if_tag_unit_test.rb +0 -8
  113. data/test/unit/template_unit_test.rb +0 -78
  114. data/test/unit/tokenizer_unit_test.rb +0 -55
  115. data/test/unit/variable_unit_test.rb +0 -162
@@ -1,15 +0,0 @@
1
- require 'test_helper'
2
-
3
- class BreakTagTest < Minitest::Test
4
- include Liquid
5
-
6
- # tests that no weird errors are raised if break is called outside of a
7
- # block
8
- def test_break_with_no_block
9
- assigns = { 'i' => 1 }
10
- markup = '{% break %}'
11
- expected = ''
12
-
13
- assert_template_result(expected, markup, assigns)
14
- end
15
- end
@@ -1,15 +0,0 @@
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
- end
@@ -1,410 +0,0 @@
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
-
42
- assert_raises(Liquid::ArgumentError) do
43
- Template.parse('{% for i in (a..2) %}{% endfor %}').render!("a" => [1, 2])
44
- end
45
-
46
- assert_template_result(' 0 1 2 3 ', '{% for item in (a..3) %} {{item}} {% endfor %}', "a" => "invalid integer")
47
- end
48
-
49
- def test_for_with_variable_range
50
- assert_template_result(' 1 2 3 ', '{%for item in (1..foobar) %} {{item}} {%endfor%}', "foobar" => 3)
51
- end
52
-
53
- def test_for_with_hash_value_range
54
- foobar = { "value" => 3 }
55
- assert_template_result(' 1 2 3 ', '{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
56
- end
57
-
58
- def test_for_with_drop_value_range
59
- foobar = ThingWithValue.new
60
- assert_template_result(' 1 2 3 ', '{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
61
- end
62
-
63
- def test_for_with_variable
64
- assert_template_result(' 1 2 3 ', '{%for item in array%} {{item}} {%endfor%}', 'array' => [1, 2, 3])
65
- assert_template_result('123', '{%for item in array%}{{item}}{%endfor%}', 'array' => [1, 2, 3])
66
- assert_template_result('123', '{% for item in array %}{{item}}{% endfor %}', 'array' => [1, 2, 3])
67
- assert_template_result('abcd', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', 'b', 'c', 'd'])
68
- assert_template_result('a b c', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', ' ', 'b', ' ', 'c'])
69
- assert_template_result('abc', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', '', 'b', '', 'c'])
70
- end
71
-
72
- def test_for_helpers
73
- assigns = { 'array' => [1, 2, 3] }
74
- assert_template_result(' 1/3 2/3 3/3 ',
75
- '{%for item in array%} {{forloop.index}}/{{forloop.length}} {%endfor%}',
76
- assigns)
77
- assert_template_result(' 1 2 3 ', '{%for item in array%} {{forloop.index}} {%endfor%}', assigns)
78
- assert_template_result(' 0 1 2 ', '{%for item in array%} {{forloop.index0}} {%endfor%}', assigns)
79
- assert_template_result(' 2 1 0 ', '{%for item in array%} {{forloop.rindex0}} {%endfor%}', assigns)
80
- assert_template_result(' 3 2 1 ', '{%for item in array%} {{forloop.rindex}} {%endfor%}', assigns)
81
- assert_template_result(' true false false ', '{%for item in array%} {{forloop.first}} {%endfor%}', assigns)
82
- assert_template_result(' false false true ', '{%for item in array%} {{forloop.last}} {%endfor%}', assigns)
83
- end
84
-
85
- def test_for_and_if
86
- assigns = { 'array' => [1, 2, 3] }
87
- assert_template_result('+--',
88
- '{%for item in array%}{% if forloop.first %}+{% else %}-{% endif %}{%endfor%}',
89
- assigns)
90
- end
91
-
92
- def test_for_else
93
- assert_template_result('+++', '{%for item in array%}+{%else%}-{%endfor%}', 'array' => [1, 2, 3])
94
- assert_template_result('-', '{%for item in array%}+{%else%}-{%endfor%}', 'array' => [])
95
- assert_template_result('-', '{%for item in array%}+{%else%}-{%endfor%}', 'array' => nil)
96
- end
97
-
98
- def test_limiting
99
- assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
100
- assert_template_result('12', '{%for i in array limit:2 %}{{ i }}{%endfor%}', assigns)
101
- assert_template_result('1234', '{%for i in array limit:4 %}{{ i }}{%endfor%}', assigns)
102
- assert_template_result('3456', '{%for i in array limit:4 offset:2 %}{{ i }}{%endfor%}', assigns)
103
- assert_template_result('3456', '{%for i in array limit: 4 offset: 2 %}{{ i }}{%endfor%}', assigns)
104
- end
105
-
106
- def test_dynamic_variable_limiting
107
- assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
108
- assigns['limit'] = 2
109
- assigns['offset'] = 2
110
-
111
- assert_template_result('34', '{%for i in array limit: limit offset: offset %}{{ i }}{%endfor%}', assigns)
112
- end
113
-
114
- def test_nested_for
115
- assigns = { 'array' => [[1, 2], [3, 4], [5, 6]] }
116
- assert_template_result('123456', '{%for item in array%}{%for i in item%}{{ i }}{%endfor%}{%endfor%}', assigns)
117
- end
118
-
119
- def test_offset_only
120
- assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] }
121
- assert_template_result('890', '{%for i in array offset:7 %}{{ i }}{%endfor%}', assigns)
122
- end
123
-
124
- def test_pause_resume
125
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } }
126
- markup = <<-MKUP
127
- {%for i in array.items limit: 3 %}{{i}}{%endfor%}
128
- next
129
- {%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
130
- next
131
- {%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
132
- MKUP
133
- expected = <<-XPCTD
134
- 123
135
- next
136
- 456
137
- next
138
- 789
139
- XPCTD
140
- assert_template_result(expected, markup, assigns)
141
- end
142
-
143
- def test_pause_resume_limit
144
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } }
145
- markup = <<-MKUP
146
- {%for i in array.items limit:3 %}{{i}}{%endfor%}
147
- next
148
- {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
149
- next
150
- {%for i in array.items offset:continue limit:1 %}{{i}}{%endfor%}
151
- MKUP
152
- expected = <<-XPCTD
153
- 123
154
- next
155
- 456
156
- next
157
- 7
158
- XPCTD
159
- assert_template_result(expected, markup, assigns)
160
- end
161
-
162
- def test_pause_resume_big_limit
163
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } }
164
- markup = <<-MKUP
165
- {%for i in array.items limit:3 %}{{i}}{%endfor%}
166
- next
167
- {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
168
- next
169
- {%for i in array.items offset:continue limit:1000 %}{{i}}{%endfor%}
170
- MKUP
171
- expected = <<-XPCTD
172
- 123
173
- next
174
- 456
175
- next
176
- 7890
177
- XPCTD
178
- assert_template_result(expected, markup, assigns)
179
- end
180
-
181
- def test_pause_resume_big_offset
182
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } }
183
- markup = '{%for i in array.items limit:3 %}{{i}}{%endfor%}
184
- next
185
- {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
186
- next
187
- {%for i in array.items offset:continue limit:3 offset:1000 %}{{i}}{%endfor%}'
188
- expected = '123
189
- next
190
- 456
191
- next
192
- '
193
- assert_template_result(expected, markup, assigns)
194
- end
195
-
196
- def test_for_with_break
197
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] } }
198
-
199
- markup = '{% for i in array.items %}{% break %}{% endfor %}'
200
- expected = ""
201
- assert_template_result(expected, markup, assigns)
202
-
203
- markup = '{% for i in array.items %}{{ i }}{% break %}{% endfor %}'
204
- expected = "1"
205
- assert_template_result(expected, markup, assigns)
206
-
207
- markup = '{% for i in array.items %}{% break %}{{ i }}{% endfor %}'
208
- expected = ""
209
- assert_template_result(expected, markup, assigns)
210
-
211
- markup = '{% for i in array.items %}{{ i }}{% if i > 3 %}{% break %}{% endif %}{% endfor %}'
212
- expected = "1234"
213
- assert_template_result(expected, markup, assigns)
214
-
215
- # tests to ensure it only breaks out of the local for loop
216
- # and not all of them.
217
- assigns = { 'array' => [[1, 2], [3, 4], [5, 6]] }
218
- markup = '{% for item in array %}' \
219
- '{% for i in item %}' \
220
- '{% if i == 1 %}' \
221
- '{% break %}' \
222
- '{% endif %}' \
223
- '{{ i }}' \
224
- '{% endfor %}' \
225
- '{% endfor %}'
226
- expected = '3456'
227
- assert_template_result(expected, markup, assigns)
228
-
229
- # test break does nothing when unreached
230
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5] } }
231
- markup = '{% for i in array.items %}{% if i == 9999 %}{% break %}{% endif %}{{ i }}{% endfor %}'
232
- expected = '12345'
233
- assert_template_result(expected, markup, assigns)
234
- end
235
-
236
- def test_for_with_continue
237
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5] } }
238
-
239
- markup = '{% for i in array.items %}{% continue %}{% endfor %}'
240
- expected = ""
241
- assert_template_result(expected, markup, assigns)
242
-
243
- markup = '{% for i in array.items %}{{ i }}{% continue %}{% endfor %}'
244
- expected = "12345"
245
- assert_template_result(expected, markup, assigns)
246
-
247
- markup = '{% for i in array.items %}{% continue %}{{ i }}{% endfor %}'
248
- expected = ""
249
- assert_template_result(expected, markup, assigns)
250
-
251
- markup = '{% for i in array.items %}{% if i > 3 %}{% continue %}{% endif %}{{ i }}{% endfor %}'
252
- expected = "123"
253
- assert_template_result(expected, markup, assigns)
254
-
255
- markup = '{% for i in array.items %}{% if i == 3 %}{% continue %}{% else %}{{ i }}{% endif %}{% endfor %}'
256
- expected = "1245"
257
- assert_template_result(expected, markup, assigns)
258
-
259
- # tests to ensure it only continues the local for loop and not all of them.
260
- assigns = { 'array' => [[1, 2], [3, 4], [5, 6]] }
261
- markup = '{% for item in array %}' \
262
- '{% for i in item %}' \
263
- '{% if i == 1 %}' \
264
- '{% continue %}' \
265
- '{% endif %}' \
266
- '{{ i }}' \
267
- '{% endfor %}' \
268
- '{% endfor %}'
269
- expected = '23456'
270
- assert_template_result(expected, markup, assigns)
271
-
272
- # test continue does nothing when unreached
273
- assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5] } }
274
- markup = '{% for i in array.items %}{% if i == 9999 %}{% continue %}{% endif %}{{ i }}{% endfor %}'
275
- expected = '12345'
276
- assert_template_result(expected, markup, assigns)
277
- end
278
-
279
- def test_for_tag_string
280
- # ruby 1.8.7 "String".each => Enumerator with single "String" element.
281
- # ruby 1.9.3 no longer supports .each on String though we mimic
282
- # the functionality for backwards compatibility
283
-
284
- assert_template_result('test string',
285
- '{%for val in string%}{{val}}{%endfor%}',
286
- 'string' => "test string")
287
-
288
- assert_template_result('test string',
289
- '{%for val in string limit:1%}{{val}}{%endfor%}',
290
- 'string' => "test string")
291
-
292
- assert_template_result('val-string-1-1-0-1-0-true-true-test string',
293
- '{%for val in string%}' \
294
- '{{forloop.name}}-' \
295
- '{{forloop.index}}-' \
296
- '{{forloop.length}}-' \
297
- '{{forloop.index0}}-' \
298
- '{{forloop.rindex}}-' \
299
- '{{forloop.rindex0}}-' \
300
- '{{forloop.first}}-' \
301
- '{{forloop.last}}-' \
302
- '{{val}}{%endfor%}',
303
- 'string' => "test string")
304
- end
305
-
306
- def test_for_parentloop_references_parent_loop
307
- assert_template_result('1.1 1.2 1.3 2.1 2.2 2.3 ',
308
- '{% for inner in outer %}{% for k in inner %}' \
309
- '{{ forloop.parentloop.index }}.{{ forloop.index }} ' \
310
- '{% endfor %}{% endfor %}',
311
- 'outer' => [[1, 1, 1], [1, 1, 1]])
312
- end
313
-
314
- def test_for_parentloop_nil_when_not_present
315
- assert_template_result('.1 .2 ',
316
- '{% for inner in outer %}' \
317
- '{{ forloop.parentloop.index }}.{{ forloop.index }} ' \
318
- '{% endfor %}',
319
- 'outer' => [[1, 1, 1], [1, 1, 1]])
320
- end
321
-
322
- def test_inner_for_over_empty_input
323
- assert_template_result 'oo', '{% for a in (1..2) %}o{% for b in empty %}{% endfor %}{% endfor %}'
324
- end
325
-
326
- def test_blank_string_not_iterable
327
- assert_template_result('', "{% for char in characters %}I WILL NOT BE OUTPUT{% endfor %}", 'characters' => '')
328
- end
329
-
330
- def test_bad_variable_naming_in_for_loop
331
- assert_raises(Liquid::SyntaxError) do
332
- Liquid::Template.parse('{% for a/b in x %}{% endfor %}')
333
- end
334
- end
335
-
336
- def test_spacing_with_variable_naming_in_for_loop
337
- expected = '12345'
338
- template = '{% for item in items %}{{item}}{% endfor %}'
339
- assigns = { 'items' => [1, 2, 3, 4, 5] }
340
- assert_template_result(expected, template, assigns)
341
- end
342
-
343
- class LoaderDrop < Liquid::Drop
344
- attr_accessor :each_called, :load_slice_called
345
-
346
- def initialize(data)
347
- @data = data
348
- end
349
-
350
- def each
351
- @each_called = true
352
- @data.each { |el| yield el }
353
- end
354
-
355
- def load_slice(from, to)
356
- @load_slice_called = true
357
- @data[(from..to - 1)]
358
- end
359
- end
360
-
361
- def test_iterate_with_each_when_no_limit_applied
362
- loader = LoaderDrop.new([1, 2, 3, 4, 5])
363
- assigns = { 'items' => loader }
364
- expected = '12345'
365
- template = '{% for item in items %}{{item}}{% endfor %}'
366
- assert_template_result(expected, template, assigns)
367
- assert loader.each_called
368
- assert !loader.load_slice_called
369
- end
370
-
371
- def test_iterate_with_load_slice_when_limit_applied
372
- loader = LoaderDrop.new([1, 2, 3, 4, 5])
373
- assigns = { 'items' => loader }
374
- expected = '1'
375
- template = '{% for item in items limit:1 %}{{item}}{% endfor %}'
376
- assert_template_result(expected, template, assigns)
377
- assert !loader.each_called
378
- assert loader.load_slice_called
379
- end
380
-
381
- def test_iterate_with_load_slice_when_limit_and_offset_applied
382
- loader = LoaderDrop.new([1, 2, 3, 4, 5])
383
- assigns = { 'items' => loader }
384
- expected = '34'
385
- template = '{% for item in items offset:2 limit:2 %}{{item}}{% endfor %}'
386
- assert_template_result(expected, template, assigns)
387
- assert !loader.each_called
388
- assert loader.load_slice_called
389
- end
390
-
391
- def test_iterate_with_load_slice_returns_same_results_as_without
392
- loader = LoaderDrop.new([1, 2, 3, 4, 5])
393
- loader_assigns = { 'items' => loader }
394
- array_assigns = { 'items' => [1, 2, 3, 4, 5] }
395
- expected = '34'
396
- template = '{% for item in items offset:2 limit:2 %}{{item}}{% endfor %}'
397
- assert_template_result(expected, template, loader_assigns)
398
- assert_template_result(expected, template, array_assigns)
399
- end
400
-
401
- def test_for_cleans_up_registers
402
- context = Context.new(ErrorDrop.new)
403
-
404
- assert_raises(StandardError) do
405
- Liquid::Template.parse('{% for i in (1..2) %}{{ standard_error }}{% endfor %}').render!(context)
406
- end
407
-
408
- assert context.registers[:for_stack].empty?
409
- end
410
- end
@@ -1,188 +0,0 @@
1
- require 'test_helper'
2
-
3
- class IfElseTagTest < Minitest::Test
4
- include Liquid
5
-
6
- def test_if
7
- assert_template_result(' ', ' {% if false %} this text should not go into the output {% endif %} ')
8
- assert_template_result(' this text should go into the output ',
9
- ' {% if true %} this text should go into the output {% endif %} ')
10
- assert_template_result(' you rock ?', '{% if false %} you suck {% endif %} {% if true %} you rock {% endif %}?')
11
- end
12
-
13
- def test_literal_comparisons
14
- assert_template_result(' NO ', '{% assign v = false %}{% if v %} YES {% else %} NO {% endif %}')
15
- assert_template_result(' YES ', '{% assign v = nil %}{% if v == nil %} YES {% else %} NO {% endif %}')
16
- end
17
-
18
- def test_if_else
19
- assert_template_result(' YES ', '{% if false %} NO {% else %} YES {% endif %}')
20
- assert_template_result(' YES ', '{% if true %} YES {% else %} NO {% endif %}')
21
- assert_template_result(' YES ', '{% if "foo" %} YES {% else %} NO {% endif %}')
22
- end
23
-
24
- def test_if_boolean
25
- assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => true)
26
- end
27
-
28
- def test_if_or
29
- assert_template_result(' YES ', '{% if a or b %} YES {% endif %}', 'a' => true, 'b' => true)
30
- assert_template_result(' YES ', '{% if a or b %} YES {% endif %}', 'a' => true, 'b' => false)
31
- assert_template_result(' YES ', '{% if a or b %} YES {% endif %}', 'a' => false, 'b' => true)
32
- assert_template_result('', '{% if a or b %} YES {% endif %}', 'a' => false, 'b' => false)
33
-
34
- assert_template_result(' YES ', '{% if a or b or c %} YES {% endif %}', 'a' => false, 'b' => false, 'c' => true)
35
- assert_template_result('', '{% if a or b or c %} YES {% endif %}', 'a' => false, 'b' => false, 'c' => false)
36
- end
37
-
38
- def test_if_or_with_operators
39
- assert_template_result(' YES ', '{% if a == true or b == true %} YES {% endif %}', 'a' => true, 'b' => true)
40
- assert_template_result(' YES ', '{% if a == true or b == false %} YES {% endif %}', 'a' => true, 'b' => true)
41
- assert_template_result('', '{% if a == false or b == false %} YES {% endif %}', 'a' => true, 'b' => true)
42
- end
43
-
44
- def test_comparison_of_strings_containing_and_or_or
45
- awful_markup = "a == 'and' and b == 'or' and c == 'foo and bar' and d == 'bar or baz' and e == 'foo' and foo and bar"
46
- assigns = { 'a' => 'and', 'b' => 'or', 'c' => 'foo and bar', 'd' => 'bar or baz', 'e' => 'foo', 'foo' => true, 'bar' => true }
47
- assert_template_result(' YES ', "{% if #{awful_markup} %} YES {% endif %}", assigns)
48
- end
49
-
50
- def test_comparison_of_expressions_starting_with_and_or_or
51
- assigns = { 'order' => { 'items_count' => 0 }, 'android' => { 'name' => 'Roy' } }
52
- assert_template_result("YES",
53
- "{% if android.name == 'Roy' %}YES{% endif %}",
54
- assigns)
55
- assert_template_result("YES",
56
- "{% if order.items_count == 0 %}YES{% endif %}",
57
- assigns)
58
- end
59
-
60
- def test_if_and
61
- assert_template_result(' YES ', '{% if true and true %} YES {% endif %}')
62
- assert_template_result('', '{% if false and true %} YES {% endif %}')
63
- assert_template_result('', '{% if false and true %} YES {% endif %}')
64
- end
65
-
66
- def test_hash_miss_generates_false
67
- assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => {})
68
- end
69
-
70
- def test_if_from_variable
71
- assert_template_result('', '{% if var %} NO {% endif %}', 'var' => false)
72
- assert_template_result('', '{% if var %} NO {% endif %}', 'var' => nil)
73
- assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => { 'bar' => false })
74
- assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => {})
75
- assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => nil)
76
- assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => true)
77
-
78
- assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => "text")
79
- assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => true)
80
- assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => 1)
81
- assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => {})
82
- assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => [])
83
- assert_template_result(' YES ', '{% if "foo" %} YES {% endif %}')
84
- assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => true })
85
- assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => "text" })
86
- assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => 1 })
87
- assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => {} })
88
- assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => [] })
89
-
90
- assert_template_result(' YES ', '{% if var %} NO {% else %} YES {% endif %}', 'var' => false)
91
- assert_template_result(' YES ', '{% if var %} NO {% else %} YES {% endif %}', 'var' => nil)
92
- assert_template_result(' YES ', '{% if var %} YES {% else %} NO {% endif %}', 'var' => true)
93
- assert_template_result(' YES ', '{% if "foo" %} YES {% else %} NO {% endif %}', 'var' => "text")
94
-
95
- assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => { 'bar' => false })
96
- assert_template_result(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', 'foo' => { 'bar' => true })
97
- assert_template_result(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', 'foo' => { 'bar' => "text" })
98
- assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => { 'notbar' => true })
99
- assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => {})
100
- assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'notfoo' => { 'bar' => true })
101
- end
102
-
103
- def test_nested_if
104
- assert_template_result('', '{% if false %}{% if false %} NO {% endif %}{% endif %}')
105
- assert_template_result('', '{% if false %}{% if true %} NO {% endif %}{% endif %}')
106
- assert_template_result('', '{% if true %}{% if false %} NO {% endif %}{% endif %}')
107
- assert_template_result(' YES ', '{% if true %}{% if true %} YES {% endif %}{% endif %}')
108
-
109
- assert_template_result(' YES ', '{% if true %}{% if true %} YES {% else %} NO {% endif %}{% else %} NO {% endif %}')
110
- assert_template_result(' YES ', '{% if true %}{% if false %} NO {% else %} YES {% endif %}{% else %} NO {% endif %}')
111
- assert_template_result(' YES ', '{% if false %}{% if true %} NO {% else %} NONO {% endif %}{% else %} YES {% endif %}')
112
- end
113
-
114
- def test_comparisons_on_null
115
- assert_template_result('', '{% if null < 10 %} NO {% endif %}')
116
- assert_template_result('', '{% if null <= 10 %} NO {% endif %}')
117
- assert_template_result('', '{% if null >= 10 %} NO {% endif %}')
118
- assert_template_result('', '{% if null > 10 %} NO {% endif %}')
119
-
120
- assert_template_result('', '{% if 10 < null %} NO {% endif %}')
121
- assert_template_result('', '{% if 10 <= null %} NO {% endif %}')
122
- assert_template_result('', '{% if 10 >= null %} NO {% endif %}')
123
- assert_template_result('', '{% if 10 > null %} NO {% endif %}')
124
- end
125
-
126
- def test_else_if
127
- assert_template_result('0', '{% if 0 == 0 %}0{% elsif 1 == 1%}1{% else %}2{% endif %}')
128
- assert_template_result('1', '{% if 0 != 0 %}0{% elsif 1 == 1%}1{% else %}2{% endif %}')
129
- assert_template_result('2', '{% if 0 != 0 %}0{% elsif 1 != 1%}1{% else %}2{% endif %}')
130
-
131
- assert_template_result('elsif', '{% if false %}if{% elsif true %}elsif{% endif %}')
132
- end
133
-
134
- def test_syntax_error_no_variable
135
- assert_raises(SyntaxError){ assert_template_result('', '{% if jerry == 1 %}') }
136
- end
137
-
138
- def test_syntax_error_no_expression
139
- assert_raises(SyntaxError) { assert_template_result('', '{% if %}') }
140
- end
141
-
142
- def test_if_with_custom_condition
143
- original_op = Condition.operators['contains']
144
- Condition.operators['contains'] = :[]
145
-
146
- assert_template_result('yes', %({% if 'bob' contains 'o' %}yes{% endif %}))
147
- assert_template_result('no', %({% if 'bob' contains 'f' %}yes{% else %}no{% endif %}))
148
- ensure
149
- Condition.operators['contains'] = original_op
150
- end
151
-
152
- def test_operators_are_ignored_unless_isolated
153
- original_op = Condition.operators['contains']
154
- Condition.operators['contains'] = :[]
155
-
156
- assert_template_result('yes',
157
- %({% if 'gnomeslab-and-or-liquid' contains 'gnomeslab-and-or-liquid' %}yes{% endif %}))
158
- ensure
159
- Condition.operators['contains'] = original_op
160
- end
161
-
162
- def test_operators_are_whitelisted
163
- assert_raises(SyntaxError) do
164
- assert_template_result('', %({% if 1 or throw or or 1 %}yes{% endif %}))
165
- end
166
- end
167
-
168
- def test_multiple_conditions
169
- tpl = "{% if a or b and c %}true{% else %}false{% endif %}"
170
-
171
- tests = {
172
- [true, true, true] => true,
173
- [true, true, false] => true,
174
- [true, false, true] => true,
175
- [true, false, false] => true,
176
- [false, true, true] => true,
177
- [false, true, false] => false,
178
- [false, false, true] => false,
179
- [false, false, false] => false,
180
- }
181
-
182
- tests.each do |vals, expected|
183
- a, b, c = vals
184
- assigns = { 'a' => a, 'b' => b, 'c' => c }
185
- assert_template_result expected.to_s, tpl, assigns, assigns.to_s
186
- end
187
- end
188
- end