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,111 +0,0 @@
1
- require 'test_helper'
2
-
3
- class StatementsTest < Minitest::Test
4
- include Liquid
5
-
6
- def test_true_eql_true
7
- text = ' {% if true == true %} true {% else %} false {% endif %} '
8
- assert_template_result ' true ', text
9
- end
10
-
11
- def test_true_not_eql_true
12
- text = ' {% if true != true %} true {% else %} false {% endif %} '
13
- assert_template_result ' false ', text
14
- end
15
-
16
- def test_true_lq_true
17
- text = ' {% if 0 > 0 %} true {% else %} false {% endif %} '
18
- assert_template_result ' false ', text
19
- end
20
-
21
- def test_one_lq_zero
22
- text = ' {% if 1 > 0 %} true {% else %} false {% endif %} '
23
- assert_template_result ' true ', text
24
- end
25
-
26
- def test_zero_lq_one
27
- text = ' {% if 0 < 1 %} true {% else %} false {% endif %} '
28
- assert_template_result ' true ', text
29
- end
30
-
31
- def test_zero_lq_or_equal_one
32
- text = ' {% if 0 <= 0 %} true {% else %} false {% endif %} '
33
- assert_template_result ' true ', text
34
- end
35
-
36
- def test_zero_lq_or_equal_one_involving_nil
37
- text = ' {% if null <= 0 %} true {% else %} false {% endif %} '
38
- assert_template_result ' false ', text
39
-
40
- text = ' {% if 0 <= null %} true {% else %} false {% endif %} '
41
- assert_template_result ' false ', text
42
- end
43
-
44
- def test_zero_lqq_or_equal_one
45
- text = ' {% if 0 >= 0 %} true {% else %} false {% endif %} '
46
- assert_template_result ' true ', text
47
- end
48
-
49
- def test_strings
50
- text = " {% if 'test' == 'test' %} true {% else %} false {% endif %} "
51
- assert_template_result ' true ', text
52
- end
53
-
54
- def test_strings_not_equal
55
- text = " {% if 'test' != 'test' %} true {% else %} false {% endif %} "
56
- assert_template_result ' false ', text
57
- end
58
-
59
- def test_var_strings_equal
60
- text = ' {% if var == "hello there!" %} true {% else %} false {% endif %} '
61
- assert_template_result ' true ', text, 'var' => 'hello there!'
62
- end
63
-
64
- def test_var_strings_are_not_equal
65
- text = ' {% if "hello there!" == var %} true {% else %} false {% endif %} '
66
- assert_template_result ' true ', text, 'var' => 'hello there!'
67
- end
68
-
69
- def test_var_and_long_string_are_equal
70
- text = " {% if var == 'hello there!' %} true {% else %} false {% endif %} "
71
- assert_template_result ' true ', text, 'var' => 'hello there!'
72
- end
73
-
74
- def test_var_and_long_string_are_equal_backwards
75
- text = " {% if 'hello there!' == var %} true {% else %} false {% endif %} "
76
- assert_template_result ' true ', text, 'var' => 'hello there!'
77
- end
78
-
79
- # def test_is_nil
80
- # text = %| {% if var != nil %} true {% else %} false {% end %} |
81
- # @template.assigns = { 'var' => 'hello there!'}
82
- # expected = %| true |
83
- # assert_equal expected, @template.parse(text)
84
- # end
85
-
86
- def test_is_collection_empty
87
- text = ' {% if array == empty %} true {% else %} false {% endif %} '
88
- assert_template_result ' true ', text, 'array' => []
89
- end
90
-
91
- def test_is_not_collection_empty
92
- text = ' {% if array == empty %} true {% else %} false {% endif %} '
93
- assert_template_result ' false ', text, 'array' => [1, 2, 3]
94
- end
95
-
96
- def test_nil
97
- text = ' {% if var == nil %} true {% else %} false {% endif %} '
98
- assert_template_result ' true ', text, 'var' => nil
99
-
100
- text = ' {% if var == null %} true {% else %} false {% endif %} '
101
- assert_template_result ' true ', text, 'var' => nil
102
- end
103
-
104
- def test_not_nil
105
- text = ' {% if var != nil %} true {% else %} false {% endif %} '
106
- assert_template_result ' true ', text, 'var' => 1
107
-
108
- text = ' {% if var != null %} true {% else %} false {% endif %} '
109
- assert_template_result ' true ', text, 'var' => 1
110
- end
111
- end # StatementsTest
@@ -1,64 +0,0 @@
1
- require 'test_helper'
2
-
3
- class TableRowTest < Minitest::Test
4
- include Liquid
5
-
6
- class ArrayDrop < Liquid::Drop
7
- include Enumerable
8
-
9
- def initialize(array)
10
- @array = array
11
- end
12
-
13
- def each(&block)
14
- @array.each(&block)
15
- end
16
- end
17
-
18
- def test_table_row
19
- assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
20
- '{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}',
21
- 'numbers' => [1, 2, 3, 4, 5, 6])
22
-
23
- assert_template_result("<tr class=\"row1\">\n</tr>\n",
24
- '{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}',
25
- 'numbers' => [])
26
- end
27
-
28
- def test_table_row_with_different_cols
29
- assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td><td class=\"col4\"> 4 </td><td class=\"col5\"> 5 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 6 </td></tr>\n",
30
- '{% tablerow n in numbers cols:5%} {{n}} {% endtablerow %}',
31
- 'numbers' => [1, 2, 3, 4, 5, 6])
32
- end
33
-
34
- def test_table_col_counter
35
- assert_template_result("<tr class=\"row1\">\n<td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n<tr class=\"row2\"><td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n<tr class=\"row3\"><td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n",
36
- '{% tablerow n in numbers cols:2%}{{tablerowloop.col}}{% endtablerow %}',
37
- 'numbers' => [1, 2, 3, 4, 5, 6])
38
- end
39
-
40
- def test_quoted_fragment
41
- assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
42
- "{% tablerow n in collections.frontpage cols:3%} {{n}} {% endtablerow %}",
43
- 'collections' => { 'frontpage' => [1, 2, 3, 4, 5, 6] })
44
- assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
45
- "{% tablerow n in collections['frontpage'] cols:3%} {{n}} {% endtablerow %}",
46
- 'collections' => { 'frontpage' => [1, 2, 3, 4, 5, 6] })
47
- end
48
-
49
- def test_enumerable_drop
50
- assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
51
- '{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}',
52
- 'numbers' => ArrayDrop.new([1, 2, 3, 4, 5, 6]))
53
- end
54
-
55
- def test_offset_and_limit
56
- assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
57
- '{% tablerow n in numbers cols:3 offset:1 limit:6%} {{n}} {% endtablerow %}',
58
- 'numbers' => [0, 1, 2, 3, 4, 5, 6, 7])
59
- end
60
-
61
- def test_blank_string_not_iterable
62
- assert_template_result("<tr class=\"row1\">\n</tr>\n", "{% tablerow char in characters cols:3 %}I WILL NOT BE OUTPUT{% endtablerow %}", 'characters' => '')
63
- end
64
- end
@@ -1,26 +0,0 @@
1
- require 'test_helper'
2
-
3
- class UnlessElseTagTest < Minitest::Test
4
- include Liquid
5
-
6
- def test_unless
7
- assert_template_result(' ', ' {% unless true %} this text should not go into the output {% endunless %} ')
8
- assert_template_result(' this text should go into the output ',
9
- ' {% unless false %} this text should go into the output {% endunless %} ')
10
- assert_template_result(' you rock ?', '{% unless true %} you suck {% endunless %} {% unless false %} you rock {% endunless %}?')
11
- end
12
-
13
- def test_unless_else
14
- assert_template_result(' YES ', '{% unless true %} NO {% else %} YES {% endunless %}')
15
- assert_template_result(' YES ', '{% unless false %} YES {% else %} NO {% endunless %}')
16
- assert_template_result(' YES ', '{% unless "foo" %} NO {% else %} YES {% endunless %}')
17
- end
18
-
19
- def test_unless_in_loop
20
- assert_template_result '23', '{% for i in choices %}{% unless i %}{{ forloop.index }}{% endunless %}{% endfor %}', 'choices' => [1, nil, false]
21
- end
22
-
23
- 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]
25
- end
26
- end # UnlessElseTest
@@ -1,332 +0,0 @@
1
- require 'test_helper'
2
- require 'timeout'
3
-
4
- class TemplateContextDrop < Liquid::Drop
5
- def liquid_method_missing(method)
6
- method
7
- end
8
-
9
- def foo
10
- 'fizzbuzz'
11
- end
12
-
13
- def baz
14
- @context.registers['lulz']
15
- end
16
- end
17
-
18
- class SomethingWithLength < Liquid::Drop
19
- def length
20
- nil
21
- end
22
- end
23
-
24
- class ErroneousDrop < Liquid::Drop
25
- def bad_method
26
- raise 'ruby error in drop'
27
- end
28
- end
29
-
30
- class DropWithUndefinedMethod < Liquid::Drop
31
- def foo
32
- 'foo'
33
- end
34
- end
35
-
36
- class TemplateTest < Minitest::Test
37
- include Liquid
38
-
39
- def test_instance_assigns_persist_on_same_template_object_between_parses
40
- t = Template.new
41
- assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!
42
- assert_equal 'from instance assigns', t.parse("{{ foo }}").render!
43
- end
44
-
45
- def test_warnings_is_not_exponential_time
46
- str = "false"
47
- 100.times do
48
- str = "{% if true %}true{% else %}#{str}{% endif %}"
49
- end
50
-
51
- t = Template.parse(str)
52
- assert_equal [], Timeout.timeout(1) { t.warnings }
53
- end
54
-
55
- def test_instance_assigns_persist_on_same_template_parsing_between_renders
56
- t = Template.new.parse("{{ foo }}{% assign foo = 'foo' %}{{ foo }}")
57
- assert_equal 'foo', t.render!
58
- assert_equal 'foofoo', t.render!
59
- end
60
-
61
- def test_custom_assigns_do_not_persist_on_same_template
62
- t = Template.new
63
- assert_equal 'from custom assigns', t.parse("{{ foo }}").render!('foo' => 'from custom assigns')
64
- assert_equal '', t.parse("{{ foo }}").render!
65
- end
66
-
67
- def test_custom_assigns_squash_instance_assigns
68
- t = Template.new
69
- assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!
70
- assert_equal 'from custom assigns', t.parse("{{ foo }}").render!('foo' => 'from custom assigns')
71
- end
72
-
73
- def test_persistent_assigns_squash_instance_assigns
74
- t = Template.new
75
- assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!
76
- t.assigns['foo'] = 'from persistent assigns'
77
- assert_equal 'from persistent assigns', t.parse("{{ foo }}").render!
78
- end
79
-
80
- def test_lambda_is_called_once_from_persistent_assigns_over_multiple_parses_and_renders
81
- t = Template.new
82
- t.assigns['number'] = -> { @global ||= 0; @global += 1 }
83
- assert_equal '1', t.parse("{{number}}").render!
84
- assert_equal '1', t.parse("{{number}}").render!
85
- assert_equal '1', t.render!
86
- @global = nil
87
- end
88
-
89
- def test_lambda_is_called_once_from_custom_assigns_over_multiple_parses_and_renders
90
- t = Template.new
91
- assigns = { 'number' => -> { @global ||= 0; @global += 1 } }
92
- assert_equal '1', t.parse("{{number}}").render!(assigns)
93
- assert_equal '1', t.parse("{{number}}").render!(assigns)
94
- assert_equal '1', t.render!(assigns)
95
- @global = nil
96
- end
97
-
98
- def test_resource_limits_works_with_custom_length_method
99
- t = Template.parse("{% assign foo = bar %}")
100
- t.resource_limits.render_length_limit = 42
101
- assert_equal "", t.render!("bar" => SomethingWithLength.new)
102
- end
103
-
104
- def test_resource_limits_render_length
105
- t = Template.parse("0123456789")
106
- t.resource_limits.render_length_limit = 5
107
- assert_equal "Liquid error: Memory limits exceeded", t.render
108
- assert t.resource_limits.reached?
109
-
110
- t.resource_limits.render_length_limit = 10
111
- assert_equal "0123456789", t.render!
112
- refute_nil t.resource_limits.render_length
113
- end
114
-
115
- def test_resource_limits_render_score
116
- t = Template.parse("{% for a in (1..10) %} {% for a in (1..10) %} foo {% endfor %} {% endfor %}")
117
- t.resource_limits.render_score_limit = 50
118
- assert_equal "Liquid error: Memory limits exceeded", t.render
119
- assert t.resource_limits.reached?
120
-
121
- t = Template.parse("{% for a in (1..100) %} foo {% endfor %}")
122
- t.resource_limits.render_score_limit = 50
123
- assert_equal "Liquid error: Memory limits exceeded", t.render
124
- assert t.resource_limits.reached?
125
-
126
- t.resource_limits.render_score_limit = 200
127
- assert_equal (" foo " * 100), t.render!
128
- refute_nil t.resource_limits.render_score
129
- end
130
-
131
- def test_resource_limits_assign_score
132
- t = Template.parse("{% assign foo = 42 %}{% assign bar = 23 %}")
133
- t.resource_limits.assign_score_limit = 1
134
- assert_equal "Liquid error: Memory limits exceeded", t.render
135
- assert t.resource_limits.reached?
136
-
137
- t.resource_limits.assign_score_limit = 2
138
- assert_equal "", t.render!
139
- refute_nil t.resource_limits.assign_score
140
- end
141
-
142
- def test_resource_limits_assign_score_nested
143
- t = Template.parse("{% assign foo = 'aaaa' | reverse %}")
144
-
145
- t.resource_limits.assign_score_limit = 3
146
- assert_equal "Liquid error: Memory limits exceeded", t.render
147
- assert t.resource_limits.reached?
148
-
149
- t.resource_limits.assign_score_limit = 5
150
- assert_equal "", t.render!
151
- end
152
-
153
- def test_resource_limits_aborts_rendering_after_first_error
154
- t = Template.parse("{% for a in (1..100) %} foo1 {% endfor %} bar {% for a in (1..100) %} foo2 {% endfor %}")
155
- t.resource_limits.render_score_limit = 50
156
- assert_equal "Liquid error: Memory limits exceeded", t.render
157
- assert t.resource_limits.reached?
158
- end
159
-
160
- def test_resource_limits_hash_in_template_gets_updated_even_if_no_limits_are_set
161
- t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}")
162
- t.render!
163
- assert t.resource_limits.assign_score > 0
164
- assert t.resource_limits.render_score > 0
165
- assert t.resource_limits.render_length > 0
166
- end
167
-
168
- def test_render_length_persists_between_blocks
169
- t = Template.parse("{% if true %}aaaa{% endif %}")
170
- t.resource_limits.render_length_limit = 7
171
- assert_equal "Liquid error: Memory limits exceeded", t.render
172
- t.resource_limits.render_length_limit = 8
173
- assert_equal "aaaa", t.render
174
-
175
- t = Template.parse("{% if true %}aaaa{% endif %}{% if true %}bbb{% endif %}")
176
- t.resource_limits.render_length_limit = 13
177
- assert_equal "Liquid error: Memory limits exceeded", t.render
178
- t.resource_limits.render_length_limit = 14
179
- assert_equal "aaaabbb", t.render
180
-
181
- t = Template.parse("{% if true %}a{% endif %}{% if true %}b{% endif %}{% if true %}a{% endif %}{% if true %}b{% endif %}{% if true %}a{% endif %}{% if true %}b{% endif %}")
182
- t.resource_limits.render_length_limit = 5
183
- assert_equal "Liquid error: Memory limits exceeded", t.render
184
- t.resource_limits.render_length_limit = 11
185
- assert_equal "Liquid error: Memory limits exceeded", t.render
186
- t.resource_limits.render_length_limit = 12
187
- assert_equal "ababab", t.render
188
- end
189
-
190
- def test_default_resource_limits_unaffected_by_render_with_context
191
- context = Context.new
192
- t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}")
193
- t.render!(context)
194
- assert context.resource_limits.assign_score > 0
195
- assert context.resource_limits.render_score > 0
196
- assert context.resource_limits.render_length > 0
197
- end
198
-
199
- def test_can_use_drop_as_context
200
- t = Template.new
201
- t.registers['lulz'] = 'haha'
202
- drop = TemplateContextDrop.new
203
- assert_equal 'fizzbuzz', t.parse('{{foo}}').render!(drop)
204
- assert_equal 'bar', t.parse('{{bar}}').render!(drop)
205
- assert_equal 'haha', t.parse("{{baz}}").render!(drop)
206
- end
207
-
208
- def test_render_bang_force_rethrow_errors_on_passed_context
209
- context = Context.new({ 'drop' => ErroneousDrop.new })
210
- t = Template.new.parse('{{ drop.bad_method }}')
211
-
212
- e = assert_raises RuntimeError do
213
- t.render!(context)
214
- end
215
- assert_equal 'ruby error in drop', e.message
216
- end
217
-
218
- def test_exception_renderer_that_returns_string
219
- exception = nil
220
- handler = ->(e) { exception = e; '<!-- error -->' }
221
-
222
- output = Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_renderer: handler)
223
-
224
- assert exception.is_a?(Liquid::ZeroDivisionError)
225
- assert_equal '<!-- error -->', output
226
- end
227
-
228
- def test_exception_renderer_that_raises
229
- exception = nil
230
- assert_raises(Liquid::ZeroDivisionError) do
231
- Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_renderer: ->(e) { exception = e; raise })
232
- end
233
- assert exception.is_a?(Liquid::ZeroDivisionError)
234
- end
235
-
236
- def test_global_filter_option_on_render
237
- global_filter_proc = ->(output) { "#{output} filtered" }
238
- rendered_template = Template.parse("{{name}}").render({ "name" => "bob" }, global_filter: global_filter_proc)
239
-
240
- assert_equal 'bob filtered', rendered_template
241
- end
242
-
243
- def test_global_filter_option_when_native_filters_exist
244
- global_filter_proc = ->(output) { "#{output} filtered" }
245
- rendered_template = Template.parse("{{name | upcase}}").render({ "name" => "bob" }, global_filter: global_filter_proc)
246
-
247
- assert_equal 'BOB filtered', rendered_template
248
- end
249
-
250
- def test_undefined_variables
251
- t = Template.parse("{{x}} {{y}} {{z.a}} {{z.b}} {{z.c.d}}")
252
- result = t.render({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } }, { strict_variables: true })
253
-
254
- assert_equal '33 32 ', result
255
- assert_equal 3, t.errors.count
256
- assert_instance_of Liquid::UndefinedVariable, t.errors[0]
257
- assert_equal 'Liquid error: undefined variable y', t.errors[0].message
258
- assert_instance_of Liquid::UndefinedVariable, t.errors[1]
259
- assert_equal 'Liquid error: undefined variable b', t.errors[1].message
260
- assert_instance_of Liquid::UndefinedVariable, t.errors[2]
261
- assert_equal 'Liquid error: undefined variable d', t.errors[2].message
262
- end
263
-
264
- def test_nil_value_does_not_raise
265
- Liquid::Template.error_mode = :strict
266
- t = Template.parse("some{{x}}thing")
267
- result = t.render!({ 'x' => nil }, strict_variables: true)
268
-
269
- assert_equal 0, t.errors.count
270
- assert_equal 'something', result
271
- end
272
-
273
- def test_undefined_variables_raise
274
- t = Template.parse("{{x}} {{y}} {{z.a}} {{z.b}} {{z.c.d}}")
275
-
276
- assert_raises UndefinedVariable do
277
- t.render!({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } }, { strict_variables: true })
278
- end
279
- end
280
-
281
- def test_undefined_drop_methods
282
- d = DropWithUndefinedMethod.new
283
- t = Template.new.parse('{{ foo }} {{ woot }}')
284
- result = t.render(d, { strict_variables: true })
285
-
286
- assert_equal 'foo ', result
287
- assert_equal 1, t.errors.count
288
- assert_instance_of Liquid::UndefinedDropMethod, t.errors[0]
289
- end
290
-
291
- def test_undefined_drop_methods_raise
292
- d = DropWithUndefinedMethod.new
293
- t = Template.new.parse('{{ foo }} {{ woot }}')
294
-
295
- assert_raises UndefinedDropMethod do
296
- t.render!(d, { strict_variables: true })
297
- end
298
- end
299
-
300
- def test_undefined_filters
301
- t = Template.parse("{{a}} {{x | upcase | somefilter1 | somefilter2 | somefilter3}}")
302
- filters = Module.new do
303
- def somefilter3(v)
304
- "-#{v}-"
305
- end
306
- end
307
- result = t.render({ 'a' => 123, 'x' => 'foo' }, { filters: [filters], strict_filters: true })
308
-
309
- assert_equal '123 ', result
310
- assert_equal 1, t.errors.count
311
- assert_instance_of Liquid::UndefinedFilter, t.errors[0]
312
- assert_equal 'Liquid error: undefined filter somefilter1', t.errors[0].message
313
- end
314
-
315
- def test_undefined_filters_raise
316
- t = Template.parse("{{x | somefilter1 | upcase | somefilter2}}")
317
-
318
- assert_raises UndefinedFilter do
319
- t.render!({ 'x' => 'foo' }, { strict_filters: true })
320
- end
321
- end
322
-
323
- def test_using_range_literal_works_as_expected
324
- t = Template.parse("{% assign foo = (x..y) %}{{ foo }}")
325
- result = t.render({ 'x' => 1, 'y' => 5 })
326
- assert_equal '1..5', result
327
-
328
- t = Template.parse("{% assign nums = (x..y) %}{% for num in nums %}{{ num }}{% endfor %}")
329
- result = t.render({ 'x' => 1, 'y' => 5 })
330
- assert_equal '12345', result
331
- end
332
- end