liquid 2.6.0 → 3.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.
- checksums.yaml +5 -13
- data/History.md +51 -4
- data/README.md +27 -2
- data/lib/liquid/block.rb +85 -51
- data/lib/liquid/block_body.rb +123 -0
- data/lib/liquid/condition.rb +26 -15
- data/lib/liquid/context.rb +106 -140
- data/lib/liquid/document.rb +3 -3
- data/lib/liquid/drop.rb +17 -1
- data/lib/liquid/errors.rb +50 -2
- data/lib/liquid/expression.rb +33 -0
- data/lib/liquid/file_system.rb +17 -6
- data/lib/liquid/i18n.rb +39 -0
- data/lib/liquid/interrupts.rb +1 -1
- data/lib/liquid/lexer.rb +51 -0
- data/lib/liquid/locales/en.yml +22 -0
- data/lib/liquid/parser.rb +90 -0
- data/lib/liquid/parser_switching.rb +31 -0
- data/lib/liquid/profiler/hooks.rb +23 -0
- data/lib/liquid/profiler.rb +159 -0
- data/lib/liquid/range_lookup.rb +22 -0
- data/lib/liquid/standardfilters.rb +143 -55
- data/lib/liquid/strainer.rb +14 -4
- data/lib/liquid/tag.rb +25 -9
- data/lib/liquid/tags/assign.rb +12 -9
- data/lib/liquid/tags/break.rb +1 -1
- data/lib/liquid/tags/capture.rb +10 -8
- data/lib/liquid/tags/case.rb +13 -13
- data/lib/liquid/tags/comment.rb +9 -2
- data/lib/liquid/tags/continue.rb +1 -4
- data/lib/liquid/tags/cycle.rb +5 -7
- data/lib/liquid/tags/decrement.rb +3 -4
- data/lib/liquid/tags/for.rb +69 -36
- data/lib/liquid/tags/if.rb +51 -24
- data/lib/liquid/tags/ifchanged.rb +3 -3
- data/lib/liquid/tags/include.rb +19 -8
- data/lib/liquid/tags/increment.rb +4 -8
- data/lib/liquid/tags/raw.rb +4 -7
- data/lib/liquid/tags/table_row.rb +73 -0
- data/lib/liquid/tags/unless.rb +2 -4
- data/lib/liquid/template.rb +124 -14
- data/lib/liquid/token.rb +18 -0
- data/lib/liquid/utils.rb +13 -4
- data/lib/liquid/variable.rb +103 -25
- data/lib/liquid/variable_lookup.rb +78 -0
- data/lib/liquid/version.rb +1 -1
- data/lib/liquid.rb +19 -11
- data/test/fixtures/en_locale.yml +9 -0
- data/test/{liquid → integration}/assign_test.rb +18 -1
- data/test/integration/blank_test.rb +106 -0
- data/test/{liquid → integration}/capture_test.rb +3 -3
- data/test/integration/context_test.rb +32 -0
- data/test/integration/drop_test.rb +271 -0
- data/test/integration/error_handling_test.rb +207 -0
- data/test/{liquid → integration}/filter_test.rb +11 -11
- data/test/integration/hash_ordering_test.rb +23 -0
- data/test/{liquid → integration}/output_test.rb +13 -13
- data/test/integration/parsing_quirks_test.rb +116 -0
- data/test/integration/render_profiling_test.rb +154 -0
- data/test/{liquid → integration}/security_test.rb +10 -10
- data/test/{liquid → integration}/standard_filter_test.rb +146 -18
- data/test/{liquid → integration}/tags/break_tag_test.rb +1 -1
- data/test/{liquid → integration}/tags/continue_tag_test.rb +1 -1
- data/test/{liquid → integration}/tags/for_tag_test.rb +80 -2
- data/test/{liquid → integration}/tags/if_else_tag_test.rb +29 -20
- data/test/integration/tags/include_tag_test.rb +234 -0
- data/test/{liquid → integration}/tags/increment_tag_test.rb +1 -1
- data/test/{liquid → integration}/tags/raw_tag_test.rb +2 -1
- data/test/{liquid → integration}/tags/standard_tag_test.rb +28 -26
- data/test/integration/tags/statements_test.rb +113 -0
- data/test/{liquid/tags/html_tag_test.rb → integration/tags/table_row_test.rb} +5 -5
- data/test/{liquid → integration}/tags/unless_else_tag_test.rb +1 -1
- data/test/{liquid → integration}/template_test.rb +81 -45
- data/test/integration/variable_test.rb +82 -0
- data/test/test_helper.rb +73 -20
- data/test/{liquid/block_test.rb → unit/block_unit_test.rb} +2 -5
- data/test/{liquid/condition_test.rb → unit/condition_unit_test.rb} +23 -1
- data/test/{liquid/context_test.rb → unit/context_unit_test.rb} +39 -25
- data/test/{liquid/file_system_test.rb → unit/file_system_unit_test.rb} +11 -5
- data/test/unit/i18n_unit_test.rb +37 -0
- data/test/unit/lexer_unit_test.rb +48 -0
- data/test/{liquid/module_ex_test.rb → unit/module_ex_unit_test.rb} +7 -7
- data/test/unit/parser_unit_test.rb +82 -0
- data/test/{liquid/regexp_test.rb → unit/regexp_unit_test.rb} +3 -3
- data/test/{liquid/strainer_test.rb → unit/strainer_unit_test.rb} +20 -1
- data/test/unit/tag_unit_test.rb +16 -0
- data/test/unit/tags/case_tag_unit_test.rb +10 -0
- data/test/unit/tags/for_tag_unit_test.rb +13 -0
- data/test/unit/tags/if_tag_unit_test.rb +8 -0
- data/test/unit/template_unit_test.rb +69 -0
- data/test/unit/tokenizer_unit_test.rb +38 -0
- data/test/unit/variable_unit_test.rb +139 -0
- metadata +141 -74
- data/lib/extras/liquid_view.rb +0 -51
- data/lib/liquid/htmltags.rb +0 -74
- data/test/liquid/drop_test.rb +0 -180
- data/test/liquid/error_handling_test.rb +0 -81
- data/test/liquid/hash_ordering_test.rb +0 -25
- data/test/liquid/parsing_quirks_test.rb +0 -52
- data/test/liquid/tags/include_tag_test.rb +0 -166
- data/test/liquid/tags/statements_test.rb +0 -134
- data/test/liquid/variable_test.rb +0 -186
|
@@ -6,21 +6,21 @@ module SecurityFilter
|
|
|
6
6
|
end
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
class SecurityTest < Test
|
|
9
|
+
class SecurityTest < Minitest::Test
|
|
10
10
|
include Liquid
|
|
11
11
|
|
|
12
12
|
def test_no_instance_eval
|
|
13
13
|
text = %( {{ '1+1' | instance_eval }} )
|
|
14
14
|
expected = %| 1+1 |
|
|
15
15
|
|
|
16
|
-
assert_equal expected, Template.parse(text).render(@assigns)
|
|
16
|
+
assert_equal expected, Template.parse(text).render!(@assigns)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def test_no_existing_instance_eval
|
|
20
20
|
text = %( {{ '1+1' | __instance_eval__ }} )
|
|
21
21
|
expected = %| 1+1 |
|
|
22
22
|
|
|
23
|
-
assert_equal expected, Template.parse(text).render(@assigns)
|
|
23
|
+
assert_equal expected, Template.parse(text).render!(@assigns)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
|
|
@@ -28,7 +28,7 @@ class SecurityTest < Test::Unit::TestCase
|
|
|
28
28
|
text = %( {{ '1+1' | instance_eval }} )
|
|
29
29
|
expected = %| 1+1 |
|
|
30
30
|
|
|
31
|
-
assert_equal expected, Template.parse(text).render(@assigns)
|
|
31
|
+
assert_equal expected, Template.parse(text).render!(@assigns)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
|
|
@@ -36,7 +36,7 @@ class SecurityTest < Test::Unit::TestCase
|
|
|
36
36
|
text = %( {{ '1+1' | add_one | instance_eval }} )
|
|
37
37
|
expected = %| 1+1 + 1 |
|
|
38
38
|
|
|
39
|
-
assert_equal expected, Template.parse(text).render(@assigns, :filters => SecurityFilter)
|
|
39
|
+
assert_equal expected, Template.parse(text).render!(@assigns, :filters => SecurityFilter)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def test_does_not_add_filters_to_symbol_table
|
|
@@ -47,17 +47,17 @@ class SecurityTest < Test::Unit::TestCase
|
|
|
47
47
|
template = Template.parse(test)
|
|
48
48
|
assert_equal [], (Symbol.all_symbols - current_symbols)
|
|
49
49
|
|
|
50
|
-
template.render
|
|
50
|
+
template.render!
|
|
51
51
|
assert_equal [], (Symbol.all_symbols - current_symbols)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def test_does_not_add_drop_methods_to_symbol_table
|
|
55
55
|
current_symbols = Symbol.all_symbols
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
assigns = { 'drop' => Drop.new }
|
|
58
|
+
assert_equal "", Template.parse("{{ drop.custom_method_1 }}", assigns).render!
|
|
59
|
+
assert_equal "", Template.parse("{{ drop.custom_method_2 }}", assigns).render!
|
|
60
|
+
assert_equal "", Template.parse("{{ drop.custom_method_3 }}", assigns).render!
|
|
61
61
|
|
|
62
62
|
assert_equal [], (Symbol.all_symbols - current_symbols)
|
|
63
63
|
end
|
|
@@ -7,6 +7,8 @@ class Filters
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
class TestThing
|
|
10
|
+
attr_reader :foo
|
|
11
|
+
|
|
10
12
|
def initialize
|
|
11
13
|
@foo = 0
|
|
12
14
|
end
|
|
@@ -15,6 +17,10 @@ class TestThing
|
|
|
15
17
|
"woot: #{@foo}"
|
|
16
18
|
end
|
|
17
19
|
|
|
20
|
+
def [](whatever)
|
|
21
|
+
to_s
|
|
22
|
+
end
|
|
23
|
+
|
|
18
24
|
def to_liquid
|
|
19
25
|
@foo += 1
|
|
20
26
|
self
|
|
@@ -27,7 +33,15 @@ class TestDrop < Liquid::Drop
|
|
|
27
33
|
end
|
|
28
34
|
end
|
|
29
35
|
|
|
30
|
-
class
|
|
36
|
+
class TestEnumerable < Liquid::Drop
|
|
37
|
+
include Enumerable
|
|
38
|
+
|
|
39
|
+
def each(&block)
|
|
40
|
+
[ { "foo" => 1, "bar" => 2 }, { "foo" => 2, "bar" => 1 }, { "foo" => 3, "bar" => 3 } ].each(&block)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class StandardFiltersTest < Minitest::Test
|
|
31
45
|
include Liquid
|
|
32
46
|
|
|
33
47
|
def setup
|
|
@@ -50,9 +64,32 @@ class StandardFiltersTest < Test::Unit::TestCase
|
|
|
50
64
|
assert_equal '', @filters.upcase(nil)
|
|
51
65
|
end
|
|
52
66
|
|
|
53
|
-
def
|
|
54
|
-
assert_equal '
|
|
55
|
-
assert_equal '', @filters.
|
|
67
|
+
def test_slice
|
|
68
|
+
assert_equal 'oob', @filters.slice('foobar', 1, 3)
|
|
69
|
+
assert_equal 'oobar', @filters.slice('foobar', 1, 1000)
|
|
70
|
+
assert_equal '', @filters.slice('foobar', 1, 0)
|
|
71
|
+
assert_equal 'o', @filters.slice('foobar', 1, 1)
|
|
72
|
+
assert_equal 'bar', @filters.slice('foobar', 3, 3)
|
|
73
|
+
assert_equal 'ar', @filters.slice('foobar', -2, 2)
|
|
74
|
+
assert_equal 'ar', @filters.slice('foobar', -2, 1000)
|
|
75
|
+
assert_equal 'r', @filters.slice('foobar', -1)
|
|
76
|
+
assert_equal '', @filters.slice(nil, 0)
|
|
77
|
+
assert_equal '', @filters.slice('foobar', 100, 10)
|
|
78
|
+
assert_equal '', @filters.slice('foobar', -100, 10)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def test_slice_on_arrays
|
|
82
|
+
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)
|
|
56
93
|
end
|
|
57
94
|
|
|
58
95
|
def test_truncate
|
|
@@ -63,12 +100,13 @@ class StandardFiltersTest < Test::Unit::TestCase
|
|
|
63
100
|
assert_equal "测试...", @filters.truncate("测试测试测试测试", 5)
|
|
64
101
|
end
|
|
65
102
|
|
|
66
|
-
def
|
|
103
|
+
def test_split
|
|
67
104
|
assert_equal ['12','34'], @filters.split('12~34', '~')
|
|
68
105
|
assert_equal ['A? ',' ,Z'], @filters.split('A? ~ ~ ~ ,Z', '~ ~ ~')
|
|
69
106
|
assert_equal ['A?Z'], @filters.split('A?Z', '~')
|
|
70
107
|
# Regexp works although Liquid does not support.
|
|
71
108
|
assert_equal ['A','Z'], @filters.split('AxZ', /x/)
|
|
109
|
+
assert_equal [], @filters.split(nil, ' ')
|
|
72
110
|
end
|
|
73
111
|
|
|
74
112
|
def test_escape
|
|
@@ -77,7 +115,12 @@ class StandardFiltersTest < Test::Unit::TestCase
|
|
|
77
115
|
end
|
|
78
116
|
|
|
79
117
|
def test_escape_once
|
|
80
|
-
assert_equal '<strong>', @filters.escape_once(
|
|
118
|
+
assert_equal '<strong>Hulk</strong>', @filters.escape_once('<strong>Hulk</strong>')
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def test_url_encode
|
|
122
|
+
assert_equal 'foo%2B1%40example.com', @filters.url_encode('foo+1@example.com')
|
|
123
|
+
assert_equal nil, @filters.url_encode(nil)
|
|
81
124
|
end
|
|
82
125
|
|
|
83
126
|
def test_truncatewords
|
|
@@ -108,10 +151,32 @@ class StandardFiltersTest < Test::Unit::TestCase
|
|
|
108
151
|
assert_equal [{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], @filters.sort([{"a" => 4}, {"a" => 3}, {"a" => 1}, {"a" => 2}], "a")
|
|
109
152
|
end
|
|
110
153
|
|
|
154
|
+
def test_legacy_sort_hash
|
|
155
|
+
assert_equal [{a:1, b:2}], @filters.sort({a:1, b:2})
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def test_numerical_vs_lexicographical_sort
|
|
159
|
+
assert_equal [2, 10], @filters.sort([10, 2])
|
|
160
|
+
assert_equal [{"a" => 2}, {"a" => 10}], @filters.sort([{"a" => 10}, {"a" => 2}], "a")
|
|
161
|
+
assert_equal ["10", "2"], @filters.sort(["10", "2"])
|
|
162
|
+
assert_equal [{"a" => "10"}, {"a" => "2"}], @filters.sort([{"a" => "10"}, {"a" => "2"}], "a")
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
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")
|
|
168
|
+
testdrop = TestDrop.new
|
|
169
|
+
assert_equal [testdrop], @filters.uniq([testdrop, TestDrop.new], 'test')
|
|
170
|
+
end
|
|
171
|
+
|
|
111
172
|
def test_reverse
|
|
112
173
|
assert_equal [4,3,2,1], @filters.reverse([1,2,3,4])
|
|
113
174
|
end
|
|
114
175
|
|
|
176
|
+
def test_legacy_reverse_hash
|
|
177
|
+
assert_equal [{a:1, b:2}], @filters.reverse(a:1, b:2)
|
|
178
|
+
end
|
|
179
|
+
|
|
115
180
|
def test_map
|
|
116
181
|
assert_equal [1,2,3,4], @filters.map([{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], 'a')
|
|
117
182
|
assert_template_result 'abc', "{{ ary | map:'foo' | map:'bar' }}",
|
|
@@ -119,20 +184,50 @@ class StandardFiltersTest < Test::Unit::TestCase
|
|
|
119
184
|
end
|
|
120
185
|
|
|
121
186
|
def test_map_doesnt_call_arbitrary_stuff
|
|
122
|
-
|
|
123
|
-
|
|
187
|
+
assert_template_result "", '{{ "foo" | map: "__id__" }}'
|
|
188
|
+
assert_template_result "", '{{ "foo" | map: "inspect" }}'
|
|
124
189
|
end
|
|
125
190
|
|
|
126
191
|
def test_map_calls_to_liquid
|
|
127
192
|
t = TestThing.new
|
|
128
|
-
|
|
193
|
+
assert_template_result "woot: 1", '{{ foo | map: "whatever" }}', "foo" => [t]
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def test_map_on_hashes
|
|
197
|
+
assert_template_result "4217", '{{ thing | map: "foo" | map: "bar" }}',
|
|
198
|
+
"thing" => { "foo" => [ { "bar" => 42 }, { "bar" => 17 } ] }
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def test_legacy_map_on_hashes_with_dynamic_key
|
|
202
|
+
template = "{% assign key = 'foo' %}{{ thing | map: key | map: 'bar' }}"
|
|
203
|
+
hash = { "foo" => { "bar" => 42 } }
|
|
204
|
+
assert_template_result "42", template, "thing" => hash
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def test_sort_calls_to_liquid
|
|
208
|
+
t = TestThing.new
|
|
209
|
+
Liquid::Template.parse('{{ foo | sort: "whatever" }}').render("foo" => [t])
|
|
210
|
+
assert t.foo > 0
|
|
129
211
|
end
|
|
130
212
|
|
|
131
213
|
def test_map_over_proc
|
|
132
214
|
drop = TestDrop.new
|
|
133
215
|
p = Proc.new{ drop }
|
|
134
216
|
templ = '{{ procs | map: "test" }}'
|
|
135
|
-
|
|
217
|
+
assert_template_result "testfoo", templ, "procs" => [p]
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def test_map_works_on_enumerables
|
|
221
|
+
assert_template_result "123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def test_sort_works_on_enumerables
|
|
225
|
+
assert_template_result "213", '{{ foo | sort: "bar" | map: "foo" }}', "foo" => TestEnumerable.new
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def test_first_and_last_call_to_liquid
|
|
229
|
+
assert_template_result 'foobar', '{{ foo | first }}', 'foo' => [ThingWithToLiquid.new]
|
|
230
|
+
assert_template_result 'foobar', '{{ foo | last }}', 'foo' => [ThingWithToLiquid.new]
|
|
136
231
|
end
|
|
137
232
|
|
|
138
233
|
def test_date
|
|
@@ -161,7 +256,6 @@ class StandardFiltersTest < Test::Unit::TestCase
|
|
|
161
256
|
assert_equal "07/05/2006", @filters.date("1152098955", "%m/%d/%Y")
|
|
162
257
|
end
|
|
163
258
|
|
|
164
|
-
|
|
165
259
|
def test_first_last
|
|
166
260
|
assert_equal 1, @filters.first([1,2,3])
|
|
167
261
|
assert_equal 3, @filters.last([1,2,3])
|
|
@@ -185,6 +279,21 @@ class StandardFiltersTest < Test::Unit::TestCase
|
|
|
185
279
|
assert_template_result 'foobar', "{{ 'foo|bar' | remove: '|' }}"
|
|
186
280
|
end
|
|
187
281
|
|
|
282
|
+
def test_strip
|
|
283
|
+
assert_template_result 'ab c', "{{ source | strip }}", 'source' => " ab c "
|
|
284
|
+
assert_template_result 'ab c', "{{ source | strip }}", 'source' => " \tab c \n \t"
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def test_lstrip
|
|
288
|
+
assert_template_result 'ab c ', "{{ source | lstrip }}", 'source' => " ab c "
|
|
289
|
+
assert_template_result "ab c \n \t", "{{ source | lstrip }}", 'source' => " \tab c \n \t"
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def test_rstrip
|
|
293
|
+
assert_template_result " ab c", "{{ source | rstrip }}", 'source' => " ab c "
|
|
294
|
+
assert_template_result " \tab c", "{{ source | rstrip }}", 'source' => " \tab c \n \t"
|
|
295
|
+
end
|
|
296
|
+
|
|
188
297
|
def test_strip_newlines
|
|
189
298
|
assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\nb\nc"
|
|
190
299
|
assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\r\nb\nc"
|
|
@@ -208,9 +317,6 @@ class StandardFiltersTest < Test::Unit::TestCase
|
|
|
208
317
|
assert_template_result "12", "{{ 3 | times:4 }}"
|
|
209
318
|
assert_template_result "0", "{{ 'foo' | times:4 }}"
|
|
210
319
|
|
|
211
|
-
# Ruby v1.9.2-rc1, or higher, backwards compatible Float test
|
|
212
|
-
assert_match(/(6\.3)|(6\.(0{13})1)/, Template.parse("{{ '2.1' | times:3 }}").render)
|
|
213
|
-
|
|
214
320
|
assert_template_result "6", "{{ '2.1' | times:3 | replace: '.','-' | plus:0}}"
|
|
215
321
|
|
|
216
322
|
assert_template_result "7.25", "{{ 0.0725 | times:100 }}"
|
|
@@ -220,11 +326,8 @@ class StandardFiltersTest < Test::Unit::TestCase
|
|
|
220
326
|
assert_template_result "4", "{{ 12 | divided_by:3 }}"
|
|
221
327
|
assert_template_result "4", "{{ 14 | divided_by:3 }}"
|
|
222
328
|
|
|
223
|
-
# Ruby v1.9.2-rc1, or higher, backwards compatible Float test
|
|
224
|
-
assert_match(/4\.(6{13,14})7/, Template.parse("{{ 14 | divided_by:'3.0' }}").render)
|
|
225
|
-
|
|
226
329
|
assert_template_result "5", "{{ 15 | divided_by:3 }}"
|
|
227
|
-
|
|
330
|
+
assert_equal "Liquid error: divided by 0", Template.parse("{{ 5 | divided_by:0 }}").render
|
|
228
331
|
|
|
229
332
|
assert_template_result "0.5", "{{ 2.0 | divided_by:4 }}"
|
|
230
333
|
end
|
|
@@ -233,6 +336,22 @@ class StandardFiltersTest < Test::Unit::TestCase
|
|
|
233
336
|
assert_template_result "1", "{{ 3 | modulo:2 }}"
|
|
234
337
|
end
|
|
235
338
|
|
|
339
|
+
def test_round
|
|
340
|
+
assert_template_result "5", "{{ input | round }}", 'input' => 4.6
|
|
341
|
+
assert_template_result "4", "{{ '4.3' | round }}"
|
|
342
|
+
assert_template_result "4.56", "{{ input | round: 2 }}", 'input' => 4.5612
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def test_ceil
|
|
346
|
+
assert_template_result "5", "{{ input | ceil }}", 'input' => 4.6
|
|
347
|
+
assert_template_result "5", "{{ '4.3' | ceil }}"
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def test_floor
|
|
351
|
+
assert_template_result "4", "{{ input | floor }}", 'input' => 4.6
|
|
352
|
+
assert_template_result "4", "{{ '4.3' | floor }}"
|
|
353
|
+
end
|
|
354
|
+
|
|
236
355
|
def test_append
|
|
237
356
|
assigns = {'a' => 'bc', 'b' => 'd' }
|
|
238
357
|
assert_template_result('bcd',"{{ a | append: 'd'}}",assigns)
|
|
@@ -245,6 +364,15 @@ class StandardFiltersTest < Test::Unit::TestCase
|
|
|
245
364
|
assert_template_result('abc',"{{ a | prepend: b}}",assigns)
|
|
246
365
|
end
|
|
247
366
|
|
|
367
|
+
def test_default
|
|
368
|
+
assert_equal "foo", @filters.default("foo", "bar")
|
|
369
|
+
assert_equal "bar", @filters.default(nil, "bar")
|
|
370
|
+
assert_equal "bar", @filters.default("", "bar")
|
|
371
|
+
assert_equal "bar", @filters.default(false, "bar")
|
|
372
|
+
assert_equal "bar", @filters.default([], "bar")
|
|
373
|
+
assert_equal "bar", @filters.default({}, "bar")
|
|
374
|
+
end
|
|
375
|
+
|
|
248
376
|
def test_cannot_access_private_methods
|
|
249
377
|
assert_template_result('a',"{{ 'a' | to_number }}")
|
|
250
378
|
end
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
require 'test_helper'
|
|
2
2
|
|
|
3
|
-
class
|
|
3
|
+
class ThingWithValue < Liquid::Drop
|
|
4
|
+
def value
|
|
5
|
+
3
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class ForTagTest < Minitest::Test
|
|
4
10
|
include Liquid
|
|
5
11
|
|
|
6
12
|
def test_for
|
|
@@ -34,6 +40,20 @@ HERE
|
|
|
34
40
|
assert_template_result(' 1 2 3 ','{%for item in (1..3) %} {{item}} {%endfor%}')
|
|
35
41
|
end
|
|
36
42
|
|
|
43
|
+
def test_for_with_variable_range
|
|
44
|
+
assert_template_result(' 1 2 3 ','{%for item in (1..foobar) %} {{item}} {%endfor%}', "foobar" => 3)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_for_with_hash_value_range
|
|
48
|
+
foobar = { "value" => 3 }
|
|
49
|
+
assert_template_result(' 1 2 3 ','{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def test_for_with_drop_value_range
|
|
53
|
+
foobar = ThingWithValue.new
|
|
54
|
+
assert_template_result(' 1 2 3 ','{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
|
|
55
|
+
end
|
|
56
|
+
|
|
37
57
|
def test_for_with_variable
|
|
38
58
|
assert_template_result(' 1 2 3 ','{%for item in array%} {{item}} {%endfor%}','array' => [1,2,3])
|
|
39
59
|
assert_template_result('123','{%for item in array%}{{item}}{%endfor%}','array' => [1,2,3])
|
|
@@ -283,7 +303,7 @@ HERE
|
|
|
283
303
|
end
|
|
284
304
|
|
|
285
305
|
def test_bad_variable_naming_in_for_loop
|
|
286
|
-
|
|
306
|
+
assert_raises(Liquid::SyntaxError) do
|
|
287
307
|
Liquid::Template.parse('{% for a/b in x %}{% endfor %}')
|
|
288
308
|
end
|
|
289
309
|
end
|
|
@@ -294,4 +314,62 @@ HERE
|
|
|
294
314
|
assigns = {'items' => [1,2,3,4,5]}
|
|
295
315
|
assert_template_result(expected, template, assigns)
|
|
296
316
|
end
|
|
317
|
+
|
|
318
|
+
class LoaderDrop < Liquid::Drop
|
|
319
|
+
attr_accessor :each_called, :load_slice_called
|
|
320
|
+
|
|
321
|
+
def initialize(data)
|
|
322
|
+
@data = data
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def each
|
|
326
|
+
@each_called = true
|
|
327
|
+
@data.each { |el| yield el }
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def load_slice(from, to)
|
|
331
|
+
@load_slice_called = true
|
|
332
|
+
@data[(from..to-1)]
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def test_iterate_with_each_when_no_limit_applied
|
|
337
|
+
loader = LoaderDrop.new([1,2,3,4,5])
|
|
338
|
+
assigns = {'items' => loader}
|
|
339
|
+
expected = '12345'
|
|
340
|
+
template = '{% for item in items %}{{item}}{% endfor %}'
|
|
341
|
+
assert_template_result(expected, template, assigns)
|
|
342
|
+
assert loader.each_called
|
|
343
|
+
assert !loader.load_slice_called
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def test_iterate_with_load_slice_when_limit_applied
|
|
347
|
+
loader = LoaderDrop.new([1,2,3,4,5])
|
|
348
|
+
assigns = {'items' => loader}
|
|
349
|
+
expected = '1'
|
|
350
|
+
template = '{% for item in items limit:1 %}{{item}}{% endfor %}'
|
|
351
|
+
assert_template_result(expected, template, assigns)
|
|
352
|
+
assert !loader.each_called
|
|
353
|
+
assert loader.load_slice_called
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def test_iterate_with_load_slice_when_limit_and_offset_applied
|
|
357
|
+
loader = LoaderDrop.new([1,2,3,4,5])
|
|
358
|
+
assigns = {'items' => loader}
|
|
359
|
+
expected = '34'
|
|
360
|
+
template = '{% for item in items offset:2 limit:2 %}{{item}}{% endfor %}'
|
|
361
|
+
assert_template_result(expected, template, assigns)
|
|
362
|
+
assert !loader.each_called
|
|
363
|
+
assert loader.load_slice_called
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def test_iterate_with_load_slice_returns_same_results_as_without
|
|
367
|
+
loader = LoaderDrop.new([1,2,3,4,5])
|
|
368
|
+
loader_assigns = {'items' => loader}
|
|
369
|
+
array_assigns = {'items' => [1,2,3,4,5]}
|
|
370
|
+
expected = '34'
|
|
371
|
+
template = '{% for item in items offset:2 limit:2 %}{{item}}{% endfor %}'
|
|
372
|
+
assert_template_result(expected, template, loader_assigns)
|
|
373
|
+
assert_template_result(expected, template, array_assigns)
|
|
374
|
+
end
|
|
297
375
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require 'test_helper'
|
|
2
2
|
|
|
3
|
-
class IfElseTagTest < Test
|
|
3
|
+
class IfElseTagTest < Minitest::Test
|
|
4
4
|
include Liquid
|
|
5
5
|
|
|
6
6
|
def test_if
|
|
@@ -10,6 +10,11 @@ class IfElseTagTest < Test::Unit::TestCase
|
|
|
10
10
|
assert_template_result(' you rock ?','{% if false %} you suck {% endif %} {% if true %} you rock {% endif %}?')
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
def test_literal_comparisons
|
|
14
|
+
assert_template_result(' NO ','{% assign v = false %}{% if v %} YES {% else %} NO {% endif %}')
|
|
15
|
+
assert_template_result(' YES ','{% assign v = nil %}{% if v == nil %} YES {% else %} NO {% endif %}')
|
|
16
|
+
end
|
|
17
|
+
|
|
13
18
|
def test_if_else
|
|
14
19
|
assert_template_result(' YES ','{% if false %} NO {% else %} YES {% endif %}')
|
|
15
20
|
assert_template_result(' YES ','{% if true %} YES {% else %} NO {% endif %}')
|
|
@@ -37,25 +42,19 @@ class IfElseTagTest < Test::Unit::TestCase
|
|
|
37
42
|
end
|
|
38
43
|
|
|
39
44
|
def test_comparison_of_strings_containing_and_or_or
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
assert_template_result(' YES ',"{% if #{awful_markup} %} YES {% endif %}", assigns)
|
|
44
|
-
end
|
|
45
|
+
awful_markup = "a == 'and' and b == 'or' and c == 'foo and bar' and d == 'bar or baz' and e == 'foo' and foo and bar"
|
|
46
|
+
assigns = {'a' => 'and', 'b' => 'or', 'c' => 'foo and bar', 'd' => 'bar or baz', 'e' => 'foo', 'foo' => true, 'bar' => true}
|
|
47
|
+
assert_template_result(' YES ',"{% if #{awful_markup} %} YES {% endif %}", assigns)
|
|
45
48
|
end
|
|
46
49
|
|
|
47
50
|
def test_comparison_of_expressions_starting_with_and_or_or
|
|
48
51
|
assigns = {'order' => {'items_count' => 0}, 'android' => {'name' => 'Roy'}}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
assert_template_result( "YES",
|
|
56
|
-
"{% if order.items_count == 0 %}YES{% endif %}",
|
|
57
|
-
assigns)
|
|
58
|
-
end
|
|
52
|
+
assert_template_result( "YES",
|
|
53
|
+
"{% if android.name == 'Roy' %}YES{% endif %}",
|
|
54
|
+
assigns)
|
|
55
|
+
assert_template_result( "YES",
|
|
56
|
+
"{% if order.items_count == 0 %}YES{% endif %}",
|
|
57
|
+
assigns)
|
|
59
58
|
end
|
|
60
59
|
|
|
61
60
|
def test_if_and
|
|
@@ -135,26 +134,36 @@ class IfElseTagTest < Test::Unit::TestCase
|
|
|
135
134
|
end
|
|
136
135
|
|
|
137
136
|
def test_syntax_error_no_variable
|
|
138
|
-
|
|
137
|
+
assert_raises(SyntaxError){ assert_template_result('', '{% if jerry == 1 %}')}
|
|
139
138
|
end
|
|
140
139
|
|
|
141
140
|
def test_syntax_error_no_expression
|
|
142
|
-
|
|
141
|
+
assert_raises(SyntaxError) { assert_template_result('', '{% if %}') }
|
|
143
142
|
end
|
|
144
143
|
|
|
145
144
|
def test_if_with_custom_condition
|
|
145
|
+
original_op = Condition.operators['contains']
|
|
146
146
|
Condition.operators['contains'] = :[]
|
|
147
147
|
|
|
148
148
|
assert_template_result('yes', %({% if 'bob' contains 'o' %}yes{% endif %}))
|
|
149
149
|
assert_template_result('no', %({% if 'bob' contains 'f' %}yes{% else %}no{% endif %}))
|
|
150
150
|
ensure
|
|
151
|
-
Condition.operators
|
|
151
|
+
Condition.operators['contains'] = original_op
|
|
152
152
|
end
|
|
153
153
|
|
|
154
154
|
def test_operators_are_ignored_unless_isolated
|
|
155
|
+
original_op = Condition.operators['contains']
|
|
155
156
|
Condition.operators['contains'] = :[]
|
|
156
157
|
|
|
157
158
|
assert_template_result('yes',
|
|
158
159
|
%({% if 'gnomeslab-and-or-liquid' contains 'gnomeslab-and-or-liquid' %}yes{% endif %}))
|
|
160
|
+
ensure
|
|
161
|
+
Condition.operators['contains'] = original_op
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def test_operators_are_whitelisted
|
|
165
|
+
assert_raises(SyntaxError) do
|
|
166
|
+
assert_template_result('', %({% if 1 or throw or or 1 %}yes{% endif %}))
|
|
167
|
+
end
|
|
159
168
|
end
|
|
160
|
-
end
|
|
169
|
+
end
|