liquid 4.0.3 → 5.1.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 (125) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +54 -0
  3. data/README.md +6 -0
  4. data/lib/liquid/block.rb +31 -14
  5. data/lib/liquid/block_body.rb +166 -54
  6. data/lib/liquid/condition.rb +41 -20
  7. data/lib/liquid/context.rb +107 -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 +29 -34
  12. data/lib/liquid/extensions.rb +2 -0
  13. data/lib/liquid/file_system.rb +6 -4
  14. data/lib/liquid/forloop_drop.rb +11 -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 +3 -1
  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/register.rb +6 -0
  28. data/lib/liquid/resource_limits.rb +47 -8
  29. data/lib/liquid/standardfilters.rb +95 -46
  30. data/lib/liquid/static_registers.rb +44 -0
  31. data/lib/liquid/strainer_factory.rb +36 -0
  32. data/lib/liquid/strainer_template.rb +53 -0
  33. data/lib/liquid/tablerowloop_drop.rb +6 -4
  34. data/lib/liquid/tag/disableable.rb +22 -0
  35. data/lib/liquid/tag/disabler.rb +21 -0
  36. data/lib/liquid/tag.rb +28 -6
  37. data/lib/liquid/tags/assign.rb +24 -10
  38. data/lib/liquid/tags/break.rb +8 -3
  39. data/lib/liquid/tags/capture.rb +11 -8
  40. data/lib/liquid/tags/case.rb +40 -27
  41. data/lib/liquid/tags/comment.rb +5 -3
  42. data/lib/liquid/tags/continue.rb +8 -3
  43. data/lib/liquid/tags/cycle.rb +25 -14
  44. data/lib/liquid/tags/decrement.rb +6 -3
  45. data/lib/liquid/tags/echo.rb +34 -0
  46. data/lib/liquid/tags/for.rb +68 -44
  47. data/lib/liquid/tags/if.rb +39 -23
  48. data/lib/liquid/tags/ifchanged.rb +11 -10
  49. data/lib/liquid/tags/include.rb +34 -47
  50. data/lib/liquid/tags/increment.rb +7 -3
  51. data/lib/liquid/tags/raw.rb +14 -11
  52. data/lib/liquid/tags/render.rb +84 -0
  53. data/lib/liquid/tags/table_row.rb +23 -19
  54. data/lib/liquid/tags/unless.rb +23 -15
  55. data/lib/liquid/template.rb +53 -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 +46 -41
  61. data/lib/liquid/variable_lookup.rb +11 -6
  62. data/lib/liquid/version.rb +2 -1
  63. data/lib/liquid.rb +17 -5
  64. data/test/integration/assign_test.rb +74 -5
  65. data/test/integration/blank_test.rb +11 -8
  66. data/test/integration/block_test.rb +47 -1
  67. data/test/integration/capture_test.rb +18 -10
  68. data/test/integration/context_test.rb +609 -5
  69. data/test/integration/document_test.rb +4 -2
  70. data/test/integration/drop_test.rb +67 -83
  71. data/test/integration/error_handling_test.rb +73 -61
  72. data/test/integration/expression_test.rb +46 -0
  73. data/test/integration/filter_test.rb +53 -42
  74. data/test/integration/hash_ordering_test.rb +5 -3
  75. data/test/integration/output_test.rb +26 -24
  76. data/test/integration/parsing_quirks_test.rb +19 -7
  77. data/test/integration/{render_profiling_test.rb → profiler_test.rb} +84 -25
  78. data/test/integration/security_test.rb +30 -21
  79. data/test/integration/standard_filter_test.rb +385 -281
  80. data/test/integration/tag/disableable_test.rb +59 -0
  81. data/test/integration/tag_test.rb +45 -0
  82. data/test/integration/tags/break_tag_test.rb +4 -2
  83. data/test/integration/tags/continue_tag_test.rb +4 -2
  84. data/test/integration/tags/echo_test.rb +13 -0
  85. data/test/integration/tags/for_tag_test.rb +107 -51
  86. data/test/integration/tags/if_else_tag_test.rb +5 -3
  87. data/test/integration/tags/include_tag_test.rb +70 -54
  88. data/test/integration/tags/increment_tag_test.rb +4 -2
  89. data/test/integration/tags/liquid_tag_test.rb +116 -0
  90. data/test/integration/tags/raw_tag_test.rb +14 -11
  91. data/test/integration/tags/render_tag_test.rb +213 -0
  92. data/test/integration/tags/standard_tag_test.rb +38 -31
  93. data/test/integration/tags/statements_test.rb +23 -21
  94. data/test/integration/tags/table_row_test.rb +2 -0
  95. data/test/integration/tags/unless_else_tag_test.rb +4 -2
  96. data/test/integration/template_test.rb +132 -124
  97. data/test/integration/trim_mode_test.rb +78 -44
  98. data/test/integration/variable_test.rb +74 -32
  99. data/test/test_helper.rb +113 -22
  100. data/test/unit/block_unit_test.rb +19 -24
  101. data/test/unit/condition_unit_test.rb +79 -77
  102. data/test/unit/file_system_unit_test.rb +6 -4
  103. data/test/unit/i18n_unit_test.rb +7 -5
  104. data/test/unit/lexer_unit_test.rb +11 -9
  105. data/test/{integration → unit}/parse_tree_visitor_test.rb +16 -2
  106. data/test/unit/parser_unit_test.rb +37 -35
  107. data/test/unit/partial_cache_unit_test.rb +128 -0
  108. data/test/unit/regexp_unit_test.rb +17 -15
  109. data/test/unit/static_registers_unit_test.rb +156 -0
  110. data/test/unit/strainer_factory_unit_test.rb +100 -0
  111. data/test/unit/strainer_template_unit_test.rb +82 -0
  112. data/test/unit/tag_unit_test.rb +5 -3
  113. data/test/unit/tags/case_tag_unit_test.rb +3 -1
  114. data/test/unit/tags/for_tag_unit_test.rb +4 -2
  115. data/test/unit/tags/if_tag_unit_test.rb +3 -1
  116. data/test/unit/template_factory_unit_test.rb +12 -0
  117. data/test/unit/template_unit_test.rb +19 -10
  118. data/test/unit/tokenizer_unit_test.rb +26 -19
  119. data/test/unit/variable_unit_test.rb +51 -49
  120. metadata +76 -50
  121. data/lib/liquid/strainer.rb +0 -66
  122. data/lib/liquid/truffle.rb +0 -5
  123. data/test/truffle/truffle_test.rb +0 -9
  124. data/test/unit/context_unit_test.rb +0 -489
  125. data/test/unit/strainer_unit_test.rb +0 -164
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class StandardTagTest < Minitest::Test
@@ -69,7 +71,7 @@ class StandardTagTest < Minitest::Test
69
71
  assert_raises(SyntaxError) do
70
72
  assert_template_result('content foo content foo ',
71
73
  '{{ var2 }}{% capture %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}',
72
- { 'var' => 'content' })
74
+ 'var' => 'content')
73
75
  end
74
76
  end
75
77
 
@@ -172,47 +174,52 @@ class StandardTagTest < Minitest::Test
172
174
 
173
175
  def test_assign_from_case
174
176
  # Example from the shopify forums
175
- code = "{% case collection.handle %}{% when 'menswear-jackets' %}{% assign ptitle = 'menswear' %}{% when 'menswear-t-shirts' %}{% assign ptitle = 'menswear' %}{% else %}{% assign ptitle = 'womenswear' %}{% endcase %}{{ ptitle }}"
177
+ code = "{% case collection.handle %}{% when 'menswear-jackets' %}{% assign ptitle = 'menswear' %}{% when 'menswear-t-shirts' %}{% assign ptitle = 'menswear' %}{% else %}{% assign ptitle = 'womenswear' %}{% endcase %}{{ ptitle }}"
176
178
  template = Liquid::Template.parse(code)
177
- assert_equal "menswear", template.render!("collection" => { 'handle' => 'menswear-jackets' })
178
- assert_equal "menswear", template.render!("collection" => { 'handle' => 'menswear-t-shirts' })
179
- assert_equal "womenswear", template.render!("collection" => { 'handle' => 'x' })
180
- assert_equal "womenswear", template.render!("collection" => { 'handle' => 'y' })
181
- assert_equal "womenswear", template.render!("collection" => { 'handle' => 'z' })
179
+ assert_equal("menswear", template.render!("collection" => { 'handle' => 'menswear-jackets' }))
180
+ assert_equal("menswear", template.render!("collection" => { 'handle' => 'menswear-t-shirts' }))
181
+ assert_equal("womenswear", template.render!("collection" => { 'handle' => 'x' }))
182
+ assert_equal("womenswear", template.render!("collection" => { 'handle' => 'y' }))
183
+ assert_equal("womenswear", template.render!("collection" => { 'handle' => 'z' }))
182
184
  end
183
185
 
184
186
  def test_case_when_or
185
187
  code = '{% case condition %}{% when 1 or 2 or 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
186
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
187
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 2 })
188
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 3 })
189
- assert_template_result(' its 4 ', code, { 'condition' => 4 })
190
- assert_template_result('', code, { 'condition' => 5 })
188
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
189
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 2)
190
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 3)
191
+ assert_template_result(' its 4 ', code, 'condition' => 4)
192
+ assert_template_result('', code, 'condition' => 5)
191
193
 
192
194
  code = '{% case condition %}{% when 1 or "string" or null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
193
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
194
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 'string' })
195
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => nil })
196
- assert_template_result('', code, { 'condition' => 'something else' })
195
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
196
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 'string')
197
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => nil)
198
+ assert_template_result('', code, 'condition' => 'something else')
197
199
  end
198
200
 
199
201
  def test_case_when_comma
200
202
  code = '{% case condition %}{% when 1, 2, 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
201
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
202
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 2 })
203
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 3 })
204
- assert_template_result(' its 4 ', code, { 'condition' => 4 })
205
- assert_template_result('', code, { 'condition' => 5 })
203
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
204
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 2)
205
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 3)
206
+ assert_template_result(' its 4 ', code, 'condition' => 4)
207
+ assert_template_result('', code, 'condition' => 5)
206
208
 
207
209
  code = '{% case condition %}{% when 1, "string", null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
208
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
209
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 'string' })
210
- assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => nil })
211
- assert_template_result('', code, { 'condition' => 'something else' })
210
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
211
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 'string')
212
+ assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => nil)
213
+ assert_template_result('', code, 'condition' => 'something else')
214
+ end
215
+
216
+ def test_case_when_comma_and_blank_body
217
+ code = '{% case condition %}{% when 1, 2 %} {% assign r = "result" %} {% endcase %}{{ r }}'
218
+ assert_template_result('result', code, 'condition' => 2)
212
219
  end
213
220
 
214
221
  def test_assign
215
- assert_template_result 'variable', '{% assign a = "variable"%}{{a}}'
222
+ assert_template_result('variable', '{% assign a = "variable"%}{{a}}')
216
223
  end
217
224
 
218
225
  def test_assign_unassigned
@@ -221,11 +228,11 @@ class StandardTagTest < Minitest::Test
221
228
  end
222
229
 
223
230
  def test_assign_an_empty_string
224
- assert_template_result '', '{% assign a = ""%}{{a}}'
231
+ assert_template_result('', '{% assign a = ""%}{{a}}')
225
232
  end
226
233
 
227
234
  def test_assign_is_global
228
- assert_template_result 'variable', '{%for i in (1..2) %}{% assign a = "variable"%}{% endfor %}{{a}}'
235
+ assert_template_result('variable', '{%for i in (1..2) %}{% assign a = "variable"%}{% endfor %}{{a}}')
229
236
  end
230
237
 
231
238
  def test_case_detects_bad_syntax
@@ -283,14 +290,14 @@ class StandardTagTest < Minitest::Test
283
290
  end
284
291
 
285
292
  def test_ifchanged
286
- assigns = { 'array' => [ 1, 1, 2, 2, 3, 3] }
293
+ assigns = { 'array' => [1, 1, 2, 2, 3, 3] }
287
294
  assert_template_result('123', '{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}', assigns)
288
295
 
289
- assigns = { 'array' => [ 1, 1, 1, 1] }
296
+ assigns = { 'array' => [1, 1, 1, 1] }
290
297
  assert_template_result('1', '{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}', assigns)
291
298
  end
292
299
 
293
300
  def test_multiline_tag
294
- assert_template_result '0 1 2 3', "0{%\nfor i in (1..3)\n%} {{\ni\n}}{%\nendfor\n%}"
301
+ assert_template_result('0 1 2 3', "0{%\nfor i in (1..3)\n%} {{\ni\n}}{%\nendfor\n%}")
295
302
  end
296
303
  end # StandardTagTest
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class StatementsTest < Minitest::Test
@@ -5,75 +7,75 @@ class StatementsTest < Minitest::Test
5
7
 
6
8
  def test_true_eql_true
7
9
  text = ' {% if true == true %} true {% else %} false {% endif %} '
8
- assert_template_result ' true ', text
10
+ assert_template_result(' true ', text)
9
11
  end
10
12
 
11
13
  def test_true_not_eql_true
12
14
  text = ' {% if true != true %} true {% else %} false {% endif %} '
13
- assert_template_result ' false ', text
15
+ assert_template_result(' false ', text)
14
16
  end
15
17
 
16
18
  def test_true_lq_true
17
19
  text = ' {% if 0 > 0 %} true {% else %} false {% endif %} '
18
- assert_template_result ' false ', text
20
+ assert_template_result(' false ', text)
19
21
  end
20
22
 
21
23
  def test_one_lq_zero
22
24
  text = ' {% if 1 > 0 %} true {% else %} false {% endif %} '
23
- assert_template_result ' true ', text
25
+ assert_template_result(' true ', text)
24
26
  end
25
27
 
26
28
  def test_zero_lq_one
27
29
  text = ' {% if 0 < 1 %} true {% else %} false {% endif %} '
28
- assert_template_result ' true ', text
30
+ assert_template_result(' true ', text)
29
31
  end
30
32
 
31
33
  def test_zero_lq_or_equal_one
32
34
  text = ' {% if 0 <= 0 %} true {% else %} false {% endif %} '
33
- assert_template_result ' true ', text
35
+ assert_template_result(' true ', text)
34
36
  end
35
37
 
36
38
  def test_zero_lq_or_equal_one_involving_nil
37
39
  text = ' {% if null <= 0 %} true {% else %} false {% endif %} '
38
- assert_template_result ' false ', text
40
+ assert_template_result(' false ', text)
39
41
 
40
42
  text = ' {% if 0 <= null %} true {% else %} false {% endif %} '
41
- assert_template_result ' false ', text
43
+ assert_template_result(' false ', text)
42
44
  end
43
45
 
44
46
  def test_zero_lqq_or_equal_one
45
47
  text = ' {% if 0 >= 0 %} true {% else %} false {% endif %} '
46
- assert_template_result ' true ', text
48
+ assert_template_result(' true ', text)
47
49
  end
48
50
 
49
51
  def test_strings
50
52
  text = " {% if 'test' == 'test' %} true {% else %} false {% endif %} "
51
- assert_template_result ' true ', text
53
+ assert_template_result(' true ', text)
52
54
  end
53
55
 
54
56
  def test_strings_not_equal
55
57
  text = " {% if 'test' != 'test' %} true {% else %} false {% endif %} "
56
- assert_template_result ' false ', text
58
+ assert_template_result(' false ', text)
57
59
  end
58
60
 
59
61
  def test_var_strings_equal
60
62
  text = ' {% if var == "hello there!" %} true {% else %} false {% endif %} '
61
- assert_template_result ' true ', text, 'var' => 'hello there!'
63
+ assert_template_result(' true ', text, 'var' => 'hello there!')
62
64
  end
63
65
 
64
66
  def test_var_strings_are_not_equal
65
67
  text = ' {% if "hello there!" == var %} true {% else %} false {% endif %} '
66
- assert_template_result ' true ', text, 'var' => 'hello there!'
68
+ assert_template_result(' true ', text, 'var' => 'hello there!')
67
69
  end
68
70
 
69
71
  def test_var_and_long_string_are_equal
70
72
  text = " {% if var == 'hello there!' %} true {% else %} false {% endif %} "
71
- assert_template_result ' true ', text, 'var' => 'hello there!'
73
+ assert_template_result(' true ', text, 'var' => 'hello there!')
72
74
  end
73
75
 
74
76
  def test_var_and_long_string_are_equal_backwards
75
77
  text = " {% if 'hello there!' == var %} true {% else %} false {% endif %} "
76
- assert_template_result ' true ', text, 'var' => 'hello there!'
78
+ assert_template_result(' true ', text, 'var' => 'hello there!')
77
79
  end
78
80
 
79
81
  # def test_is_nil
@@ -85,27 +87,27 @@ class StatementsTest < Minitest::Test
85
87
 
86
88
  def test_is_collection_empty
87
89
  text = ' {% if array == empty %} true {% else %} false {% endif %} '
88
- assert_template_result ' true ', text, 'array' => []
90
+ assert_template_result(' true ', text, 'array' => [])
89
91
  end
90
92
 
91
93
  def test_is_not_collection_empty
92
94
  text = ' {% if array == empty %} true {% else %} false {% endif %} '
93
- assert_template_result ' false ', text, 'array' => [1, 2, 3]
95
+ assert_template_result(' false ', text, 'array' => [1, 2, 3])
94
96
  end
95
97
 
96
98
  def test_nil
97
99
  text = ' {% if var == nil %} true {% else %} false {% endif %} '
98
- assert_template_result ' true ', text, 'var' => nil
100
+ assert_template_result(' true ', text, 'var' => nil)
99
101
 
100
102
  text = ' {% if var == null %} true {% else %} false {% endif %} '
101
- assert_template_result ' true ', text, 'var' => nil
103
+ assert_template_result(' true ', text, 'var' => nil)
102
104
  end
103
105
 
104
106
  def test_not_nil
105
107
  text = ' {% if var != nil %} true {% else %} false {% endif %} '
106
- assert_template_result ' true ', text, 'var' => 1
108
+ assert_template_result(' true ', text, 'var' => 1)
107
109
 
108
110
  text = ' {% if var != null %} true {% else %} false {% endif %} '
109
- assert_template_result ' true ', text, 'var' => 1
111
+ assert_template_result(' true ', text, 'var' => 1)
110
112
  end
111
113
  end # StatementsTest
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class TableRowTest < Minitest::Test
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class UnlessElseTagTest < Minitest::Test
@@ -17,10 +19,10 @@ class UnlessElseTagTest < Minitest::Test
17
19
  end
18
20
 
19
21
  def test_unless_in_loop
20
- assert_template_result '23', '{% for i in choices %}{% unless i %}{{ forloop.index }}{% endunless %}{% endfor %}', 'choices' => [1, nil, false]
22
+ assert_template_result('23', '{% for i in choices %}{% unless i %}{{ forloop.index }}{% endunless %}{% endfor %}', 'choices' => [1, nil, false])
21
23
  end
22
24
 
23
25
  def test_unless_else_in_loop
24
- assert_template_result ' TRUE 2 3 ', '{% for i in choices %}{% unless i %} {{ forloop.index }} {% else %} TRUE {% endunless %}{% endfor %}', 'choices' => [1, nil, false]
26
+ assert_template_result(' TRUE 2 3 ', '{% for i in choices %}{% unless i %} {{ forloop.index }} {% else %} TRUE {% endunless %}{% endfor %}', 'choices' => [1, nil, false])
25
27
  end
26
28
  end # UnlessElseTest