liquid 3.0.0 → 4.0.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 (100) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +130 -62
  3. data/README.md +31 -0
  4. data/lib/liquid/block.rb +31 -124
  5. data/lib/liquid/block_body.rb +75 -59
  6. data/lib/liquid/condition.rb +23 -22
  7. data/lib/liquid/context.rb +51 -60
  8. data/lib/liquid/document.rb +19 -9
  9. data/lib/liquid/drop.rb +17 -16
  10. data/lib/liquid/errors.rb +20 -24
  11. data/lib/liquid/expression.rb +15 -3
  12. data/lib/liquid/extensions.rb +13 -7
  13. data/lib/liquid/file_system.rb +11 -11
  14. data/lib/liquid/forloop_drop.rb +42 -0
  15. data/lib/liquid/i18n.rb +5 -5
  16. data/lib/liquid/interrupts.rb +1 -2
  17. data/lib/liquid/lexer.rb +6 -4
  18. data/lib/liquid/locales/en.yml +5 -1
  19. data/lib/liquid/parse_context.rb +37 -0
  20. data/lib/liquid/parser.rb +1 -1
  21. data/lib/liquid/parser_switching.rb +4 -4
  22. data/lib/liquid/profiler/hooks.rb +7 -7
  23. data/lib/liquid/profiler.rb +18 -19
  24. data/lib/liquid/range_lookup.rb +16 -1
  25. data/lib/liquid/resource_limits.rb +23 -0
  26. data/lib/liquid/standardfilters.rb +121 -61
  27. data/lib/liquid/strainer.rb +32 -29
  28. data/lib/liquid/tablerowloop_drop.rb +62 -0
  29. data/lib/liquid/tag.rb +9 -8
  30. data/lib/liquid/tags/assign.rb +17 -4
  31. data/lib/liquid/tags/break.rb +0 -3
  32. data/lib/liquid/tags/capture.rb +2 -2
  33. data/lib/liquid/tags/case.rb +19 -12
  34. data/lib/liquid/tags/comment.rb +2 -2
  35. data/lib/liquid/tags/cycle.rb +6 -6
  36. data/lib/liquid/tags/decrement.rb +1 -4
  37. data/lib/liquid/tags/for.rb +95 -75
  38. data/lib/liquid/tags/if.rb +48 -43
  39. data/lib/liquid/tags/ifchanged.rb +0 -2
  40. data/lib/liquid/tags/include.rb +61 -52
  41. data/lib/liquid/tags/raw.rb +32 -4
  42. data/lib/liquid/tags/table_row.rb +12 -31
  43. data/lib/liquid/tags/unless.rb +4 -5
  44. data/lib/liquid/template.rb +42 -54
  45. data/lib/liquid/tokenizer.rb +31 -0
  46. data/lib/liquid/utils.rb +52 -8
  47. data/lib/liquid/variable.rb +46 -45
  48. data/lib/liquid/variable_lookup.rb +9 -5
  49. data/lib/liquid/version.rb +1 -1
  50. data/lib/liquid.rb +9 -7
  51. data/test/integration/assign_test.rb +18 -8
  52. data/test/integration/blank_test.rb +14 -14
  53. data/test/integration/capture_test.rb +10 -0
  54. data/test/integration/context_test.rb +2 -2
  55. data/test/integration/document_test.rb +19 -0
  56. data/test/integration/drop_test.rb +42 -40
  57. data/test/integration/error_handling_test.rb +99 -46
  58. data/test/integration/filter_test.rb +72 -19
  59. data/test/integration/hash_ordering_test.rb +9 -9
  60. data/test/integration/output_test.rb +34 -27
  61. data/test/integration/parsing_quirks_test.rb +15 -13
  62. data/test/integration/render_profiling_test.rb +20 -20
  63. data/test/integration/security_test.rb +9 -7
  64. data/test/integration/standard_filter_test.rb +198 -42
  65. data/test/integration/tags/break_tag_test.rb +1 -2
  66. data/test/integration/tags/continue_tag_test.rb +0 -1
  67. data/test/integration/tags/for_tag_test.rb +133 -98
  68. data/test/integration/tags/if_else_tag_test.rb +96 -77
  69. data/test/integration/tags/include_tag_test.rb +34 -30
  70. data/test/integration/tags/increment_tag_test.rb +10 -11
  71. data/test/integration/tags/raw_tag_test.rb +7 -1
  72. data/test/integration/tags/standard_tag_test.rb +121 -122
  73. data/test/integration/tags/statements_test.rb +3 -5
  74. data/test/integration/tags/table_row_test.rb +20 -19
  75. data/test/integration/tags/unless_else_tag_test.rb +6 -6
  76. data/test/integration/template_test.rb +190 -49
  77. data/test/integration/trim_mode_test.rb +525 -0
  78. data/test/integration/variable_test.rb +23 -13
  79. data/test/test_helper.rb +44 -9
  80. data/test/unit/block_unit_test.rb +8 -5
  81. data/test/unit/condition_unit_test.rb +86 -77
  82. data/test/unit/context_unit_test.rb +48 -57
  83. data/test/unit/file_system_unit_test.rb +3 -3
  84. data/test/unit/i18n_unit_test.rb +2 -2
  85. data/test/unit/lexer_unit_test.rb +11 -8
  86. data/test/unit/parser_unit_test.rb +2 -2
  87. data/test/unit/regexp_unit_test.rb +1 -1
  88. data/test/unit/strainer_unit_test.rb +85 -8
  89. data/test/unit/tag_unit_test.rb +7 -2
  90. data/test/unit/tags/case_tag_unit_test.rb +1 -1
  91. data/test/unit/tags/for_tag_unit_test.rb +2 -2
  92. data/test/unit/tags/if_tag_unit_test.rb +1 -1
  93. data/test/unit/template_unit_test.rb +14 -5
  94. data/test/unit/tokenizer_unit_test.rb +24 -7
  95. data/test/unit/variable_unit_test.rb +66 -43
  96. metadata +55 -50
  97. data/lib/liquid/module_ex.rb +0 -62
  98. data/lib/liquid/token.rb +0 -18
  99. data/test/unit/module_ex_unit_test.rb +0 -87
  100. /data/{MIT-LICENSE → LICENSE} +0 -0
@@ -41,6 +41,16 @@ class TestEnumerable < Liquid::Drop
41
41
  end
42
42
  end
43
43
 
44
+ class NumberLikeThing < Liquid::Drop
45
+ def initialize(amount)
46
+ @amount = amount
47
+ end
48
+
49
+ def to_number
50
+ @amount
51
+ end
52
+ end
53
+
44
54
  class StandardFiltersTest < Minitest::Test
45
55
  include Liquid
46
56
 
@@ -49,7 +59,7 @@ class StandardFiltersTest < Minitest::Test
49
59
  end
50
60
 
51
61
  def test_size
52
- assert_equal 3, @filters.size([1,2,3])
62
+ assert_equal 3, @filters.size([1, 2, 3])
53
63
  assert_equal 0, @filters.size([])
54
64
  assert_equal 0, @filters.size(nil)
55
65
  end
@@ -76,20 +86,27 @@ class StandardFiltersTest < Minitest::Test
76
86
  assert_equal '', @filters.slice(nil, 0)
77
87
  assert_equal '', @filters.slice('foobar', 100, 10)
78
88
  assert_equal '', @filters.slice('foobar', -100, 10)
89
+ assert_equal 'oob', @filters.slice('foobar', '1', '3')
90
+ assert_raises(Liquid::ArgumentError) do
91
+ @filters.slice('foobar', nil)
92
+ end
93
+ assert_raises(Liquid::ArgumentError) do
94
+ @filters.slice('foobar', 0, "")
95
+ end
79
96
  end
80
97
 
81
98
  def test_slice_on_arrays
82
99
  input = 'foobar'.split(//)
83
- assert_equal %w{o o b}, @filters.slice(input, 1, 3)
84
- assert_equal %w{o o b a r}, @filters.slice(input, 1, 1000)
85
- assert_equal %w{}, @filters.slice(input, 1, 0)
86
- assert_equal %w{o}, @filters.slice(input, 1, 1)
87
- assert_equal %w{b a r}, @filters.slice(input, 3, 3)
88
- assert_equal %w{a r}, @filters.slice(input, -2, 2)
89
- assert_equal %w{a r}, @filters.slice(input, -2, 1000)
90
- assert_equal %w{r}, @filters.slice(input, -1)
91
- assert_equal %w{}, @filters.slice(input, 100, 10)
92
- assert_equal %w{}, @filters.slice(input, -100, 10)
100
+ assert_equal %w(o o b), @filters.slice(input, 1, 3)
101
+ assert_equal %w(o o b a r), @filters.slice(input, 1, 1000)
102
+ assert_equal %w(), @filters.slice(input, 1, 0)
103
+ assert_equal %w(o), @filters.slice(input, 1, 1)
104
+ assert_equal %w(b a r), @filters.slice(input, 3, 3)
105
+ assert_equal %w(a r), @filters.slice(input, -2, 2)
106
+ assert_equal %w(a r), @filters.slice(input, -2, 1000)
107
+ assert_equal %w(r), @filters.slice(input, -1)
108
+ assert_equal %w(), @filters.slice(input, 100, 10)
109
+ assert_equal %w(), @filters.slice(input, -100, 10)
93
110
  end
94
111
 
95
112
  def test_truncate
@@ -98,19 +115,20 @@ class StandardFiltersTest < Minitest::Test
98
115
  assert_equal '...', @filters.truncate('1234567890', 0)
99
116
  assert_equal '1234567890', @filters.truncate('1234567890')
100
117
  assert_equal "测试...", @filters.truncate("测试测试测试测试", 5)
118
+ assert_equal '12341', @filters.truncate("1234567890", 5, 1)
101
119
  end
102
120
 
103
121
  def test_split
104
- assert_equal ['12','34'], @filters.split('12~34', '~')
105
- assert_equal ['A? ',' ,Z'], @filters.split('A? ~ ~ ~ ,Z', '~ ~ ~')
122
+ assert_equal ['12', '34'], @filters.split('12~34', '~')
123
+ assert_equal ['A? ', ' ,Z'], @filters.split('A? ~ ~ ~ ,Z', '~ ~ ~')
106
124
  assert_equal ['A?Z'], @filters.split('A?Z', '~')
107
- # Regexp works although Liquid does not support.
108
- assert_equal ['A','Z'], @filters.split('AxZ', /x/)
109
125
  assert_equal [], @filters.split(nil, ' ')
126
+ assert_equal ['A', 'Z'], @filters.split('A1Z', 1)
110
127
  end
111
128
 
112
129
  def test_escape
113
130
  assert_equal '&lt;strong&gt;', @filters.escape('<strong>')
131
+ assert_equal nil, @filters.escape(nil)
114
132
  assert_equal '&lt;strong&gt;', @filters.h('<strong>')
115
133
  end
116
134
 
@@ -123,12 +141,20 @@ class StandardFiltersTest < Minitest::Test
123
141
  assert_equal nil, @filters.url_encode(nil)
124
142
  end
125
143
 
144
+ def test_url_decode
145
+ assert_equal 'foo bar', @filters.url_decode('foo+bar')
146
+ assert_equal 'foo bar', @filters.url_decode('foo%20bar')
147
+ assert_equal 'foo+1@example.com', @filters.url_decode('foo%2B1%40example.com')
148
+ assert_equal nil, @filters.url_decode(nil)
149
+ end
150
+
126
151
  def test_truncatewords
127
152
  assert_equal 'one two three', @filters.truncatewords('one two three', 4)
128
153
  assert_equal 'one two...', @filters.truncatewords('one two three', 2)
129
154
  assert_equal 'one two three', @filters.truncatewords('one two three')
130
155
  assert_equal 'Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221;...', @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)
131
156
  assert_equal "测试测试测试测试", @filters.truncatewords('测试测试测试测试', 5)
157
+ assert_equal 'one two1', @filters.truncatewords("one two three", 2, 1)
132
158
  end
133
159
 
134
160
  def test_strip_html
@@ -142,45 +168,80 @@ class StandardFiltersTest < Minitest::Test
142
168
  end
143
169
 
144
170
  def test_join
145
- assert_equal '1 2 3 4', @filters.join([1,2,3,4])
146
- assert_equal '1 - 2 - 3 - 4', @filters.join([1,2,3,4], ' - ')
171
+ assert_equal '1 2 3 4', @filters.join([1, 2, 3, 4])
172
+ assert_equal '1 - 2 - 3 - 4', @filters.join([1, 2, 3, 4], ' - ')
147
173
  end
148
174
 
149
175
  def test_sort
150
- assert_equal [1,2,3,4], @filters.sort([4,3,2,1])
151
- assert_equal [{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], @filters.sort([{"a" => 4}, {"a" => 3}, {"a" => 1}, {"a" => 2}], "a")
176
+ assert_equal [1, 2, 3, 4], @filters.sort([4, 3, 2, 1])
177
+ assert_equal [{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], @filters.sort([{ "a" => 4 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a")
178
+ end
179
+
180
+ def test_sort_when_property_is_sometimes_missing_puts_nils_last
181
+ input = [
182
+ { "price" => 4, "handle" => "alpha" },
183
+ { "handle" => "beta" },
184
+ { "price" => 1, "handle" => "gamma" },
185
+ { "handle" => "delta" },
186
+ { "price" => 2, "handle" => "epsilon" }
187
+ ]
188
+ expectation = [
189
+ { "price" => 1, "handle" => "gamma" },
190
+ { "price" => 2, "handle" => "epsilon" },
191
+ { "price" => 4, "handle" => "alpha" },
192
+ { "handle" => "delta" },
193
+ { "handle" => "beta" }
194
+ ]
195
+ assert_equal expectation, @filters.sort(input, "price")
196
+ end
197
+
198
+ def test_sort_empty_array
199
+ assert_equal [], @filters.sort([], "a")
200
+ end
201
+
202
+ def test_sort_natural_empty_array
203
+ assert_equal [], @filters.sort_natural([], "a")
152
204
  end
153
205
 
154
206
  def test_legacy_sort_hash
155
- assert_equal [{a:1, b:2}], @filters.sort({a:1, b:2})
207
+ assert_equal [{ a: 1, b: 2 }], @filters.sort({ a: 1, b: 2 })
156
208
  end
157
209
 
158
210
  def test_numerical_vs_lexicographical_sort
159
211
  assert_equal [2, 10], @filters.sort([10, 2])
160
- assert_equal [{"a" => 2}, {"a" => 10}], @filters.sort([{"a" => 10}, {"a" => 2}], "a")
212
+ assert_equal [{ "a" => 2 }, { "a" => 10 }], @filters.sort([{ "a" => 10 }, { "a" => 2 }], "a")
161
213
  assert_equal ["10", "2"], @filters.sort(["10", "2"])
162
- assert_equal [{"a" => "10"}, {"a" => "2"}], @filters.sort([{"a" => "10"}, {"a" => "2"}], "a")
214
+ assert_equal [{ "a" => "10" }, { "a" => "2" }], @filters.sort([{ "a" => "10" }, { "a" => "2" }], "a")
163
215
  end
164
216
 
165
217
  def test_uniq
166
- assert_equal [1,3,2,4], @filters.uniq([1,1,3,2,3,1,4,3,2,1])
167
- assert_equal [{"a" => 1}, {"a" => 3}, {"a" => 2}], @filters.uniq([{"a" => 1}, {"a" => 3}, {"a" => 1}, {"a" => 2}], "a")
218
+ assert_equal ["foo"], @filters.uniq("foo")
219
+ assert_equal [1, 3, 2, 4], @filters.uniq([1, 1, 3, 2, 3, 1, 4, 3, 2, 1])
220
+ assert_equal [{ "a" => 1 }, { "a" => 3 }, { "a" => 2 }], @filters.uniq([{ "a" => 1 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a")
168
221
  testdrop = TestDrop.new
169
222
  assert_equal [testdrop], @filters.uniq([testdrop, TestDrop.new], 'test')
170
223
  end
171
224
 
225
+ def test_uniq_empty_array
226
+ assert_equal [], @filters.uniq([], "a")
227
+ end
228
+
229
+ def test_compact_empty_array
230
+ assert_equal [], @filters.compact([], "a")
231
+ end
232
+
172
233
  def test_reverse
173
- assert_equal [4,3,2,1], @filters.reverse([1,2,3,4])
234
+ assert_equal [4, 3, 2, 1], @filters.reverse([1, 2, 3, 4])
174
235
  end
175
236
 
176
237
  def test_legacy_reverse_hash
177
- assert_equal [{a:1, b:2}], @filters.reverse(a:1, b:2)
238
+ assert_equal [{ a: 1, b: 2 }], @filters.reverse(a: 1, b: 2)
178
239
  end
179
240
 
180
241
  def test_map
181
- assert_equal [1,2,3,4], @filters.map([{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], 'a')
242
+ assert_equal [1, 2, 3, 4], @filters.map([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], 'a')
182
243
  assert_template_result 'abc', "{{ ary | map:'foo' | map:'bar' }}",
183
- 'ary' => [{'foo' => {'bar' => 'a'}}, {'foo' => {'bar' => 'b'}}, {'foo' => {'bar' => 'c'}}]
244
+ 'ary' => [{ 'foo' => { 'bar' => 'a' } }, { 'foo' => { 'bar' => 'b' } }, { 'foo' => { 'bar' => 'c' } }]
184
245
  end
185
246
 
186
247
  def test_map_doesnt_call_arbitrary_stuff
@@ -212,11 +273,24 @@ class StandardFiltersTest < Minitest::Test
212
273
 
213
274
  def test_map_over_proc
214
275
  drop = TestDrop.new
215
- p = Proc.new{ drop }
276
+ p = proc{ drop }
216
277
  templ = '{{ procs | map: "test" }}'
217
278
  assert_template_result "testfoo", templ, "procs" => [p]
218
279
  end
219
280
 
281
+ def test_map_over_drops_returning_procs
282
+ drops = [
283
+ {
284
+ "proc" => ->{ "foo" },
285
+ },
286
+ {
287
+ "proc" => ->{ "bar" },
288
+ },
289
+ ]
290
+ templ = '{{ drops | map: "proc" }}'
291
+ assert_template_result "foobar", templ, "drops" => drops
292
+ end
293
+
220
294
  def test_map_works_on_enumerables
221
295
  assert_template_result "123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new
222
296
  end
@@ -230,6 +304,10 @@ class StandardFiltersTest < Minitest::Test
230
304
  assert_template_result 'foobar', '{{ foo | last }}', 'foo' => [ThingWithToLiquid.new]
231
305
  end
232
306
 
307
+ def test_truncate_calls_to_liquid
308
+ assert_template_result "wo...", '{{ foo | truncate: 5 }}', "foo" => TestThing.new
309
+ end
310
+
233
311
  def test_date
234
312
  assert_equal 'May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B")
235
313
  assert_equal 'June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B")
@@ -249,29 +327,38 @@ class StandardFiltersTest < Minitest::Test
249
327
  assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y")
250
328
  assert_equal "#{Date.today.year}", @filters.date('now', '%Y')
251
329
  assert_equal "#{Date.today.year}", @filters.date('today', '%Y')
330
+ assert_equal "#{Date.today.year}", @filters.date('Today', '%Y')
252
331
 
253
332
  assert_equal nil, @filters.date(nil, "%B")
254
333
 
255
- assert_equal "07/05/2006", @filters.date(1152098955, "%m/%d/%Y")
256
- assert_equal "07/05/2006", @filters.date("1152098955", "%m/%d/%Y")
334
+ assert_equal '', @filters.date('', "%B")
335
+
336
+ with_timezone("UTC") do
337
+ assert_equal "07/05/2006", @filters.date(1152098955, "%m/%d/%Y")
338
+ assert_equal "07/05/2006", @filters.date("1152098955", "%m/%d/%Y")
339
+ end
257
340
  end
258
341
 
259
342
  def test_first_last
260
- assert_equal 1, @filters.first([1,2,3])
261
- assert_equal 3, @filters.last([1,2,3])
343
+ assert_equal 1, @filters.first([1, 2, 3])
344
+ assert_equal 3, @filters.last([1, 2, 3])
262
345
  assert_equal nil, @filters.first([])
263
346
  assert_equal nil, @filters.last([])
264
347
  end
265
348
 
266
349
  def test_replace
267
350
  assert_equal '2 2 2 2', @filters.replace('1 1 1 1', '1', 2)
351
+ assert_equal '2 2 2 2', @filters.replace('1 1 1 1', 1, 2)
268
352
  assert_equal '2 1 1 1', @filters.replace_first('1 1 1 1', '1', 2)
353
+ assert_equal '2 1 1 1', @filters.replace_first('1 1 1 1', 1, 2)
269
354
  assert_template_result '2 1 1 1', "{{ '1 1 1 1' | replace_first: '1', 2 }}"
270
355
  end
271
356
 
272
357
  def test_remove
273
358
  assert_equal ' ', @filters.remove("a a a a", 'a')
359
+ assert_equal ' ', @filters.remove("1 1 1 1", 1)
274
360
  assert_equal 'a a a', @filters.remove_first("a a a a", 'a ')
361
+ assert_equal ' 1 1 1', @filters.remove_first("1 1 1 1", 1)
275
362
  assert_template_result 'a a a', "{{ 'a a a a' | remove_first: 'a ' }}"
276
363
  end
277
364
 
@@ -306,20 +393,38 @@ class StandardFiltersTest < Minitest::Test
306
393
  def test_plus
307
394
  assert_template_result "2", "{{ 1 | plus:1 }}"
308
395
  assert_template_result "2.0", "{{ '1' | plus:'1.0' }}"
396
+
397
+ assert_template_result "5", "{{ price | plus:'2' }}", 'price' => NumberLikeThing.new(3)
309
398
  end
310
399
 
311
400
  def test_minus
312
401
  assert_template_result "4", "{{ input | minus:operand }}", 'input' => 5, 'operand' => 1
313
402
  assert_template_result "2.3", "{{ '4.3' | minus:'2' }}"
403
+
404
+ assert_template_result "5", "{{ price | minus:'2' }}", 'price' => NumberLikeThing.new(7)
405
+ end
406
+
407
+ def test_abs
408
+ assert_template_result "17", "{{ 17 | abs }}"
409
+ assert_template_result "17", "{{ -17 | abs }}"
410
+ assert_template_result "17", "{{ '17' | abs }}"
411
+ assert_template_result "17", "{{ '-17' | abs }}"
412
+ assert_template_result "0", "{{ 0 | abs }}"
413
+ assert_template_result "0", "{{ '0' | abs }}"
414
+ assert_template_result "17.42", "{{ 17.42 | abs }}"
415
+ assert_template_result "17.42", "{{ -17.42 | abs }}"
416
+ assert_template_result "17.42", "{{ '17.42' | abs }}"
417
+ assert_template_result "17.42", "{{ '-17.42' | abs }}"
314
418
  end
315
419
 
316
420
  def test_times
317
421
  assert_template_result "12", "{{ 3 | times:4 }}"
318
422
  assert_template_result "0", "{{ 'foo' | times:4 }}"
319
-
320
423
  assert_template_result "6", "{{ '2.1' | times:3 | replace: '.','-' | plus:0}}"
321
-
322
424
  assert_template_result "7.25", "{{ 0.0725 | times:100 }}"
425
+ assert_template_result "-7.25", '{{ "-0.0725" | times:100 }}'
426
+ assert_template_result "7.25", '{{ "-0.0725" | times: -100 }}'
427
+ assert_template_result "4", "{{ price | times:2 }}", 'price' => NumberLikeThing.new(2)
323
428
  end
324
429
 
325
430
  def test_divided_by
@@ -330,38 +435,74 @@ class StandardFiltersTest < Minitest::Test
330
435
  assert_equal "Liquid error: divided by 0", Template.parse("{{ 5 | divided_by:0 }}").render
331
436
 
332
437
  assert_template_result "0.5", "{{ 2.0 | divided_by:4 }}"
438
+ assert_raises(Liquid::ZeroDivisionError) do
439
+ assert_template_result "4", "{{ 1 | modulo: 0 }}"
440
+ end
441
+
442
+ assert_template_result "5", "{{ price | divided_by:2 }}", 'price' => NumberLikeThing.new(10)
333
443
  end
334
444
 
335
445
  def test_modulo
336
446
  assert_template_result "1", "{{ 3 | modulo:2 }}"
447
+ assert_raises(Liquid::ZeroDivisionError) do
448
+ assert_template_result "4", "{{ 1 | modulo: 0 }}"
449
+ end
450
+
451
+ assert_template_result "1", "{{ price | modulo:2 }}", 'price' => NumberLikeThing.new(3)
337
452
  end
338
453
 
339
454
  def test_round
340
455
  assert_template_result "5", "{{ input | round }}", 'input' => 4.6
341
456
  assert_template_result "4", "{{ '4.3' | round }}"
342
457
  assert_template_result "4.56", "{{ input | round: 2 }}", 'input' => 4.5612
458
+ assert_raises(Liquid::FloatDomainError) do
459
+ assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | round }}"
460
+ end
461
+
462
+ assert_template_result "5", "{{ price | round }}", 'price' => NumberLikeThing.new(4.6)
463
+ assert_template_result "4", "{{ price | round }}", 'price' => NumberLikeThing.new(4.3)
343
464
  end
344
465
 
345
466
  def test_ceil
346
467
  assert_template_result "5", "{{ input | ceil }}", 'input' => 4.6
347
468
  assert_template_result "5", "{{ '4.3' | ceil }}"
469
+ assert_raises(Liquid::FloatDomainError) do
470
+ assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | ceil }}"
471
+ end
472
+
473
+ assert_template_result "5", "{{ price | ceil }}", 'price' => NumberLikeThing.new(4.6)
348
474
  end
349
475
 
350
476
  def test_floor
351
477
  assert_template_result "4", "{{ input | floor }}", 'input' => 4.6
352
478
  assert_template_result "4", "{{ '4.3' | floor }}"
479
+ assert_raises(Liquid::FloatDomainError) do
480
+ assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | floor }}"
481
+ end
482
+
483
+ assert_template_result "5", "{{ price | floor }}", 'price' => NumberLikeThing.new(5.4)
353
484
  end
354
485
 
355
486
  def test_append
356
- assigns = {'a' => 'bc', 'b' => 'd' }
357
- assert_template_result('bcd',"{{ a | append: 'd'}}",assigns)
358
- assert_template_result('bcd',"{{ a | append: b}}",assigns)
487
+ assigns = { 'a' => 'bc', 'b' => 'd' }
488
+ assert_template_result('bcd', "{{ a | append: 'd'}}", assigns)
489
+ assert_template_result('bcd', "{{ a | append: b}}", assigns)
490
+ end
491
+
492
+ def test_concat
493
+ assert_equal [1, 2, 3, 4], @filters.concat([1, 2], [3, 4])
494
+ assert_equal [1, 2, 'a'], @filters.concat([1, 2], ['a'])
495
+ assert_equal [1, 2, 10], @filters.concat([1, 2], [10])
496
+
497
+ assert_raises(Liquid::ArgumentError, "concat filter requires an array argument") do
498
+ @filters.concat([1, 2], 10)
499
+ end
359
500
  end
360
501
 
361
502
  def test_prepend
362
- assigns = {'a' => 'bc', 'b' => 'a' }
363
- assert_template_result('abc',"{{ a | prepend: 'a'}}",assigns)
364
- assert_template_result('abc',"{{ a | prepend: b}}",assigns)
503
+ assigns = { 'a' => 'bc', 'b' => 'a' }
504
+ assert_template_result('abc', "{{ a | prepend: 'a'}}", assigns)
505
+ assert_template_result('abc', "{{ a | prepend: b}}", assigns)
365
506
  end
366
507
 
367
508
  def test_default
@@ -374,6 +515,21 @@ class StandardFiltersTest < Minitest::Test
374
515
  end
375
516
 
376
517
  def test_cannot_access_private_methods
377
- assert_template_result('a',"{{ 'a' | to_number }}")
518
+ assert_template_result('a', "{{ 'a' | to_number }}")
519
+ end
520
+
521
+ def test_date_raises_nothing
522
+ assert_template_result('', "{{ '' | date: '%D' }}")
523
+ assert_template_result('abc', "{{ 'abc' | date: '%D' }}")
524
+ end
525
+
526
+ private
527
+
528
+ def with_timezone(tz)
529
+ old_tz = ENV['TZ']
530
+ ENV['TZ'] = tz
531
+ yield
532
+ ensure
533
+ ENV['TZ'] = old_tz
378
534
  end
379
535
  end # StandardFiltersTest
@@ -6,11 +6,10 @@ class BreakTagTest < Minitest::Test
6
6
  # tests that no weird errors are raised if break is called outside of a
7
7
  # block
8
8
  def test_break_with_no_block
9
- assigns = {'i' => 1}
9
+ assigns = { 'i' => 1 }
10
10
  markup = '{% break %}'
11
11
  expected = ''
12
12
 
13
13
  assert_template_result(expected, markup, assigns)
14
14
  end
15
-
16
15
  end
@@ -12,5 +12,4 @@ class ContinueTagTest < Minitest::Test
12
12
 
13
13
  assert_template_result(expected, markup, assigns)
14
14
  end
15
-
16
15
  end