liquid 3.0.6 → 4.0.3
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.
- checksums.yaml +5 -5
- data/History.md +154 -58
- data/{MIT-LICENSE → LICENSE} +0 -0
- data/README.md +33 -0
- data/lib/liquid/block.rb +42 -125
- data/lib/liquid/block_body.rb +99 -79
- data/lib/liquid/condition.rb +52 -32
- data/lib/liquid/context.rb +57 -51
- data/lib/liquid/document.rb +19 -9
- data/lib/liquid/drop.rb +17 -16
- data/lib/liquid/errors.rb +20 -24
- data/lib/liquid/expression.rb +26 -10
- data/lib/liquid/extensions.rb +19 -7
- data/lib/liquid/file_system.rb +11 -11
- data/lib/liquid/forloop_drop.rb +42 -0
- data/lib/liquid/i18n.rb +6 -6
- data/lib/liquid/interrupts.rb +1 -2
- data/lib/liquid/lexer.rb +12 -8
- data/lib/liquid/locales/en.yml +6 -2
- data/lib/liquid/parse_context.rb +38 -0
- data/lib/liquid/parse_tree_visitor.rb +42 -0
- data/lib/liquid/parser_switching.rb +4 -4
- data/lib/liquid/profiler/hooks.rb +7 -7
- data/lib/liquid/profiler.rb +18 -19
- data/lib/liquid/range_lookup.rb +16 -1
- data/lib/liquid/resource_limits.rb +23 -0
- data/lib/liquid/standardfilters.rb +207 -61
- data/lib/liquid/strainer.rb +15 -8
- data/lib/liquid/tablerowloop_drop.rb +62 -0
- data/lib/liquid/tag.rb +9 -8
- data/lib/liquid/tags/assign.rb +25 -4
- data/lib/liquid/tags/break.rb +0 -3
- data/lib/liquid/tags/capture.rb +1 -1
- data/lib/liquid/tags/case.rb +27 -12
- data/lib/liquid/tags/comment.rb +2 -2
- data/lib/liquid/tags/cycle.rb +16 -8
- data/lib/liquid/tags/decrement.rb +1 -4
- data/lib/liquid/tags/for.rb +103 -75
- data/lib/liquid/tags/if.rb +60 -44
- data/lib/liquid/tags/ifchanged.rb +0 -2
- data/lib/liquid/tags/include.rb +71 -51
- data/lib/liquid/tags/raw.rb +32 -4
- data/lib/liquid/tags/table_row.rb +21 -31
- data/lib/liquid/tags/unless.rb +3 -4
- data/lib/liquid/template.rb +42 -54
- data/lib/liquid/tokenizer.rb +31 -0
- data/lib/liquid/truffle.rb +5 -0
- data/lib/liquid/utils.rb +52 -8
- data/lib/liquid/variable.rb +59 -46
- data/lib/liquid/variable_lookup.rb +14 -6
- data/lib/liquid/version.rb +2 -1
- data/lib/liquid.rb +10 -7
- data/test/integration/assign_test.rb +8 -8
- data/test/integration/blank_test.rb +14 -14
- data/test/integration/block_test.rb +12 -0
- data/test/integration/context_test.rb +2 -2
- data/test/integration/document_test.rb +19 -0
- data/test/integration/drop_test.rb +42 -40
- data/test/integration/error_handling_test.rb +96 -43
- data/test/integration/filter_test.rb +60 -20
- data/test/integration/hash_ordering_test.rb +9 -9
- data/test/integration/output_test.rb +26 -27
- data/test/integration/parse_tree_visitor_test.rb +247 -0
- data/test/integration/parsing_quirks_test.rb +19 -13
- data/test/integration/render_profiling_test.rb +20 -20
- data/test/integration/security_test.rb +23 -7
- data/test/integration/standard_filter_test.rb +426 -46
- data/test/integration/tags/break_tag_test.rb +1 -2
- data/test/integration/tags/continue_tag_test.rb +0 -1
- data/test/integration/tags/for_tag_test.rb +135 -100
- data/test/integration/tags/if_else_tag_test.rb +75 -77
- data/test/integration/tags/include_tag_test.rb +50 -31
- data/test/integration/tags/increment_tag_test.rb +10 -11
- data/test/integration/tags/raw_tag_test.rb +7 -1
- data/test/integration/tags/standard_tag_test.rb +121 -122
- data/test/integration/tags/statements_test.rb +3 -5
- data/test/integration/tags/table_row_test.rb +20 -19
- data/test/integration/tags/unless_else_tag_test.rb +6 -6
- data/test/integration/template_test.rb +199 -49
- data/test/integration/trim_mode_test.rb +529 -0
- data/test/integration/variable_test.rb +27 -13
- data/test/test_helper.rb +33 -6
- data/test/truffle/truffle_test.rb +9 -0
- data/test/unit/block_unit_test.rb +8 -5
- data/test/unit/condition_unit_test.rb +94 -77
- data/test/unit/context_unit_test.rb +69 -72
- data/test/unit/file_system_unit_test.rb +3 -3
- data/test/unit/i18n_unit_test.rb +2 -2
- data/test/unit/lexer_unit_test.rb +12 -9
- data/test/unit/parser_unit_test.rb +2 -2
- data/test/unit/regexp_unit_test.rb +1 -1
- data/test/unit/strainer_unit_test.rb +96 -1
- data/test/unit/tag_unit_test.rb +7 -2
- data/test/unit/tags/case_tag_unit_test.rb +1 -1
- data/test/unit/tags/for_tag_unit_test.rb +2 -2
- data/test/unit/tags/if_tag_unit_test.rb +1 -1
- data/test/unit/template_unit_test.rb +14 -5
- data/test/unit/tokenizer_unit_test.rb +24 -7
- data/test/unit/variable_unit_test.rb +60 -43
- metadata +62 -50
- data/lib/liquid/module_ex.rb +0 -62
- data/lib/liquid/token.rb +0 -18
- data/test/unit/module_ex_unit_test.rb +0 -87
@@ -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
|
84
|
-
assert_equal %w
|
85
|
-
assert_equal %w
|
86
|
-
assert_equal %w
|
87
|
-
assert_equal %w
|
88
|
-
assert_equal %w
|
89
|
-
assert_equal %w
|
90
|
-
assert_equal %w
|
91
|
-
assert_equal %w
|
92
|
-
assert_equal %w
|
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,20 +115,29 @@ 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 '<strong>', @filters.escape('<strong>')
|
131
|
+
assert_equal '1', @filters.escape(1)
|
132
|
+
assert_equal '2001-02-03', @filters.escape(Date.new(2001, 2, 3))
|
133
|
+
assert_nil @filters.escape(nil)
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_h
|
114
137
|
assert_equal '<strong>', @filters.h('<strong>')
|
138
|
+
assert_equal '1', @filters.h(1)
|
139
|
+
assert_equal '2001-02-03', @filters.h(Date.new(2001, 2, 3))
|
140
|
+
assert_nil @filters.h(nil)
|
115
141
|
end
|
116
142
|
|
117
143
|
def test_escape_once
|
@@ -120,7 +146,22 @@ class StandardFiltersTest < Minitest::Test
|
|
120
146
|
|
121
147
|
def test_url_encode
|
122
148
|
assert_equal 'foo%2B1%40example.com', @filters.url_encode('foo+1@example.com')
|
123
|
-
assert_equal
|
149
|
+
assert_equal '1', @filters.url_encode(1)
|
150
|
+
assert_equal '2001-02-03', @filters.url_encode(Date.new(2001, 2, 3))
|
151
|
+
assert_nil @filters.url_encode(nil)
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_url_decode
|
155
|
+
assert_equal 'foo bar', @filters.url_decode('foo+bar')
|
156
|
+
assert_equal 'foo bar', @filters.url_decode('foo%20bar')
|
157
|
+
assert_equal 'foo+1@example.com', @filters.url_decode('foo%2B1%40example.com')
|
158
|
+
assert_equal '1', @filters.url_decode(1)
|
159
|
+
assert_equal '2001-02-03', @filters.url_decode(Date.new(2001, 2, 3))
|
160
|
+
assert_nil @filters.url_decode(nil)
|
161
|
+
exception = assert_raises Liquid::ArgumentError do
|
162
|
+
@filters.url_decode('%ff')
|
163
|
+
end
|
164
|
+
assert_equal 'Liquid error: invalid byte sequence in UTF-8', exception.message
|
124
165
|
end
|
125
166
|
|
126
167
|
def test_truncatewords
|
@@ -129,6 +170,7 @@ class StandardFiltersTest < Minitest::Test
|
|
129
170
|
assert_equal 'one two three', @filters.truncatewords('one two three')
|
130
171
|
assert_equal 'Two small (13” x 5.5” x 10” high) baskets fit inside one large basket (13”...', @filters.truncatewords('Two small (13” x 5.5” x 10” high) baskets fit inside one large basket (13” x 16” x 10.5” high) with cover.', 15)
|
131
172
|
assert_equal "测试测试测试测试", @filters.truncatewords('测试测试测试测试', 5)
|
173
|
+
assert_equal 'one two1', @filters.truncatewords("one two three", 2, 1)
|
132
174
|
end
|
133
175
|
|
134
176
|
def test_strip_html
|
@@ -139,48 +181,191 @@ class StandardFiltersTest < Minitest::Test
|
|
139
181
|
assert_equal 'test', @filters.strip_html("<div\nclass='multiline'>test</div>")
|
140
182
|
assert_equal 'test', @filters.strip_html("<!-- foo bar \n test -->test")
|
141
183
|
assert_equal '', @filters.strip_html(nil)
|
184
|
+
|
185
|
+
# Quirk of the existing implementation
|
186
|
+
assert_equal 'foo;', @filters.strip_html("<<<script </script>script>foo;</script>")
|
142
187
|
end
|
143
188
|
|
144
189
|
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], ' - ')
|
190
|
+
assert_equal '1 2 3 4', @filters.join([1, 2, 3, 4])
|
191
|
+
assert_equal '1 - 2 - 3 - 4', @filters.join([1, 2, 3, 4], ' - ')
|
192
|
+
assert_equal '1121314', @filters.join([1, 2, 3, 4], 1)
|
147
193
|
end
|
148
194
|
|
149
195
|
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")
|
196
|
+
assert_equal [1, 2, 3, 4], @filters.sort([4, 3, 2, 1])
|
197
|
+
assert_equal [{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], @filters.sort([{ "a" => 4 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a")
|
198
|
+
end
|
199
|
+
|
200
|
+
def test_sort_with_nils
|
201
|
+
assert_equal [1, 2, 3, 4, nil], @filters.sort([nil, 4, 3, 2, 1])
|
202
|
+
assert_equal [{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }, {}], @filters.sort([{ "a" => 4 }, { "a" => 3 }, {}, { "a" => 1 }, { "a" => 2 }], "a")
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_sort_when_property_is_sometimes_missing_puts_nils_last
|
206
|
+
input = [
|
207
|
+
{ "price" => 4, "handle" => "alpha" },
|
208
|
+
{ "handle" => "beta" },
|
209
|
+
{ "price" => 1, "handle" => "gamma" },
|
210
|
+
{ "handle" => "delta" },
|
211
|
+
{ "price" => 2, "handle" => "epsilon" }
|
212
|
+
]
|
213
|
+
expectation = [
|
214
|
+
{ "price" => 1, "handle" => "gamma" },
|
215
|
+
{ "price" => 2, "handle" => "epsilon" },
|
216
|
+
{ "price" => 4, "handle" => "alpha" },
|
217
|
+
{ "handle" => "delta" },
|
218
|
+
{ "handle" => "beta" }
|
219
|
+
]
|
220
|
+
assert_equal expectation, @filters.sort(input, "price")
|
221
|
+
end
|
222
|
+
|
223
|
+
def test_sort_natural
|
224
|
+
assert_equal ["a", "B", "c", "D"], @filters.sort_natural(["c", "D", "a", "B"])
|
225
|
+
assert_equal [{ "a" => "a" }, { "a" => "B" }, { "a" => "c" }, { "a" => "D" }], @filters.sort_natural([{ "a" => "D" }, { "a" => "c" }, { "a" => "a" }, { "a" => "B" }], "a")
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_sort_natural_with_nils
|
229
|
+
assert_equal ["a", "B", "c", "D", nil], @filters.sort_natural([nil, "c", "D", "a", "B"])
|
230
|
+
assert_equal [{ "a" => "a" }, { "a" => "B" }, { "a" => "c" }, { "a" => "D" }, {}], @filters.sort_natural([{ "a" => "D" }, { "a" => "c" }, {}, { "a" => "a" }, { "a" => "B" }], "a")
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_sort_natural_when_property_is_sometimes_missing_puts_nils_last
|
234
|
+
input = [
|
235
|
+
{ "price" => "4", "handle" => "alpha" },
|
236
|
+
{ "handle" => "beta" },
|
237
|
+
{ "price" => "1", "handle" => "gamma" },
|
238
|
+
{ "handle" => "delta" },
|
239
|
+
{ "price" => 2, "handle" => "epsilon" }
|
240
|
+
]
|
241
|
+
expectation = [
|
242
|
+
{ "price" => "1", "handle" => "gamma" },
|
243
|
+
{ "price" => 2, "handle" => "epsilon" },
|
244
|
+
{ "price" => "4", "handle" => "alpha" },
|
245
|
+
{ "handle" => "delta" },
|
246
|
+
{ "handle" => "beta" }
|
247
|
+
]
|
248
|
+
assert_equal expectation, @filters.sort_natural(input, "price")
|
249
|
+
end
|
250
|
+
|
251
|
+
def test_sort_natural_case_check
|
252
|
+
input = [
|
253
|
+
{ "key" => "X" },
|
254
|
+
{ "key" => "Y" },
|
255
|
+
{ "key" => "Z" },
|
256
|
+
{ "fake" => "t" },
|
257
|
+
{ "key" => "a" },
|
258
|
+
{ "key" => "b" },
|
259
|
+
{ "key" => "c" }
|
260
|
+
]
|
261
|
+
expectation = [
|
262
|
+
{ "key" => "a" },
|
263
|
+
{ "key" => "b" },
|
264
|
+
{ "key" => "c" },
|
265
|
+
{ "key" => "X" },
|
266
|
+
{ "key" => "Y" },
|
267
|
+
{ "key" => "Z" },
|
268
|
+
{ "fake" => "t" }
|
269
|
+
]
|
270
|
+
assert_equal expectation, @filters.sort_natural(input, "key")
|
271
|
+
assert_equal ["a", "b", "c", "X", "Y", "Z"], @filters.sort_natural(["X", "Y", "Z", "a", "b", "c"])
|
272
|
+
end
|
273
|
+
|
274
|
+
def test_sort_empty_array
|
275
|
+
assert_equal [], @filters.sort([], "a")
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_sort_invalid_property
|
279
|
+
foo = [
|
280
|
+
[1],
|
281
|
+
[2],
|
282
|
+
[3]
|
283
|
+
]
|
284
|
+
|
285
|
+
assert_raises Liquid::ArgumentError do
|
286
|
+
@filters.sort(foo, "bar")
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def test_sort_natural_empty_array
|
291
|
+
assert_equal [], @filters.sort_natural([], "a")
|
292
|
+
end
|
293
|
+
|
294
|
+
def test_sort_natural_invalid_property
|
295
|
+
foo = [
|
296
|
+
[1],
|
297
|
+
[2],
|
298
|
+
[3]
|
299
|
+
]
|
300
|
+
|
301
|
+
assert_raises Liquid::ArgumentError do
|
302
|
+
@filters.sort_natural(foo, "bar")
|
303
|
+
end
|
152
304
|
end
|
153
305
|
|
154
306
|
def test_legacy_sort_hash
|
155
|
-
assert_equal [{a:1, b:2}], @filters.sort({a:1, b:2})
|
307
|
+
assert_equal [{ a: 1, b: 2 }], @filters.sort({ a: 1, b: 2 })
|
156
308
|
end
|
157
309
|
|
158
310
|
def test_numerical_vs_lexicographical_sort
|
159
311
|
assert_equal [2, 10], @filters.sort([10, 2])
|
160
|
-
assert_equal [{"a" => 2}, {"a" => 10}], @filters.sort([{"a" => 10}, {"a" => 2}], "a")
|
312
|
+
assert_equal [{ "a" => 2 }, { "a" => 10 }], @filters.sort([{ "a" => 10 }, { "a" => 2 }], "a")
|
161
313
|
assert_equal ["10", "2"], @filters.sort(["10", "2"])
|
162
|
-
assert_equal [{"a" => "10"}, {"a" => "2"}], @filters.sort([{"a" => "10"}, {"a" => "2"}], "a")
|
314
|
+
assert_equal [{ "a" => "10" }, { "a" => "2" }], @filters.sort([{ "a" => "10" }, { "a" => "2" }], "a")
|
163
315
|
end
|
164
316
|
|
165
317
|
def test_uniq
|
166
|
-
assert_equal [
|
167
|
-
assert_equal [
|
318
|
+
assert_equal ["foo"], @filters.uniq("foo")
|
319
|
+
assert_equal [1, 3, 2, 4], @filters.uniq([1, 1, 3, 2, 3, 1, 4, 3, 2, 1])
|
320
|
+
assert_equal [{ "a" => 1 }, { "a" => 3 }, { "a" => 2 }], @filters.uniq([{ "a" => 1 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a")
|
168
321
|
testdrop = TestDrop.new
|
169
322
|
assert_equal [testdrop], @filters.uniq([testdrop, TestDrop.new], 'test')
|
170
323
|
end
|
171
324
|
|
325
|
+
def test_uniq_empty_array
|
326
|
+
assert_equal [], @filters.uniq([], "a")
|
327
|
+
end
|
328
|
+
|
329
|
+
def test_uniq_invalid_property
|
330
|
+
foo = [
|
331
|
+
[1],
|
332
|
+
[2],
|
333
|
+
[3]
|
334
|
+
]
|
335
|
+
|
336
|
+
assert_raises Liquid::ArgumentError do
|
337
|
+
@filters.uniq(foo, "bar")
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def test_compact_empty_array
|
342
|
+
assert_equal [], @filters.compact([], "a")
|
343
|
+
end
|
344
|
+
|
345
|
+
def test_compact_invalid_property
|
346
|
+
foo = [
|
347
|
+
[1],
|
348
|
+
[2],
|
349
|
+
[3]
|
350
|
+
]
|
351
|
+
|
352
|
+
assert_raises Liquid::ArgumentError do
|
353
|
+
@filters.compact(foo, "bar")
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
172
357
|
def test_reverse
|
173
|
-
assert_equal [4,3,2,1], @filters.reverse([1,2,3,4])
|
358
|
+
assert_equal [4, 3, 2, 1], @filters.reverse([1, 2, 3, 4])
|
174
359
|
end
|
175
360
|
|
176
361
|
def test_legacy_reverse_hash
|
177
|
-
assert_equal [{a:1, b:2}], @filters.reverse(a:1, b:2)
|
362
|
+
assert_equal [{ a: 1, b: 2 }], @filters.reverse(a: 1, b: 2)
|
178
363
|
end
|
179
364
|
|
180
365
|
def test_map
|
181
|
-
assert_equal [1,2,3,4], @filters.map([{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], 'a')
|
366
|
+
assert_equal [1, 2, 3, 4], @filters.map([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], 'a')
|
182
367
|
assert_template_result 'abc', "{{ ary | map:'foo' | map:'bar' }}",
|
183
|
-
'ary' => [{'foo' => {'bar' => 'a'}}, {'foo' => {'bar' => 'b'}}, {'foo' => {'bar' => 'c'}}]
|
368
|
+
'ary' => [{ 'foo' => { 'bar' => 'a' } }, { 'foo' => { 'bar' => 'b' } }, { 'foo' => { 'bar' => 'c' } }]
|
184
369
|
end
|
185
370
|
|
186
371
|
def test_map_doesnt_call_arbitrary_stuff
|
@@ -212,15 +397,51 @@ class StandardFiltersTest < Minitest::Test
|
|
212
397
|
|
213
398
|
def test_map_over_proc
|
214
399
|
drop = TestDrop.new
|
215
|
-
p =
|
400
|
+
p = proc{ drop }
|
216
401
|
templ = '{{ procs | map: "test" }}'
|
217
402
|
assert_template_result "testfoo", templ, "procs" => [p]
|
218
403
|
end
|
219
404
|
|
405
|
+
def test_map_over_drops_returning_procs
|
406
|
+
drops = [
|
407
|
+
{
|
408
|
+
"proc" => ->{ "foo" },
|
409
|
+
},
|
410
|
+
{
|
411
|
+
"proc" => ->{ "bar" },
|
412
|
+
},
|
413
|
+
]
|
414
|
+
templ = '{{ drops | map: "proc" }}'
|
415
|
+
assert_template_result "foobar", templ, "drops" => drops
|
416
|
+
end
|
417
|
+
|
220
418
|
def test_map_works_on_enumerables
|
221
419
|
assert_template_result "123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new
|
222
420
|
end
|
223
421
|
|
422
|
+
def test_map_returns_empty_on_2d_input_array
|
423
|
+
foo = [
|
424
|
+
[1],
|
425
|
+
[2],
|
426
|
+
[3]
|
427
|
+
]
|
428
|
+
|
429
|
+
assert_raises Liquid::ArgumentError do
|
430
|
+
@filters.map(foo, "bar")
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
def test_map_returns_empty_with_no_property
|
435
|
+
foo = [
|
436
|
+
[1],
|
437
|
+
[2],
|
438
|
+
[3]
|
439
|
+
]
|
440
|
+
assert_raises Liquid::ArgumentError do
|
441
|
+
@filters.map(foo, nil)
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
224
445
|
def test_sort_works_on_enumerables
|
225
446
|
assert_template_result "213", '{{ foo | sort: "bar" | map: "foo" }}', "foo" => TestEnumerable.new
|
226
447
|
end
|
@@ -230,6 +451,10 @@ class StandardFiltersTest < Minitest::Test
|
|
230
451
|
assert_template_result 'foobar', '{{ foo | last }}', 'foo' => [ThingWithToLiquid.new]
|
231
452
|
end
|
232
453
|
|
454
|
+
def test_truncate_calls_to_liquid
|
455
|
+
assert_template_result "wo...", '{{ foo | truncate: 5 }}', "foo" => TestThing.new
|
456
|
+
end
|
457
|
+
|
233
458
|
def test_date
|
234
459
|
assert_equal 'May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B")
|
235
460
|
assert_equal 'June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B")
|
@@ -247,10 +472,13 @@ class StandardFiltersTest < Minitest::Test
|
|
247
472
|
assert_equal '07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y")
|
248
473
|
|
249
474
|
assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y")
|
250
|
-
assert_equal
|
251
|
-
assert_equal
|
475
|
+
assert_equal Date.today.year.to_s, @filters.date('now', '%Y')
|
476
|
+
assert_equal Date.today.year.to_s, @filters.date('today', '%Y')
|
477
|
+
assert_equal Date.today.year.to_s, @filters.date('Today', '%Y')
|
478
|
+
|
479
|
+
assert_nil @filters.date(nil, "%B")
|
252
480
|
|
253
|
-
assert_equal
|
481
|
+
assert_equal '', @filters.date('', "%B")
|
254
482
|
|
255
483
|
with_timezone("UTC") do
|
256
484
|
assert_equal "07/05/2006", @filters.date(1152098955, "%m/%d/%Y")
|
@@ -259,21 +487,25 @@ class StandardFiltersTest < Minitest::Test
|
|
259
487
|
end
|
260
488
|
|
261
489
|
def test_first_last
|
262
|
-
assert_equal 1, @filters.first([1,2,3])
|
263
|
-
assert_equal 3, @filters.last([1,2,3])
|
264
|
-
|
265
|
-
|
490
|
+
assert_equal 1, @filters.first([1, 2, 3])
|
491
|
+
assert_equal 3, @filters.last([1, 2, 3])
|
492
|
+
assert_nil @filters.first([])
|
493
|
+
assert_nil @filters.last([])
|
266
494
|
end
|
267
495
|
|
268
496
|
def test_replace
|
269
497
|
assert_equal '2 2 2 2', @filters.replace('1 1 1 1', '1', 2)
|
498
|
+
assert_equal '2 2 2 2', @filters.replace('1 1 1 1', 1, 2)
|
270
499
|
assert_equal '2 1 1 1', @filters.replace_first('1 1 1 1', '1', 2)
|
500
|
+
assert_equal '2 1 1 1', @filters.replace_first('1 1 1 1', 1, 2)
|
271
501
|
assert_template_result '2 1 1 1', "{{ '1 1 1 1' | replace_first: '1', 2 }}"
|
272
502
|
end
|
273
503
|
|
274
504
|
def test_remove
|
275
505
|
assert_equal ' ', @filters.remove("a a a a", 'a')
|
506
|
+
assert_equal ' ', @filters.remove("1 1 1 1", 1)
|
276
507
|
assert_equal 'a a a', @filters.remove_first("a a a a", 'a ')
|
508
|
+
assert_equal ' 1 1 1', @filters.remove_first("1 1 1 1", 1)
|
277
509
|
assert_template_result 'a a a', "{{ 'a a a a' | remove_first: 'a ' }}"
|
278
510
|
end
|
279
511
|
|
@@ -308,20 +540,38 @@ class StandardFiltersTest < Minitest::Test
|
|
308
540
|
def test_plus
|
309
541
|
assert_template_result "2", "{{ 1 | plus:1 }}"
|
310
542
|
assert_template_result "2.0", "{{ '1' | plus:'1.0' }}"
|
543
|
+
|
544
|
+
assert_template_result "5", "{{ price | plus:'2' }}", 'price' => NumberLikeThing.new(3)
|
311
545
|
end
|
312
546
|
|
313
547
|
def test_minus
|
314
548
|
assert_template_result "4", "{{ input | minus:operand }}", 'input' => 5, 'operand' => 1
|
315
549
|
assert_template_result "2.3", "{{ '4.3' | minus:'2' }}"
|
550
|
+
|
551
|
+
assert_template_result "5", "{{ price | minus:'2' }}", 'price' => NumberLikeThing.new(7)
|
552
|
+
end
|
553
|
+
|
554
|
+
def test_abs
|
555
|
+
assert_template_result "17", "{{ 17 | abs }}"
|
556
|
+
assert_template_result "17", "{{ -17 | abs }}"
|
557
|
+
assert_template_result "17", "{{ '17' | abs }}"
|
558
|
+
assert_template_result "17", "{{ '-17' | abs }}"
|
559
|
+
assert_template_result "0", "{{ 0 | abs }}"
|
560
|
+
assert_template_result "0", "{{ '0' | abs }}"
|
561
|
+
assert_template_result "17.42", "{{ 17.42 | abs }}"
|
562
|
+
assert_template_result "17.42", "{{ -17.42 | abs }}"
|
563
|
+
assert_template_result "17.42", "{{ '17.42' | abs }}"
|
564
|
+
assert_template_result "17.42", "{{ '-17.42' | abs }}"
|
316
565
|
end
|
317
566
|
|
318
567
|
def test_times
|
319
568
|
assert_template_result "12", "{{ 3 | times:4 }}"
|
320
569
|
assert_template_result "0", "{{ 'foo' | times:4 }}"
|
321
|
-
|
322
570
|
assert_template_result "6", "{{ '2.1' | times:3 | replace: '.','-' | plus:0}}"
|
323
|
-
|
324
571
|
assert_template_result "7.25", "{{ 0.0725 | times:100 }}"
|
572
|
+
assert_template_result "-7.25", '{{ "-0.0725" | times:100 }}'
|
573
|
+
assert_template_result "7.25", '{{ "-0.0725" | times: -100 }}'
|
574
|
+
assert_template_result "4", "{{ price | times:2 }}", 'price' => NumberLikeThing.new(2)
|
325
575
|
end
|
326
576
|
|
327
577
|
def test_divided_by
|
@@ -332,38 +582,96 @@ class StandardFiltersTest < Minitest::Test
|
|
332
582
|
assert_equal "Liquid error: divided by 0", Template.parse("{{ 5 | divided_by:0 }}").render
|
333
583
|
|
334
584
|
assert_template_result "0.5", "{{ 2.0 | divided_by:4 }}"
|
585
|
+
assert_raises(Liquid::ZeroDivisionError) do
|
586
|
+
assert_template_result "4", "{{ 1 | modulo: 0 }}"
|
587
|
+
end
|
588
|
+
|
589
|
+
assert_template_result "5", "{{ price | divided_by:2 }}", 'price' => NumberLikeThing.new(10)
|
335
590
|
end
|
336
591
|
|
337
592
|
def test_modulo
|
338
593
|
assert_template_result "1", "{{ 3 | modulo:2 }}"
|
594
|
+
assert_raises(Liquid::ZeroDivisionError) do
|
595
|
+
assert_template_result "4", "{{ 1 | modulo: 0 }}"
|
596
|
+
end
|
597
|
+
|
598
|
+
assert_template_result "1", "{{ price | modulo:2 }}", 'price' => NumberLikeThing.new(3)
|
339
599
|
end
|
340
600
|
|
341
601
|
def test_round
|
342
602
|
assert_template_result "5", "{{ input | round }}", 'input' => 4.6
|
343
603
|
assert_template_result "4", "{{ '4.3' | round }}"
|
344
604
|
assert_template_result "4.56", "{{ input | round: 2 }}", 'input' => 4.5612
|
605
|
+
assert_raises(Liquid::FloatDomainError) do
|
606
|
+
assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | round }}"
|
607
|
+
end
|
608
|
+
|
609
|
+
assert_template_result "5", "{{ price | round }}", 'price' => NumberLikeThing.new(4.6)
|
610
|
+
assert_template_result "4", "{{ price | round }}", 'price' => NumberLikeThing.new(4.3)
|
345
611
|
end
|
346
612
|
|
347
613
|
def test_ceil
|
348
614
|
assert_template_result "5", "{{ input | ceil }}", 'input' => 4.6
|
349
615
|
assert_template_result "5", "{{ '4.3' | ceil }}"
|
616
|
+
assert_raises(Liquid::FloatDomainError) do
|
617
|
+
assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | ceil }}"
|
618
|
+
end
|
619
|
+
|
620
|
+
assert_template_result "5", "{{ price | ceil }}", 'price' => NumberLikeThing.new(4.6)
|
350
621
|
end
|
351
622
|
|
352
623
|
def test_floor
|
353
624
|
assert_template_result "4", "{{ input | floor }}", 'input' => 4.6
|
354
625
|
assert_template_result "4", "{{ '4.3' | floor }}"
|
626
|
+
assert_raises(Liquid::FloatDomainError) do
|
627
|
+
assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | floor }}"
|
628
|
+
end
|
629
|
+
|
630
|
+
assert_template_result "5", "{{ price | floor }}", 'price' => NumberLikeThing.new(5.4)
|
631
|
+
end
|
632
|
+
|
633
|
+
def test_at_most
|
634
|
+
assert_template_result "4", "{{ 5 | at_most:4 }}"
|
635
|
+
assert_template_result "5", "{{ 5 | at_most:5 }}"
|
636
|
+
assert_template_result "5", "{{ 5 | at_most:6 }}"
|
637
|
+
|
638
|
+
assert_template_result "4.5", "{{ 4.5 | at_most:5 }}"
|
639
|
+
assert_template_result "5", "{{ width | at_most:5 }}", 'width' => NumberLikeThing.new(6)
|
640
|
+
assert_template_result "4", "{{ width | at_most:5 }}", 'width' => NumberLikeThing.new(4)
|
641
|
+
assert_template_result "4", "{{ 5 | at_most: width }}", 'width' => NumberLikeThing.new(4)
|
642
|
+
end
|
643
|
+
|
644
|
+
def test_at_least
|
645
|
+
assert_template_result "5", "{{ 5 | at_least:4 }}"
|
646
|
+
assert_template_result "5", "{{ 5 | at_least:5 }}"
|
647
|
+
assert_template_result "6", "{{ 5 | at_least:6 }}"
|
648
|
+
|
649
|
+
assert_template_result "5", "{{ 4.5 | at_least:5 }}"
|
650
|
+
assert_template_result "6", "{{ width | at_least:5 }}", 'width' => NumberLikeThing.new(6)
|
651
|
+
assert_template_result "5", "{{ width | at_least:5 }}", 'width' => NumberLikeThing.new(4)
|
652
|
+
assert_template_result "6", "{{ 5 | at_least: width }}", 'width' => NumberLikeThing.new(6)
|
355
653
|
end
|
356
654
|
|
357
655
|
def test_append
|
358
|
-
assigns = {'a' => 'bc', 'b' => 'd' }
|
359
|
-
assert_template_result('bcd',"{{ a | append: 'd'}}",assigns)
|
360
|
-
assert_template_result('bcd',"{{ a | append: b}}",assigns)
|
656
|
+
assigns = { 'a' => 'bc', 'b' => 'd' }
|
657
|
+
assert_template_result('bcd', "{{ a | append: 'd'}}", assigns)
|
658
|
+
assert_template_result('bcd', "{{ a | append: b}}", assigns)
|
659
|
+
end
|
660
|
+
|
661
|
+
def test_concat
|
662
|
+
assert_equal [1, 2, 3, 4], @filters.concat([1, 2], [3, 4])
|
663
|
+
assert_equal [1, 2, 'a'], @filters.concat([1, 2], ['a'])
|
664
|
+
assert_equal [1, 2, 10], @filters.concat([1, 2], [10])
|
665
|
+
|
666
|
+
assert_raises(Liquid::ArgumentError, "concat filter requires an array argument") do
|
667
|
+
@filters.concat([1, 2], 10)
|
668
|
+
end
|
361
669
|
end
|
362
670
|
|
363
671
|
def test_prepend
|
364
|
-
assigns = {'a' => 'bc', 'b' => 'a' }
|
365
|
-
assert_template_result('abc',"{{ a | prepend: 'a'}}",assigns)
|
366
|
-
assert_template_result('abc',"{{ a | prepend: b}}",assigns)
|
672
|
+
assigns = { 'a' => 'bc', 'b' => 'a' }
|
673
|
+
assert_template_result('abc', "{{ a | prepend: 'a'}}", assigns)
|
674
|
+
assert_template_result('abc', "{{ a | prepend: b}}", assigns)
|
367
675
|
end
|
368
676
|
|
369
677
|
def test_default
|
@@ -376,7 +684,7 @@ class StandardFiltersTest < Minitest::Test
|
|
376
684
|
end
|
377
685
|
|
378
686
|
def test_cannot_access_private_methods
|
379
|
-
assert_template_result('a',"{{ 'a' | to_number }}")
|
687
|
+
assert_template_result('a', "{{ 'a' | to_number }}")
|
380
688
|
end
|
381
689
|
|
382
690
|
def test_date_raises_nothing
|
@@ -384,6 +692,78 @@ class StandardFiltersTest < Minitest::Test
|
|
384
692
|
assert_template_result('abc', "{{ 'abc' | date: '%D' }}")
|
385
693
|
end
|
386
694
|
|
695
|
+
def test_where
|
696
|
+
input = [
|
697
|
+
{ "handle" => "alpha", "ok" => true },
|
698
|
+
{ "handle" => "beta", "ok" => false },
|
699
|
+
{ "handle" => "gamma", "ok" => false },
|
700
|
+
{ "handle" => "delta", "ok" => true }
|
701
|
+
]
|
702
|
+
|
703
|
+
expectation = [
|
704
|
+
{ "handle" => "alpha", "ok" => true },
|
705
|
+
{ "handle" => "delta", "ok" => true }
|
706
|
+
]
|
707
|
+
|
708
|
+
assert_equal expectation, @filters.where(input, "ok", true)
|
709
|
+
assert_equal expectation, @filters.where(input, "ok")
|
710
|
+
end
|
711
|
+
|
712
|
+
def test_where_no_key_set
|
713
|
+
input = [
|
714
|
+
{ "handle" => "alpha", "ok" => true },
|
715
|
+
{ "handle" => "beta" },
|
716
|
+
{ "handle" => "gamma" },
|
717
|
+
{ "handle" => "delta", "ok" => true }
|
718
|
+
]
|
719
|
+
|
720
|
+
expectation = [
|
721
|
+
{ "handle" => "alpha", "ok" => true },
|
722
|
+
{ "handle" => "delta", "ok" => true }
|
723
|
+
]
|
724
|
+
|
725
|
+
assert_equal expectation, @filters.where(input, "ok", true)
|
726
|
+
assert_equal expectation, @filters.where(input, "ok")
|
727
|
+
end
|
728
|
+
|
729
|
+
def test_where_non_array_map_input
|
730
|
+
assert_equal [{ "a" => "ok" }], @filters.where({ "a" => "ok" }, "a", "ok")
|
731
|
+
assert_equal [], @filters.where({ "a" => "not ok" }, "a", "ok")
|
732
|
+
end
|
733
|
+
|
734
|
+
def test_where_indexable_but_non_map_value
|
735
|
+
assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok", true) }
|
736
|
+
assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok") }
|
737
|
+
end
|
738
|
+
|
739
|
+
def test_where_non_boolean_value
|
740
|
+
input = [
|
741
|
+
{ "message" => "Bonjour!", "language" => "French" },
|
742
|
+
{ "message" => "Hello!", "language" => "English" },
|
743
|
+
{ "message" => "Hallo!", "language" => "German" }
|
744
|
+
]
|
745
|
+
|
746
|
+
assert_equal [{ "message" => "Bonjour!", "language" => "French" }], @filters.where(input, "language", "French")
|
747
|
+
assert_equal [{ "message" => "Hallo!", "language" => "German" }], @filters.where(input, "language", "German")
|
748
|
+
assert_equal [{ "message" => "Hello!", "language" => "English" }], @filters.where(input, "language", "English")
|
749
|
+
end
|
750
|
+
|
751
|
+
def test_where_array_of_only_unindexable_values
|
752
|
+
assert_nil @filters.where([nil], "ok", true)
|
753
|
+
assert_nil @filters.where([nil], "ok")
|
754
|
+
end
|
755
|
+
|
756
|
+
def test_where_no_target_value
|
757
|
+
input = [
|
758
|
+
{ "foo" => false },
|
759
|
+
{ "foo" => true },
|
760
|
+
{ "foo" => "for sure" },
|
761
|
+
{ "bar" => true }
|
762
|
+
]
|
763
|
+
|
764
|
+
assert_equal [{ "foo" => true }, { "foo" => "for sure" }], @filters.where(input, "foo")
|
765
|
+
end
|
766
|
+
|
387
767
|
private
|
388
768
|
|
389
769
|
def with_timezone(tz)
|