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