liquid 5.1.0 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
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,880 +0,0 @@
1
- # encoding: utf-8
2
- # frozen_string_literal: true
3
-
4
- require 'test_helper'
5
-
6
- class Filters
7
- include Liquid::StandardFilters
8
- end
9
-
10
- class TestThing
11
- attr_reader :foo
12
-
13
- def initialize
14
- @foo = 0
15
- end
16
-
17
- def to_s
18
- "woot: #{@foo}"
19
- end
20
-
21
- def [](_whatever)
22
- to_s
23
- end
24
-
25
- def to_liquid
26
- @foo += 1
27
- self
28
- end
29
- end
30
-
31
- class TestDrop < Liquid::Drop
32
- def test
33
- "testfoo"
34
- end
35
- end
36
-
37
- class TestEnumerable < Liquid::Drop
38
- include Enumerable
39
-
40
- def each(&block)
41
- [{ "foo" => 1, "bar" => 2 }, { "foo" => 2, "bar" => 1 }, { "foo" => 3, "bar" => 3 }].each(&block)
42
- end
43
- end
44
-
45
- class NumberLikeThing < Liquid::Drop
46
- def initialize(amount)
47
- @amount = amount
48
- end
49
-
50
- def to_number
51
- @amount
52
- end
53
- end
54
-
55
- class StandardFiltersTest < Minitest::Test
56
- include Liquid
57
-
58
- def setup
59
- @filters = Filters.new
60
- end
61
-
62
- def test_size
63
- assert_equal(3, @filters.size([1, 2, 3]))
64
- assert_equal(0, @filters.size([]))
65
- assert_equal(0, @filters.size(nil))
66
- end
67
-
68
- def test_downcase
69
- assert_equal('testing', @filters.downcase("Testing"))
70
- assert_equal('', @filters.downcase(nil))
71
- end
72
-
73
- def test_upcase
74
- assert_equal('TESTING', @filters.upcase("Testing"))
75
- assert_equal('', @filters.upcase(nil))
76
- end
77
-
78
- def test_slice
79
- assert_equal('oob', @filters.slice('foobar', 1, 3))
80
- assert_equal('oobar', @filters.slice('foobar', 1, 1000))
81
- assert_equal('', @filters.slice('foobar', 1, 0))
82
- assert_equal('o', @filters.slice('foobar', 1, 1))
83
- assert_equal('bar', @filters.slice('foobar', 3, 3))
84
- assert_equal('ar', @filters.slice('foobar', -2, 2))
85
- assert_equal('ar', @filters.slice('foobar', -2, 1000))
86
- assert_equal('r', @filters.slice('foobar', -1))
87
- assert_equal('', @filters.slice(nil, 0))
88
- assert_equal('', @filters.slice('foobar', 100, 10))
89
- assert_equal('', @filters.slice('foobar', -100, 10))
90
- assert_equal('oob', @filters.slice('foobar', '1', '3'))
91
- assert_raises(Liquid::ArgumentError) do
92
- @filters.slice('foobar', nil)
93
- end
94
- assert_raises(Liquid::ArgumentError) do
95
- @filters.slice('foobar', 0, "")
96
- end
97
- end
98
-
99
- def test_slice_on_arrays
100
- input = 'foobar'.split(//)
101
- assert_equal(%w(o o b), @filters.slice(input, 1, 3))
102
- assert_equal(%w(o o b a r), @filters.slice(input, 1, 1000))
103
- assert_equal(%w(), @filters.slice(input, 1, 0))
104
- assert_equal(%w(o), @filters.slice(input, 1, 1))
105
- assert_equal(%w(b a r), @filters.slice(input, 3, 3))
106
- assert_equal(%w(a r), @filters.slice(input, -2, 2))
107
- assert_equal(%w(a r), @filters.slice(input, -2, 1000))
108
- assert_equal(%w(r), @filters.slice(input, -1))
109
- assert_equal(%w(), @filters.slice(input, 100, 10))
110
- assert_equal(%w(), @filters.slice(input, -100, 10))
111
- end
112
-
113
- def test_truncate
114
- assert_equal('1234...', @filters.truncate('1234567890', 7))
115
- assert_equal('1234567890', @filters.truncate('1234567890', 20))
116
- assert_equal('...', @filters.truncate('1234567890', 0))
117
- assert_equal('1234567890', @filters.truncate('1234567890'))
118
- assert_equal("测试...", @filters.truncate("测试测试测试测试", 5))
119
- assert_equal('12341', @filters.truncate("1234567890", 5, 1))
120
- end
121
-
122
- def test_split
123
- assert_equal(['12', '34'], @filters.split('12~34', '~'))
124
- assert_equal(['A? ', ' ,Z'], @filters.split('A? ~ ~ ~ ,Z', '~ ~ ~'))
125
- assert_equal(['A?Z'], @filters.split('A?Z', '~'))
126
- assert_equal([], @filters.split(nil, ' '))
127
- assert_equal(['A', 'Z'], @filters.split('A1Z', 1))
128
- end
129
-
130
- def test_escape
131
- assert_equal('&lt;strong&gt;', @filters.escape('<strong>'))
132
- assert_equal('1', @filters.escape(1))
133
- assert_equal('2001-02-03', @filters.escape(Date.new(2001, 2, 3)))
134
- assert_nil(@filters.escape(nil))
135
- end
136
-
137
- def test_h
138
- assert_equal('&lt;strong&gt;', @filters.h('<strong>'))
139
- assert_equal('1', @filters.h(1))
140
- assert_equal('2001-02-03', @filters.h(Date.new(2001, 2, 3)))
141
- assert_nil(@filters.h(nil))
142
- end
143
-
144
- def test_escape_once
145
- assert_equal('&lt;strong&gt;Hulk&lt;/strong&gt;', @filters.escape_once('&lt;strong&gt;Hulk</strong>'))
146
- end
147
-
148
- def test_base64_encode
149
- assert_equal('b25lIHR3byB0aHJlZQ==', @filters.base64_encode('one two three'))
150
- assert_equal('', @filters.base64_encode(nil))
151
- end
152
-
153
- def test_base64_decode
154
- assert_equal('one two three', @filters.base64_decode('b25lIHR3byB0aHJlZQ=='))
155
-
156
- exception = assert_raises(Liquid::ArgumentError) do
157
- @filters.base64_decode("invalidbase64")
158
- end
159
-
160
- assert_equal('Liquid error: invalid base64 provided to base64_decode', exception.message)
161
- end
162
-
163
- def test_base64_url_safe_encode
164
- assert_equal(
165
- 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXogQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogMTIzNDU2Nzg5MCAhQCMkJV4mKigpLT1fKy8_Ljo7W117fVx8',
166
- @filters.base64_url_safe_encode('abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 !@#$%^&*()-=_+/?.:;[]{}\|')
167
- )
168
- assert_equal('', @filters.base64_url_safe_encode(nil))
169
- end
170
-
171
- def test_base64_url_safe_decode
172
- assert_equal(
173
- 'abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 !@#$%^&*()-=_+/?.:;[]{}\|',
174
- @filters.base64_url_safe_decode('YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXogQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogMTIzNDU2Nzg5MCAhQCMkJV4mKigpLT1fKy8_Ljo7W117fVx8')
175
- )
176
- exception = assert_raises(Liquid::ArgumentError) do
177
- @filters.base64_url_safe_decode("invalidbase64")
178
- end
179
- assert_equal('Liquid error: invalid base64 provided to base64_url_safe_decode', exception.message)
180
- end
181
-
182
- def test_url_encode
183
- assert_equal('foo%2B1%40example.com', @filters.url_encode('foo+1@example.com'))
184
- assert_equal('1', @filters.url_encode(1))
185
- assert_equal('2001-02-03', @filters.url_encode(Date.new(2001, 2, 3)))
186
- assert_nil(@filters.url_encode(nil))
187
- end
188
-
189
- def test_url_decode
190
- assert_equal('foo bar', @filters.url_decode('foo+bar'))
191
- assert_equal('foo bar', @filters.url_decode('foo%20bar'))
192
- assert_equal('foo+1@example.com', @filters.url_decode('foo%2B1%40example.com'))
193
- assert_equal('1', @filters.url_decode(1))
194
- assert_equal('2001-02-03', @filters.url_decode(Date.new(2001, 2, 3)))
195
- assert_nil(@filters.url_decode(nil))
196
- exception = assert_raises(Liquid::ArgumentError) do
197
- @filters.url_decode('%ff')
198
- end
199
- assert_equal('Liquid error: invalid byte sequence in UTF-8', exception.message)
200
- end
201
-
202
- def test_truncatewords
203
- assert_equal('one two three', @filters.truncatewords('one two three', 4))
204
- assert_equal('one two...', @filters.truncatewords('one two three', 2))
205
- assert_equal('one two three', @filters.truncatewords('one two three'))
206
- assert_equal(
207
- 'Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221;...',
208
- @filters.truncatewords('Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221; x 16&#8221; x 10.5&#8221; high) with cover.', 15)
209
- )
210
- assert_equal("测试测试测试测试", @filters.truncatewords('测试测试测试测试', 5))
211
- assert_equal('one two1', @filters.truncatewords("one two three", 2, 1))
212
- assert_equal('one two three...', @filters.truncatewords("one two\tthree\nfour", 3))
213
- assert_equal('one two...', @filters.truncatewords("one two three four", 2))
214
- assert_equal('one...', @filters.truncatewords("one two three four", 0))
215
- exception = assert_raises(Liquid::ArgumentError) do
216
- @filters.truncatewords("one two three four", 1 << 31)
217
- end
218
- assert_equal("Liquid error: integer #{1 << 31} too big for truncatewords", exception.message)
219
- end
220
-
221
- def test_strip_html
222
- assert_equal('test', @filters.strip_html("<div>test</div>"))
223
- assert_equal('test', @filters.strip_html("<div id='test'>test</div>"))
224
- assert_equal('', @filters.strip_html("<script type='text/javascript'>document.write('some stuff');</script>"))
225
- assert_equal('', @filters.strip_html("<style type='text/css'>foo bar</style>"))
226
- assert_equal('test', @filters.strip_html("<div\nclass='multiline'>test</div>"))
227
- assert_equal('test', @filters.strip_html("<!-- foo bar \n test -->test"))
228
- assert_equal('', @filters.strip_html(nil))
229
-
230
- # Quirk of the existing implementation
231
- assert_equal('foo;', @filters.strip_html("<<<script </script>script>foo;</script>"))
232
- end
233
-
234
- def test_join
235
- assert_equal('1 2 3 4', @filters.join([1, 2, 3, 4]))
236
- assert_equal('1 - 2 - 3 - 4', @filters.join([1, 2, 3, 4], ' - '))
237
- assert_equal('1121314', @filters.join([1, 2, 3, 4], 1))
238
- end
239
-
240
- def test_sort
241
- assert_equal([1, 2, 3, 4], @filters.sort([4, 3, 2, 1]))
242
- assert_equal([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], @filters.sort([{ "a" => 4 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a"))
243
- end
244
-
245
- def test_sort_with_nils
246
- assert_equal([1, 2, 3, 4, nil], @filters.sort([nil, 4, 3, 2, 1]))
247
- assert_equal([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }, {}], @filters.sort([{ "a" => 4 }, { "a" => 3 }, {}, { "a" => 1 }, { "a" => 2 }], "a"))
248
- end
249
-
250
- def test_sort_when_property_is_sometimes_missing_puts_nils_last
251
- input = [
252
- { "price" => 4, "handle" => "alpha" },
253
- { "handle" => "beta" },
254
- { "price" => 1, "handle" => "gamma" },
255
- { "handle" => "delta" },
256
- { "price" => 2, "handle" => "epsilon" },
257
- ]
258
- expectation = [
259
- { "price" => 1, "handle" => "gamma" },
260
- { "price" => 2, "handle" => "epsilon" },
261
- { "price" => 4, "handle" => "alpha" },
262
- { "handle" => "delta" },
263
- { "handle" => "beta" },
264
- ]
265
- assert_equal(expectation, @filters.sort(input, "price"))
266
- end
267
-
268
- def test_sort_natural
269
- assert_equal(["a", "B", "c", "D"], @filters.sort_natural(["c", "D", "a", "B"]))
270
- assert_equal([{ "a" => "a" }, { "a" => "B" }, { "a" => "c" }, { "a" => "D" }], @filters.sort_natural([{ "a" => "D" }, { "a" => "c" }, { "a" => "a" }, { "a" => "B" }], "a"))
271
- end
272
-
273
- def test_sort_natural_with_nils
274
- assert_equal(["a", "B", "c", "D", nil], @filters.sort_natural([nil, "c", "D", "a", "B"]))
275
- assert_equal([{ "a" => "a" }, { "a" => "B" }, { "a" => "c" }, { "a" => "D" }, {}], @filters.sort_natural([{ "a" => "D" }, { "a" => "c" }, {}, { "a" => "a" }, { "a" => "B" }], "a"))
276
- end
277
-
278
- def test_sort_natural_when_property_is_sometimes_missing_puts_nils_last
279
- input = [
280
- { "price" => "4", "handle" => "alpha" },
281
- { "handle" => "beta" },
282
- { "price" => "1", "handle" => "gamma" },
283
- { "handle" => "delta" },
284
- { "price" => 2, "handle" => "epsilon" },
285
- ]
286
- expectation = [
287
- { "price" => "1", "handle" => "gamma" },
288
- { "price" => 2, "handle" => "epsilon" },
289
- { "price" => "4", "handle" => "alpha" },
290
- { "handle" => "delta" },
291
- { "handle" => "beta" },
292
- ]
293
- assert_equal(expectation, @filters.sort_natural(input, "price"))
294
- end
295
-
296
- def test_sort_natural_case_check
297
- input = [
298
- { "key" => "X" },
299
- { "key" => "Y" },
300
- { "key" => "Z" },
301
- { "fake" => "t" },
302
- { "key" => "a" },
303
- { "key" => "b" },
304
- { "key" => "c" },
305
- ]
306
- expectation = [
307
- { "key" => "a" },
308
- { "key" => "b" },
309
- { "key" => "c" },
310
- { "key" => "X" },
311
- { "key" => "Y" },
312
- { "key" => "Z" },
313
- { "fake" => "t" },
314
- ]
315
- assert_equal(expectation, @filters.sort_natural(input, "key"))
316
- assert_equal(["a", "b", "c", "X", "Y", "Z"], @filters.sort_natural(["X", "Y", "Z", "a", "b", "c"]))
317
- end
318
-
319
- def test_sort_empty_array
320
- assert_equal([], @filters.sort([], "a"))
321
- end
322
-
323
- def test_sort_invalid_property
324
- foo = [
325
- [1],
326
- [2],
327
- [3],
328
- ]
329
-
330
- assert_raises(Liquid::ArgumentError) do
331
- @filters.sort(foo, "bar")
332
- end
333
- end
334
-
335
- def test_sort_natural_empty_array
336
- assert_equal([], @filters.sort_natural([], "a"))
337
- end
338
-
339
- def test_sort_natural_invalid_property
340
- foo = [
341
- [1],
342
- [2],
343
- [3],
344
- ]
345
-
346
- assert_raises(Liquid::ArgumentError) do
347
- @filters.sort_natural(foo, "bar")
348
- end
349
- end
350
-
351
- def test_legacy_sort_hash
352
- assert_equal([{ a: 1, b: 2 }], @filters.sort(a: 1, b: 2))
353
- end
354
-
355
- def test_numerical_vs_lexicographical_sort
356
- assert_equal([2, 10], @filters.sort([10, 2]))
357
- assert_equal([{ "a" => 2 }, { "a" => 10 }], @filters.sort([{ "a" => 10 }, { "a" => 2 }], "a"))
358
- assert_equal(["10", "2"], @filters.sort(["10", "2"]))
359
- assert_equal([{ "a" => "10" }, { "a" => "2" }], @filters.sort([{ "a" => "10" }, { "a" => "2" }], "a"))
360
- end
361
-
362
- def test_uniq
363
- assert_equal(["foo"], @filters.uniq("foo"))
364
- assert_equal([1, 3, 2, 4], @filters.uniq([1, 1, 3, 2, 3, 1, 4, 3, 2, 1]))
365
- assert_equal([{ "a" => 1 }, { "a" => 3 }, { "a" => 2 }], @filters.uniq([{ "a" => 1 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a"))
366
- testdrop = TestDrop.new
367
- assert_equal([testdrop], @filters.uniq([testdrop, TestDrop.new], 'test'))
368
- end
369
-
370
- def test_uniq_empty_array
371
- assert_equal([], @filters.uniq([], "a"))
372
- end
373
-
374
- def test_uniq_invalid_property
375
- foo = [
376
- [1],
377
- [2],
378
- [3],
379
- ]
380
-
381
- assert_raises(Liquid::ArgumentError) do
382
- @filters.uniq(foo, "bar")
383
- end
384
- end
385
-
386
- def test_compact_empty_array
387
- assert_equal([], @filters.compact([], "a"))
388
- end
389
-
390
- def test_compact_invalid_property
391
- foo = [
392
- [1],
393
- [2],
394
- [3],
395
- ]
396
-
397
- assert_raises(Liquid::ArgumentError) do
398
- @filters.compact(foo, "bar")
399
- end
400
- end
401
-
402
- def test_reverse
403
- assert_equal([4, 3, 2, 1], @filters.reverse([1, 2, 3, 4]))
404
- end
405
-
406
- def test_legacy_reverse_hash
407
- assert_equal([{ a: 1, b: 2 }], @filters.reverse(a: 1, b: 2))
408
- end
409
-
410
- def test_map
411
- assert_equal([1, 2, 3, 4], @filters.map([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], 'a'))
412
- assert_template_result('abc', "{{ ary | map:'foo' | map:'bar' }}",
413
- 'ary' => [{ 'foo' => { 'bar' => 'a' } }, { 'foo' => { 'bar' => 'b' } }, { 'foo' => { 'bar' => 'c' } }])
414
- end
415
-
416
- def test_map_doesnt_call_arbitrary_stuff
417
- assert_template_result("", '{{ "foo" | map: "__id__" }}')
418
- assert_template_result("", '{{ "foo" | map: "inspect" }}')
419
- end
420
-
421
- def test_map_calls_to_liquid
422
- t = TestThing.new
423
- assert_template_result("woot: 1", '{{ foo | map: "whatever" }}', "foo" => [t])
424
- end
425
-
426
- def test_map_on_hashes
427
- assert_template_result("4217", '{{ thing | map: "foo" | map: "bar" }}',
428
- "thing" => { "foo" => [{ "bar" => 42 }, { "bar" => 17 }] })
429
- end
430
-
431
- def test_legacy_map_on_hashes_with_dynamic_key
432
- template = "{% assign key = 'foo' %}{{ thing | map: key | map: 'bar' }}"
433
- hash = { "foo" => { "bar" => 42 } }
434
- assert_template_result("42", template, "thing" => hash)
435
- end
436
-
437
- def test_sort_calls_to_liquid
438
- t = TestThing.new
439
- Liquid::Template.parse('{{ foo | sort: "whatever" }}').render("foo" => [t])
440
- assert(t.foo > 0)
441
- end
442
-
443
- def test_map_over_proc
444
- drop = TestDrop.new
445
- p = proc { drop }
446
- templ = '{{ procs | map: "test" }}'
447
- assert_template_result("testfoo", templ, "procs" => [p])
448
- end
449
-
450
- def test_map_over_drops_returning_procs
451
- drops = [
452
- {
453
- "proc" => -> { "foo" },
454
- },
455
- {
456
- "proc" => -> { "bar" },
457
- },
458
- ]
459
- templ = '{{ drops | map: "proc" }}'
460
- assert_template_result("foobar", templ, "drops" => drops)
461
- end
462
-
463
- def test_map_works_on_enumerables
464
- assert_template_result("123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new)
465
- end
466
-
467
- def test_map_returns_empty_on_2d_input_array
468
- foo = [
469
- [1],
470
- [2],
471
- [3],
472
- ]
473
-
474
- assert_raises(Liquid::ArgumentError) do
475
- @filters.map(foo, "bar")
476
- end
477
- end
478
-
479
- def test_map_returns_empty_with_no_property
480
- foo = [
481
- [1],
482
- [2],
483
- [3],
484
- ]
485
- assert_raises(Liquid::ArgumentError) do
486
- @filters.map(foo, nil)
487
- end
488
- end
489
-
490
- def test_sort_works_on_enumerables
491
- assert_template_result("213", '{{ foo | sort: "bar" | map: "foo" }}', "foo" => TestEnumerable.new)
492
- end
493
-
494
- def test_first_and_last_call_to_liquid
495
- assert_template_result('foobar', '{{ foo | first }}', 'foo' => [ThingWithToLiquid.new])
496
- assert_template_result('foobar', '{{ foo | last }}', 'foo' => [ThingWithToLiquid.new])
497
- end
498
-
499
- def test_truncate_calls_to_liquid
500
- assert_template_result("wo...", '{{ foo | truncate: 5 }}', "foo" => TestThing.new)
501
- end
502
-
503
- def test_date
504
- assert_equal('May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B"))
505
- assert_equal('June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B"))
506
- assert_equal('July', @filters.date(Time.parse("2006-07-05 10:00:00"), "%B"))
507
-
508
- assert_equal('May', @filters.date("2006-05-05 10:00:00", "%B"))
509
- assert_equal('June', @filters.date("2006-06-05 10:00:00", "%B"))
510
- assert_equal('July', @filters.date("2006-07-05 10:00:00", "%B"))
511
-
512
- assert_equal('2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", ""))
513
- assert_equal('2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", ""))
514
- assert_equal('2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", ""))
515
- assert_equal('2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", nil))
516
-
517
- assert_equal('07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y"))
518
-
519
- assert_equal("07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y"))
520
- assert_equal(Date.today.year.to_s, @filters.date('now', '%Y'))
521
- assert_equal(Date.today.year.to_s, @filters.date('today', '%Y'))
522
- assert_equal(Date.today.year.to_s, @filters.date('Today', '%Y'))
523
-
524
- assert_nil(@filters.date(nil, "%B"))
525
-
526
- assert_equal('', @filters.date('', "%B"))
527
-
528
- with_timezone("UTC") do
529
- assert_equal("07/05/2006", @filters.date(1152098955, "%m/%d/%Y"))
530
- assert_equal("07/05/2006", @filters.date("1152098955", "%m/%d/%Y"))
531
- end
532
- end
533
-
534
- def test_first_last
535
- assert_equal(1, @filters.first([1, 2, 3]))
536
- assert_equal(3, @filters.last([1, 2, 3]))
537
- assert_nil(@filters.first([]))
538
- assert_nil(@filters.last([]))
539
- end
540
-
541
- def test_replace
542
- assert_equal('2 2 2 2', @filters.replace('1 1 1 1', '1', 2))
543
- assert_equal('2 2 2 2', @filters.replace('1 1 1 1', 1, 2))
544
- assert_equal('2 1 1 1', @filters.replace_first('1 1 1 1', '1', 2))
545
- assert_equal('2 1 1 1', @filters.replace_first('1 1 1 1', 1, 2))
546
- assert_template_result('2 1 1 1', "{{ '1 1 1 1' | replace_first: '1', 2 }}")
547
- end
548
-
549
- def test_remove
550
- assert_equal(' ', @filters.remove("a a a a", 'a'))
551
- assert_equal(' ', @filters.remove("1 1 1 1", 1))
552
- assert_equal('a a a', @filters.remove_first("a a a a", 'a '))
553
- assert_equal(' 1 1 1', @filters.remove_first("1 1 1 1", 1))
554
- assert_template_result('a a a', "{{ 'a a a a' | remove_first: 'a ' }}")
555
- end
556
-
557
- def test_pipes_in_string_arguments
558
- assert_template_result('foobar', "{{ 'foo|bar' | remove: '|' }}")
559
- end
560
-
561
- def test_strip
562
- assert_template_result('ab c', "{{ source | strip }}", 'source' => " ab c ")
563
- assert_template_result('ab c', "{{ source | strip }}", 'source' => " \tab c \n \t")
564
- end
565
-
566
- def test_lstrip
567
- assert_template_result('ab c ', "{{ source | lstrip }}", 'source' => " ab c ")
568
- assert_template_result("ab c \n \t", "{{ source | lstrip }}", 'source' => " \tab c \n \t")
569
- end
570
-
571
- def test_rstrip
572
- assert_template_result(" ab c", "{{ source | rstrip }}", 'source' => " ab c ")
573
- assert_template_result(" \tab c", "{{ source | rstrip }}", 'source' => " \tab c \n \t")
574
- end
575
-
576
- def test_strip_newlines
577
- assert_template_result('abc', "{{ source | strip_newlines }}", 'source' => "a\nb\nc")
578
- assert_template_result('abc', "{{ source | strip_newlines }}", 'source' => "a\r\nb\nc")
579
- end
580
-
581
- def test_newlines_to_br
582
- assert_template_result("a<br />\nb<br />\nc", "{{ source | newline_to_br }}", 'source' => "a\nb\nc")
583
- assert_template_result("a<br />\nb<br />\nc", "{{ source | newline_to_br }}", 'source' => "a\r\nb\nc")
584
- end
585
-
586
- def test_plus
587
- assert_template_result("2", "{{ 1 | plus:1 }}")
588
- assert_template_result("2.0", "{{ '1' | plus:'1.0' }}")
589
-
590
- assert_template_result("5", "{{ price | plus:'2' }}", 'price' => NumberLikeThing.new(3))
591
- end
592
-
593
- def test_minus
594
- assert_template_result("4", "{{ input | minus:operand }}", 'input' => 5, 'operand' => 1)
595
- assert_template_result("2.3", "{{ '4.3' | minus:'2' }}")
596
-
597
- assert_template_result("5", "{{ price | minus:'2' }}", 'price' => NumberLikeThing.new(7))
598
- end
599
-
600
- def test_abs
601
- assert_template_result("17", "{{ 17 | abs }}")
602
- assert_template_result("17", "{{ -17 | abs }}")
603
- assert_template_result("17", "{{ '17' | abs }}")
604
- assert_template_result("17", "{{ '-17' | abs }}")
605
- assert_template_result("0", "{{ 0 | abs }}")
606
- assert_template_result("0", "{{ '0' | abs }}")
607
- assert_template_result("17.42", "{{ 17.42 | abs }}")
608
- assert_template_result("17.42", "{{ -17.42 | abs }}")
609
- assert_template_result("17.42", "{{ '17.42' | abs }}")
610
- assert_template_result("17.42", "{{ '-17.42' | abs }}")
611
- end
612
-
613
- def test_times
614
- assert_template_result("12", "{{ 3 | times:4 }}")
615
- assert_template_result("0", "{{ 'foo' | times:4 }}")
616
- assert_template_result("6", "{{ '2.1' | times:3 | replace: '.','-' | plus:0}}")
617
- assert_template_result("7.25", "{{ 0.0725 | times:100 }}")
618
- assert_template_result("-7.25", '{{ "-0.0725" | times:100 }}')
619
- assert_template_result("7.25", '{{ "-0.0725" | times: -100 }}')
620
- assert_template_result("4", "{{ price | times:2 }}", 'price' => NumberLikeThing.new(2))
621
- end
622
-
623
- def test_divided_by
624
- assert_template_result("4", "{{ 12 | divided_by:3 }}")
625
- assert_template_result("4", "{{ 14 | divided_by:3 }}")
626
-
627
- assert_template_result("5", "{{ 15 | divided_by:3 }}")
628
- assert_equal("Liquid error: divided by 0", Template.parse("{{ 5 | divided_by:0 }}").render)
629
-
630
- assert_template_result("0.5", "{{ 2.0 | divided_by:4 }}")
631
- assert_raises(Liquid::ZeroDivisionError) do
632
- assert_template_result("4", "{{ 1 | modulo: 0 }}")
633
- end
634
-
635
- assert_template_result("5", "{{ price | divided_by:2 }}", 'price' => NumberLikeThing.new(10))
636
- end
637
-
638
- def test_modulo
639
- assert_template_result("1", "{{ 3 | modulo:2 }}")
640
- assert_raises(Liquid::ZeroDivisionError) do
641
- assert_template_result("4", "{{ 1 | modulo: 0 }}")
642
- end
643
-
644
- assert_template_result("1", "{{ price | modulo:2 }}", 'price' => NumberLikeThing.new(3))
645
- end
646
-
647
- def test_round
648
- assert_template_result("5", "{{ input | round }}", 'input' => 4.6)
649
- assert_template_result("4", "{{ '4.3' | round }}")
650
- assert_template_result("4.56", "{{ input | round: 2 }}", 'input' => 4.5612)
651
- assert_raises(Liquid::FloatDomainError) do
652
- assert_template_result("4", "{{ 1.0 | divided_by: 0.0 | round }}")
653
- end
654
-
655
- assert_template_result("5", "{{ price | round }}", 'price' => NumberLikeThing.new(4.6))
656
- assert_template_result("4", "{{ price | round }}", 'price' => NumberLikeThing.new(4.3))
657
- end
658
-
659
- def test_ceil
660
- assert_template_result("5", "{{ input | ceil }}", 'input' => 4.6)
661
- assert_template_result("5", "{{ '4.3' | ceil }}")
662
- assert_raises(Liquid::FloatDomainError) do
663
- assert_template_result("4", "{{ 1.0 | divided_by: 0.0 | ceil }}")
664
- end
665
-
666
- assert_template_result("5", "{{ price | ceil }}", 'price' => NumberLikeThing.new(4.6))
667
- end
668
-
669
- def test_floor
670
- assert_template_result("4", "{{ input | floor }}", 'input' => 4.6)
671
- assert_template_result("4", "{{ '4.3' | floor }}")
672
- assert_raises(Liquid::FloatDomainError) do
673
- assert_template_result("4", "{{ 1.0 | divided_by: 0.0 | floor }}")
674
- end
675
-
676
- assert_template_result("5", "{{ price | floor }}", 'price' => NumberLikeThing.new(5.4))
677
- end
678
-
679
- def test_at_most
680
- assert_template_result("4", "{{ 5 | at_most:4 }}")
681
- assert_template_result("5", "{{ 5 | at_most:5 }}")
682
- assert_template_result("5", "{{ 5 | at_most:6 }}")
683
-
684
- assert_template_result("4.5", "{{ 4.5 | at_most:5 }}")
685
- assert_template_result("5", "{{ width | at_most:5 }}", 'width' => NumberLikeThing.new(6))
686
- assert_template_result("4", "{{ width | at_most:5 }}", 'width' => NumberLikeThing.new(4))
687
- assert_template_result("4", "{{ 5 | at_most: width }}", 'width' => NumberLikeThing.new(4))
688
- end
689
-
690
- def test_at_least
691
- assert_template_result("5", "{{ 5 | at_least:4 }}")
692
- assert_template_result("5", "{{ 5 | at_least:5 }}")
693
- assert_template_result("6", "{{ 5 | at_least:6 }}")
694
-
695
- assert_template_result("5", "{{ 4.5 | at_least:5 }}")
696
- assert_template_result("6", "{{ width | at_least:5 }}", 'width' => NumberLikeThing.new(6))
697
- assert_template_result("5", "{{ width | at_least:5 }}", 'width' => NumberLikeThing.new(4))
698
- assert_template_result("6", "{{ 5 | at_least: width }}", 'width' => NumberLikeThing.new(6))
699
- end
700
-
701
- def test_append
702
- assigns = { 'a' => 'bc', 'b' => 'd' }
703
- assert_template_result('bcd', "{{ a | append: 'd'}}", assigns)
704
- assert_template_result('bcd', "{{ a | append: b}}", assigns)
705
- end
706
-
707
- def test_concat
708
- assert_equal([1, 2, 3, 4], @filters.concat([1, 2], [3, 4]))
709
- assert_equal([1, 2, 'a'], @filters.concat([1, 2], ['a']))
710
- assert_equal([1, 2, 10], @filters.concat([1, 2], [10]))
711
-
712
- assert_raises(Liquid::ArgumentError, "concat filter requires an array argument") do
713
- @filters.concat([1, 2], 10)
714
- end
715
- end
716
-
717
- def test_prepend
718
- assigns = { 'a' => 'bc', 'b' => 'a' }
719
- assert_template_result('abc', "{{ a | prepend: 'a'}}", assigns)
720
- assert_template_result('abc', "{{ a | prepend: b}}", assigns)
721
- end
722
-
723
- def test_default
724
- assert_equal("foo", @filters.default("foo", "bar"))
725
- assert_equal("bar", @filters.default(nil, "bar"))
726
- assert_equal("bar", @filters.default("", "bar"))
727
- assert_equal("bar", @filters.default(false, "bar"))
728
- assert_equal("bar", @filters.default([], "bar"))
729
- assert_equal("bar", @filters.default({}, "bar"))
730
- assert_template_result('bar', "{{ false | default: 'bar' }}")
731
- assert_template_result('bar', "{{ drop | default: 'bar' }}", 'drop' => BooleanDrop.new(false))
732
- assert_template_result('Yay', "{{ drop | default: 'bar' }}", 'drop' => BooleanDrop.new(true))
733
- end
734
-
735
- def test_default_handle_false
736
- assert_equal("foo", @filters.default("foo", "bar", "allow_false" => true))
737
- assert_equal("bar", @filters.default(nil, "bar", "allow_false" => true))
738
- assert_equal("bar", @filters.default("", "bar", "allow_false" => true))
739
- assert_equal(false, @filters.default(false, "bar", "allow_false" => true))
740
- assert_equal("bar", @filters.default([], "bar", "allow_false" => true))
741
- assert_equal("bar", @filters.default({}, "bar", "allow_false" => true))
742
- assert_template_result('false', "{{ false | default: 'bar', allow_false: true }}")
743
- assert_template_result('Nay', "{{ drop | default: 'bar', allow_false: true }}", 'drop' => BooleanDrop.new(false))
744
- assert_template_result('Yay', "{{ drop | default: 'bar', allow_false: true }}", 'drop' => BooleanDrop.new(true))
745
- end
746
-
747
- def test_cannot_access_private_methods
748
- assert_template_result('a', "{{ 'a' | to_number }}")
749
- end
750
-
751
- def test_date_raises_nothing
752
- assert_template_result('', "{{ '' | date: '%D' }}")
753
- assert_template_result('abc', "{{ 'abc' | date: '%D' }}")
754
- end
755
-
756
- def test_where
757
- input = [
758
- { "handle" => "alpha", "ok" => true },
759
- { "handle" => "beta", "ok" => false },
760
- { "handle" => "gamma", "ok" => false },
761
- { "handle" => "delta", "ok" => true },
762
- ]
763
-
764
- expectation = [
765
- { "handle" => "alpha", "ok" => true },
766
- { "handle" => "delta", "ok" => true },
767
- ]
768
-
769
- assert_equal(expectation, @filters.where(input, "ok", true))
770
- assert_equal(expectation, @filters.where(input, "ok"))
771
- end
772
-
773
- def test_where_no_key_set
774
- input = [
775
- { "handle" => "alpha", "ok" => true },
776
- { "handle" => "beta" },
777
- { "handle" => "gamma" },
778
- { "handle" => "delta", "ok" => true },
779
- ]
780
-
781
- expectation = [
782
- { "handle" => "alpha", "ok" => true },
783
- { "handle" => "delta", "ok" => true },
784
- ]
785
-
786
- assert_equal(expectation, @filters.where(input, "ok", true))
787
- assert_equal(expectation, @filters.where(input, "ok"))
788
- end
789
-
790
- def test_where_non_array_map_input
791
- assert_equal([{ "a" => "ok" }], @filters.where({ "a" => "ok" }, "a", "ok"))
792
- assert_equal([], @filters.where({ "a" => "not ok" }, "a", "ok"))
793
- end
794
-
795
- def test_where_indexable_but_non_map_value
796
- assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok", true) }
797
- assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok") }
798
- end
799
-
800
- def test_where_non_boolean_value
801
- input = [
802
- { "message" => "Bonjour!", "language" => "French" },
803
- { "message" => "Hello!", "language" => "English" },
804
- { "message" => "Hallo!", "language" => "German" },
805
- ]
806
-
807
- assert_equal([{ "message" => "Bonjour!", "language" => "French" }], @filters.where(input, "language", "French"))
808
- assert_equal([{ "message" => "Hallo!", "language" => "German" }], @filters.where(input, "language", "German"))
809
- assert_equal([{ "message" => "Hello!", "language" => "English" }], @filters.where(input, "language", "English"))
810
- end
811
-
812
- def test_where_array_of_only_unindexable_values
813
- assert_nil(@filters.where([nil], "ok", true))
814
- assert_nil(@filters.where([nil], "ok"))
815
- end
816
-
817
- def test_all_filters_never_raise_non_liquid_exception
818
- test_drop = TestDrop.new
819
- test_drop.context = Context.new
820
- test_enum = TestEnumerable.new
821
- test_enum.context = Context.new
822
- test_types = [
823
- "foo",
824
- 123,
825
- 0,
826
- 0.0,
827
- -1234.003030303,
828
- -99999999,
829
- 1234.38383000383830003838300,
830
- nil,
831
- true,
832
- false,
833
- TestThing.new,
834
- test_drop,
835
- test_enum,
836
- ["foo", "bar"],
837
- { "foo" => "bar" },
838
- { foo: "bar" },
839
- [{ "foo" => "bar" }, { "foo" => 123 }, { "foo" => nil }, { "foo" => true }, { "foo" => ["foo", "bar"] }],
840
- { 1 => "bar" },
841
- ["foo", 123, nil, true, false, Drop, ["foo"], { foo: "bar" }],
842
- ]
843
- test_types.each do |first|
844
- test_types.each do |other|
845
- (@filters.methods - Object.methods).each do |method|
846
- arg_count = @filters.method(method).arity
847
- arg_count *= -1 if arg_count < 0
848
- inputs = [first]
849
- inputs << ([other] * (arg_count - 1)) if arg_count > 1
850
- begin
851
- @filters.send(method, *inputs)
852
- rescue Liquid::ArgumentError, Liquid::ZeroDivisionError
853
- nil
854
- end
855
- end
856
- end
857
- end
858
- end
859
-
860
- def test_where_no_target_value
861
- input = [
862
- { "foo" => false },
863
- { "foo" => true },
864
- { "foo" => "for sure" },
865
- { "bar" => true },
866
- ]
867
-
868
- assert_equal([{ "foo" => true }, { "foo" => "for sure" }], @filters.where(input, "foo"))
869
- end
870
-
871
- private
872
-
873
- def with_timezone(tz)
874
- old_tz = ENV['TZ']
875
- ENV['TZ'] = tz
876
- yield
877
- ensure
878
- ENV['TZ'] = old_tz
879
- end
880
- end # StandardFiltersTest