liquid 3.0.6 → 4.0.0.rc1
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 +4 -4
- data/History.md +89 -58
- data/{MIT-LICENSE → LICENSE} +0 -0
- data/lib/liquid.rb +7 -6
- data/lib/liquid/block.rb +31 -124
- data/lib/liquid/block_body.rb +54 -57
- data/lib/liquid/condition.rb +23 -22
- data/lib/liquid/context.rb +50 -42
- data/lib/liquid/document.rb +19 -9
- data/lib/liquid/drop.rb +12 -13
- data/lib/liquid/errors.rb +16 -17
- data/lib/liquid/expression.rb +15 -3
- data/lib/liquid/extensions.rb +7 -7
- data/lib/liquid/file_system.rb +3 -3
- data/lib/liquid/forloop_drop.rb +42 -0
- data/lib/liquid/i18n.rb +5 -5
- data/lib/liquid/interrupts.rb +1 -2
- data/lib/liquid/lexer.rb +6 -4
- data/lib/liquid/locales/en.yml +3 -1
- data/lib/liquid/parse_context.rb +37 -0
- data/lib/liquid/parser_switching.rb +4 -4
- data/lib/liquid/profiler.rb +18 -19
- data/lib/liquid/profiler/hooks.rb +7 -7
- data/lib/liquid/range_lookup.rb +16 -1
- data/lib/liquid/resource_limits.rb +23 -0
- data/lib/liquid/standardfilters.rb +101 -56
- data/lib/liquid/strainer.rb +4 -5
- data/lib/liquid/tablerowloop_drop.rb +62 -0
- data/lib/liquid/tag.rb +9 -8
- data/lib/liquid/tags/assign.rb +5 -4
- data/lib/liquid/tags/break.rb +0 -3
- data/lib/liquid/tags/capture.rb +1 -1
- data/lib/liquid/tags/case.rb +19 -12
- data/lib/liquid/tags/comment.rb +2 -2
- data/lib/liquid/tags/cycle.rb +6 -6
- data/lib/liquid/tags/decrement.rb +1 -4
- data/lib/liquid/tags/for.rb +93 -75
- data/lib/liquid/tags/if.rb +49 -44
- data/lib/liquid/tags/ifchanged.rb +0 -2
- data/lib/liquid/tags/include.rb +60 -52
- data/lib/liquid/tags/raw.rb +26 -4
- data/lib/liquid/tags/table_row.rb +12 -30
- data/lib/liquid/tags/unless.rb +3 -4
- data/lib/liquid/template.rb +23 -50
- data/lib/liquid/tokenizer.rb +31 -0
- data/lib/liquid/utils.rb +48 -8
- data/lib/liquid/variable.rb +46 -45
- data/lib/liquid/variable_lookup.rb +3 -3
- data/lib/liquid/version.rb +1 -1
- data/test/integration/assign_test.rb +8 -8
- data/test/integration/blank_test.rb +14 -14
- 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 +64 -45
- data/test/integration/filter_test.rb +60 -20
- data/test/integration/output_test.rb +26 -27
- data/test/integration/parsing_quirks_test.rb +15 -13
- data/test/integration/render_profiling_test.rb +20 -20
- data/test/integration/security_test.rb +5 -7
- data/test/integration/standard_filter_test.rb +119 -37
- 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 +133 -98
- data/test/integration/tags/if_else_tag_test.rb +75 -77
- data/test/integration/tags/include_tag_test.rb +23 -30
- 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 +91 -45
- data/test/integration/variable_test.rb +23 -13
- data/test/test_helper.rb +33 -5
- data/test/unit/block_unit_test.rb +6 -5
- data/test/unit/condition_unit_test.rb +82 -77
- data/test/unit/context_unit_test.rb +48 -57
- 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 +11 -8
- 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 +13 -2
- 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 +6 -5
- data/test/unit/tokenizer_unit_test.rb +24 -7
- data/test/unit/variable_unit_test.rb +60 -43
- metadata +44 -41
- 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
@@ -28,11 +28,14 @@ class ParsingQuirksTest < Minitest::Test
|
|
28
28
|
|
29
29
|
def test_error_on_empty_filter
|
30
30
|
assert Template.parse("{{test}}")
|
31
|
-
|
31
|
+
|
32
|
+
with_error_mode(:lax) do
|
33
|
+
assert Template.parse("{{|test}}")
|
34
|
+
end
|
35
|
+
|
32
36
|
with_error_mode(:strict) do
|
33
|
-
assert_raises(SyntaxError)
|
34
|
-
|
35
|
-
end
|
37
|
+
assert_raises(SyntaxError) { Template.parse("{{|test}}") }
|
38
|
+
assert_raises(SyntaxError) { Template.parse("{{test |a|b|}}") }
|
36
39
|
end
|
37
40
|
end
|
38
41
|
|
@@ -59,25 +62,25 @@ class ParsingQuirksTest < Minitest::Test
|
|
59
62
|
end
|
60
63
|
|
61
64
|
def test_no_error_on_lax_empty_filter
|
62
|
-
assert Template.parse("{{test |a|b|}}", :
|
63
|
-
assert Template.parse("{{test}}", :
|
64
|
-
assert Template.parse("{{|test|}}", :
|
65
|
+
assert Template.parse("{{test |a|b|}}", error_mode: :lax)
|
66
|
+
assert Template.parse("{{test}}", error_mode: :lax)
|
67
|
+
assert Template.parse("{{|test|}}", error_mode: :lax)
|
65
68
|
end
|
66
69
|
|
67
70
|
def test_meaningless_parens_lax
|
68
71
|
with_error_mode(:lax) do
|
69
|
-
assigns = {'b' => 'bar', 'c' => 'baz'}
|
72
|
+
assigns = { 'b' => 'bar', 'c' => 'baz' }
|
70
73
|
markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false"
|
71
|
-
assert_template_result(' YES ',"{% if #{markup} %} YES {% endif %}", assigns)
|
74
|
+
assert_template_result(' YES ', "{% if #{markup} %} YES {% endif %}", assigns)
|
72
75
|
end
|
73
76
|
end
|
74
77
|
|
75
78
|
def test_unexpected_characters_silently_eat_logic_lax
|
76
79
|
with_error_mode(:lax) do
|
77
80
|
markup = "true && false"
|
78
|
-
assert_template_result(' YES ',"{% if #{markup} %} YES {% endif %}")
|
81
|
+
assert_template_result(' YES ', "{% if #{markup} %} YES {% endif %}")
|
79
82
|
markup = "false || true"
|
80
|
-
assert_template_result('',"{% if #{markup} %} YES {% endif %}")
|
83
|
+
assert_template_result('', "{% if #{markup} %} YES {% endif %}")
|
81
84
|
end
|
82
85
|
end
|
83
86
|
|
@@ -89,7 +92,7 @@ class ParsingQuirksTest < Minitest::Test
|
|
89
92
|
|
90
93
|
def test_unanchored_filter_arguments
|
91
94
|
with_error_mode(:lax) do
|
92
|
-
assert_template_result('hi',"{{ 'hi there' | split$$$:' ' | first }}")
|
95
|
+
assert_template_result('hi', "{{ 'hi there' | split$$$:' ' | first }}")
|
93
96
|
|
94
97
|
assert_template_result('x', "{{ 'X' | downcase) }}")
|
95
98
|
|
@@ -112,5 +115,4 @@ class ParsingQuirksTest < Minitest::Test
|
|
112
115
|
assert_template_result('12345', "{% for i in (1...5) %}{{ i }}{% endfor %}")
|
113
116
|
end
|
114
117
|
end
|
115
|
-
|
116
118
|
end # ParsingQuirksTest
|
@@ -4,7 +4,7 @@ class RenderProfilingTest < Minitest::Test
|
|
4
4
|
include Liquid
|
5
5
|
|
6
6
|
class ProfilingFileSystem
|
7
|
-
def read_template_file(template_path
|
7
|
+
def read_template_file(template_path)
|
8
8
|
"Rendering template {% assign template_name = '#{template_path}'%}\n{{ template_name }}"
|
9
9
|
end
|
10
10
|
end
|
@@ -21,7 +21,7 @@ class RenderProfilingTest < Minitest::Test
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def test_parse_makes_available_simple_profiling
|
24
|
-
t = Template.parse("{{ 'a string' | upcase }}", :
|
24
|
+
t = Template.parse("{{ 'a string' | upcase }}", profile: true)
|
25
25
|
t.render!
|
26
26
|
|
27
27
|
assert_equal 1, t.profiler.length
|
@@ -31,14 +31,14 @@ class RenderProfilingTest < Minitest::Test
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def test_render_ignores_raw_strings_when_profiling
|
34
|
-
t = Template.parse("This is raw string\nstuff\nNewline", :
|
34
|
+
t = Template.parse("This is raw string\nstuff\nNewline", profile: true)
|
35
35
|
t.render!
|
36
36
|
|
37
37
|
assert_equal 0, t.profiler.length
|
38
38
|
end
|
39
39
|
|
40
40
|
def test_profiling_includes_line_numbers_of_liquid_nodes
|
41
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", :
|
41
|
+
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", profile: true)
|
42
42
|
t.render!
|
43
43
|
assert_equal 2, t.profiler.length
|
44
44
|
|
@@ -49,7 +49,7 @@ class RenderProfilingTest < Minitest::Test
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def test_profiling_includes_line_numbers_of_included_partials
|
52
|
-
t = Template.parse("{% include 'a_template' %}", :
|
52
|
+
t = Template.parse("{% include 'a_template' %}", profile: true)
|
53
53
|
t.render!
|
54
54
|
|
55
55
|
included_children = t.profiler[0].children
|
@@ -61,7 +61,7 @@ class RenderProfilingTest < Minitest::Test
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def test_profiling_times_the_rendering_of_tokens
|
64
|
-
t = Template.parse("{% include 'a_template' %}", :
|
64
|
+
t = Template.parse("{% include 'a_template' %}", profile: true)
|
65
65
|
t.render!
|
66
66
|
|
67
67
|
node = t.profiler[0]
|
@@ -69,14 +69,14 @@ class RenderProfilingTest < Minitest::Test
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def test_profiling_times_the_entire_render
|
72
|
-
t = Template.parse("{% include 'a_template' %}", :
|
72
|
+
t = Template.parse("{% include 'a_template' %}", profile: true)
|
73
73
|
t.render!
|
74
74
|
|
75
75
|
assert t.profiler.total_render_time >= 0, "Total render time was not calculated"
|
76
76
|
end
|
77
77
|
|
78
78
|
def test_profiling_uses_include_to_mark_children
|
79
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", :
|
79
|
+
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", profile: true)
|
80
80
|
t.render!
|
81
81
|
|
82
82
|
include_node = t.profiler[1]
|
@@ -84,47 +84,47 @@ class RenderProfilingTest < Minitest::Test
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def test_profiling_marks_children_with_the_name_of_included_partial
|
87
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", :
|
87
|
+
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", profile: true)
|
88
88
|
t.render!
|
89
89
|
|
90
90
|
include_node = t.profiler[1]
|
91
91
|
include_node.children.each do |child|
|
92
|
-
assert_equal "
|
92
|
+
assert_equal "a_template", child.partial
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
96
|
def test_profiling_supports_multiple_templates
|
97
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'b_template' %}", :
|
97
|
+
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'b_template' %}", profile: true)
|
98
98
|
t.render!
|
99
99
|
|
100
100
|
a_template = t.profiler[1]
|
101
101
|
a_template.children.each do |child|
|
102
|
-
assert_equal "
|
102
|
+
assert_equal "a_template", child.partial
|
103
103
|
end
|
104
104
|
|
105
105
|
b_template = t.profiler[2]
|
106
106
|
b_template.children.each do |child|
|
107
|
-
assert_equal "
|
107
|
+
assert_equal "b_template", child.partial
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
111
|
def test_profiling_supports_rendering_the_same_partial_multiple_times
|
112
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'a_template' %}", :
|
112
|
+
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'a_template' %}", profile: true)
|
113
113
|
t.render!
|
114
114
|
|
115
115
|
a_template1 = t.profiler[1]
|
116
116
|
a_template1.children.each do |child|
|
117
|
-
assert_equal "
|
117
|
+
assert_equal "a_template", child.partial
|
118
118
|
end
|
119
119
|
|
120
120
|
a_template2 = t.profiler[2]
|
121
121
|
a_template2.children.each do |child|
|
122
|
-
assert_equal "
|
122
|
+
assert_equal "a_template", child.partial
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
126
|
def test_can_iterate_over_each_profiling_entry
|
127
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", :
|
127
|
+
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", profile: true)
|
128
128
|
t.render!
|
129
129
|
|
130
130
|
timing_count = 0
|
@@ -136,7 +136,7 @@ class RenderProfilingTest < Minitest::Test
|
|
136
136
|
end
|
137
137
|
|
138
138
|
def test_profiling_marks_children_of_if_blocks
|
139
|
-
t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", :
|
139
|
+
t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", profile: true)
|
140
140
|
t.render!
|
141
141
|
|
142
142
|
assert_equal 1, t.profiler.length
|
@@ -144,8 +144,8 @@ class RenderProfilingTest < Minitest::Test
|
|
144
144
|
end
|
145
145
|
|
146
146
|
def test_profiling_marks_children_of_for_blocks
|
147
|
-
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", :
|
148
|
-
t.render!({"collection" => ["one", "two"]})
|
147
|
+
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", profile: true)
|
148
|
+
t.render!({ "collection" => ["one", "two"] })
|
149
149
|
|
150
150
|
assert_equal 1, t.profiler.length
|
151
151
|
# Will profile each invocation of the for block
|
@@ -11,32 +11,30 @@ class SecurityTest < Minitest::Test
|
|
11
11
|
|
12
12
|
def test_no_instance_eval
|
13
13
|
text = %( {{ '1+1' | instance_eval }} )
|
14
|
-
expected =
|
14
|
+
expected = %( 1+1 )
|
15
15
|
|
16
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
|
-
expected =
|
21
|
+
expected = %( 1+1 )
|
22
22
|
|
23
23
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
26
|
def test_no_instance_eval_after_mixing_in_new_filter
|
28
27
|
text = %( {{ '1+1' | instance_eval }} )
|
29
|
-
expected =
|
28
|
+
expected = %( 1+1 )
|
30
29
|
|
31
30
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
32
31
|
end
|
33
32
|
|
34
|
-
|
35
33
|
def test_no_instance_eval_later_in_chain
|
36
34
|
text = %( {{ '1+1' | add_one | instance_eval }} )
|
37
|
-
expected =
|
35
|
+
expected = %( 1+1 + 1 )
|
38
36
|
|
39
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
37
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: SecurityFilter)
|
40
38
|
end
|
41
39
|
|
42
40
|
def test_does_not_add_filters_to_symbol_table
|
@@ -49,7 +49,7 @@ class StandardFiltersTest < Minitest::Test
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def test_size
|
52
|
-
assert_equal 3, @filters.size([1,2,3])
|
52
|
+
assert_equal 3, @filters.size([1, 2, 3])
|
53
53
|
assert_equal 0, @filters.size([])
|
54
54
|
assert_equal 0, @filters.size(nil)
|
55
55
|
end
|
@@ -76,20 +76,27 @@ class StandardFiltersTest < Minitest::Test
|
|
76
76
|
assert_equal '', @filters.slice(nil, 0)
|
77
77
|
assert_equal '', @filters.slice('foobar', 100, 10)
|
78
78
|
assert_equal '', @filters.slice('foobar', -100, 10)
|
79
|
+
assert_equal 'oob', @filters.slice('foobar', '1', '3')
|
80
|
+
assert_raises(Liquid::ArgumentError) do
|
81
|
+
@filters.slice('foobar', nil)
|
82
|
+
end
|
83
|
+
assert_raises(Liquid::ArgumentError) do
|
84
|
+
@filters.slice('foobar', 0, "")
|
85
|
+
end
|
79
86
|
end
|
80
87
|
|
81
88
|
def test_slice_on_arrays
|
82
89
|
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
|
90
|
+
assert_equal %w(o o b), @filters.slice(input, 1, 3)
|
91
|
+
assert_equal %w(o o b a r), @filters.slice(input, 1, 1000)
|
92
|
+
assert_equal %w(), @filters.slice(input, 1, 0)
|
93
|
+
assert_equal %w(o), @filters.slice(input, 1, 1)
|
94
|
+
assert_equal %w(b a r), @filters.slice(input, 3, 3)
|
95
|
+
assert_equal %w(a r), @filters.slice(input, -2, 2)
|
96
|
+
assert_equal %w(a r), @filters.slice(input, -2, 1000)
|
97
|
+
assert_equal %w(r), @filters.slice(input, -1)
|
98
|
+
assert_equal %w(), @filters.slice(input, 100, 10)
|
99
|
+
assert_equal %w(), @filters.slice(input, -100, 10)
|
93
100
|
end
|
94
101
|
|
95
102
|
def test_truncate
|
@@ -101,16 +108,17 @@ class StandardFiltersTest < Minitest::Test
|
|
101
108
|
end
|
102
109
|
|
103
110
|
def test_split
|
104
|
-
assert_equal ['12','34'], @filters.split('12~34', '~')
|
105
|
-
assert_equal ['A? ',' ,Z'], @filters.split('A? ~ ~ ~ ,Z', '~ ~ ~')
|
111
|
+
assert_equal ['12', '34'], @filters.split('12~34', '~')
|
112
|
+
assert_equal ['A? ', ' ,Z'], @filters.split('A? ~ ~ ~ ,Z', '~ ~ ~')
|
106
113
|
assert_equal ['A?Z'], @filters.split('A?Z', '~')
|
107
114
|
# Regexp works although Liquid does not support.
|
108
|
-
assert_equal ['A','Z'], @filters.split('AxZ', /x/)
|
115
|
+
assert_equal ['A', 'Z'], @filters.split('AxZ', /x/)
|
109
116
|
assert_equal [], @filters.split(nil, ' ')
|
110
117
|
end
|
111
118
|
|
112
119
|
def test_escape
|
113
120
|
assert_equal '<strong>', @filters.escape('<strong>')
|
121
|
+
assert_equal nil, @filters.escape(nil)
|
114
122
|
assert_equal '<strong>', @filters.h('<strong>')
|
115
123
|
end
|
116
124
|
|
@@ -123,6 +131,13 @@ class StandardFiltersTest < Minitest::Test
|
|
123
131
|
assert_equal nil, @filters.url_encode(nil)
|
124
132
|
end
|
125
133
|
|
134
|
+
def test_url_decode
|
135
|
+
assert_equal 'foo bar', @filters.url_decode('foo+bar')
|
136
|
+
assert_equal 'foo bar', @filters.url_decode('foo%20bar')
|
137
|
+
assert_equal 'foo+1@example.com', @filters.url_decode('foo%2B1%40example.com')
|
138
|
+
assert_equal nil, @filters.url_decode(nil)
|
139
|
+
end
|
140
|
+
|
126
141
|
def test_truncatewords
|
127
142
|
assert_equal 'one two three', @filters.truncatewords('one two three', 4)
|
128
143
|
assert_equal 'one two...', @filters.truncatewords('one two three', 2)
|
@@ -142,45 +157,62 @@ class StandardFiltersTest < Minitest::Test
|
|
142
157
|
end
|
143
158
|
|
144
159
|
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], ' - ')
|
160
|
+
assert_equal '1 2 3 4', @filters.join([1, 2, 3, 4])
|
161
|
+
assert_equal '1 - 2 - 3 - 4', @filters.join([1, 2, 3, 4], ' - ')
|
147
162
|
end
|
148
163
|
|
149
164
|
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")
|
165
|
+
assert_equal [1, 2, 3, 4], @filters.sort([4, 3, 2, 1])
|
166
|
+
assert_equal [{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], @filters.sort([{ "a" => 4 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a")
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_sort_empty_array
|
170
|
+
assert_equal [], @filters.sort([], "a")
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_sort_natural_empty_array
|
174
|
+
assert_equal [], @filters.sort_natural([], "a")
|
152
175
|
end
|
153
176
|
|
154
177
|
def test_legacy_sort_hash
|
155
|
-
assert_equal [{a:1, b:2}], @filters.sort({a:1, b:2})
|
178
|
+
assert_equal [{ a: 1, b: 2 }], @filters.sort({ a: 1, b: 2 })
|
156
179
|
end
|
157
180
|
|
158
181
|
def test_numerical_vs_lexicographical_sort
|
159
182
|
assert_equal [2, 10], @filters.sort([10, 2])
|
160
|
-
assert_equal [{"a" => 2}, {"a" => 10}], @filters.sort([{"a" => 10}, {"a" => 2}], "a")
|
183
|
+
assert_equal [{ "a" => 2 }, { "a" => 10 }], @filters.sort([{ "a" => 10 }, { "a" => 2 }], "a")
|
161
184
|
assert_equal ["10", "2"], @filters.sort(["10", "2"])
|
162
|
-
assert_equal [{"a" => "10"}, {"a" => "2"}], @filters.sort([{"a" => "10"}, {"a" => "2"}], "a")
|
185
|
+
assert_equal [{ "a" => "10" }, { "a" => "2" }], @filters.sort([{ "a" => "10" }, { "a" => "2" }], "a")
|
163
186
|
end
|
164
187
|
|
165
188
|
def test_uniq
|
166
|
-
assert_equal [
|
167
|
-
assert_equal [
|
189
|
+
assert_equal ["foo"], @filters.uniq("foo")
|
190
|
+
assert_equal [1, 3, 2, 4], @filters.uniq([1, 1, 3, 2, 3, 1, 4, 3, 2, 1])
|
191
|
+
assert_equal [{ "a" => 1 }, { "a" => 3 }, { "a" => 2 }], @filters.uniq([{ "a" => 1 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a")
|
168
192
|
testdrop = TestDrop.new
|
169
193
|
assert_equal [testdrop], @filters.uniq([testdrop, TestDrop.new], 'test')
|
170
194
|
end
|
171
195
|
|
196
|
+
def test_uniq_empty_array
|
197
|
+
assert_equal [], @filters.uniq([], "a")
|
198
|
+
end
|
199
|
+
|
200
|
+
def test_compact_empty_array
|
201
|
+
assert_equal [], @filters.compact([], "a")
|
202
|
+
end
|
203
|
+
|
172
204
|
def test_reverse
|
173
|
-
assert_equal [4,3,2,1], @filters.reverse([1,2,3,4])
|
205
|
+
assert_equal [4, 3, 2, 1], @filters.reverse([1, 2, 3, 4])
|
174
206
|
end
|
175
207
|
|
176
208
|
def test_legacy_reverse_hash
|
177
|
-
assert_equal [{a:1, b:2}], @filters.reverse(a:1, b:2)
|
209
|
+
assert_equal [{ a: 1, b: 2 }], @filters.reverse(a: 1, b: 2)
|
178
210
|
end
|
179
211
|
|
180
212
|
def test_map
|
181
|
-
assert_equal [1,2,3,4], @filters.map([{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], 'a')
|
213
|
+
assert_equal [1, 2, 3, 4], @filters.map([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], 'a')
|
182
214
|
assert_template_result 'abc', "{{ ary | map:'foo' | map:'bar' }}",
|
183
|
-
'ary' => [{'foo' => {'bar' => 'a'}}, {'foo' => {'bar' => 'b'}}, {'foo' => {'bar' => 'c'}}]
|
215
|
+
'ary' => [{ 'foo' => { 'bar' => 'a' } }, { 'foo' => { 'bar' => 'b' } }, { 'foo' => { 'bar' => 'c' } }]
|
184
216
|
end
|
185
217
|
|
186
218
|
def test_map_doesnt_call_arbitrary_stuff
|
@@ -212,11 +244,24 @@ class StandardFiltersTest < Minitest::Test
|
|
212
244
|
|
213
245
|
def test_map_over_proc
|
214
246
|
drop = TestDrop.new
|
215
|
-
p =
|
247
|
+
p = proc{ drop }
|
216
248
|
templ = '{{ procs | map: "test" }}'
|
217
249
|
assert_template_result "testfoo", templ, "procs" => [p]
|
218
250
|
end
|
219
251
|
|
252
|
+
def test_map_over_drops_returning_procs
|
253
|
+
drops = [
|
254
|
+
{
|
255
|
+
"proc" => ->{ "foo" },
|
256
|
+
},
|
257
|
+
{
|
258
|
+
"proc" => ->{ "bar" },
|
259
|
+
},
|
260
|
+
]
|
261
|
+
templ = '{{ drops | map: "proc" }}'
|
262
|
+
assert_template_result "foobar", templ, "drops" => drops
|
263
|
+
end
|
264
|
+
|
220
265
|
def test_map_works_on_enumerables
|
221
266
|
assert_template_result "123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new
|
222
267
|
end
|
@@ -230,6 +275,10 @@ class StandardFiltersTest < Minitest::Test
|
|
230
275
|
assert_template_result 'foobar', '{{ foo | last }}', 'foo' => [ThingWithToLiquid.new]
|
231
276
|
end
|
232
277
|
|
278
|
+
def test_truncate_calls_to_liquid
|
279
|
+
assert_template_result "wo...", '{{ foo | truncate: 5 }}', "foo" => TestThing.new
|
280
|
+
end
|
281
|
+
|
233
282
|
def test_date
|
234
283
|
assert_equal 'May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B")
|
235
284
|
assert_equal 'June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B")
|
@@ -249,9 +298,12 @@ class StandardFiltersTest < Minitest::Test
|
|
249
298
|
assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y")
|
250
299
|
assert_equal "#{Date.today.year}", @filters.date('now', '%Y')
|
251
300
|
assert_equal "#{Date.today.year}", @filters.date('today', '%Y')
|
301
|
+
assert_equal "#{Date.today.year}", @filters.date('Today', '%Y')
|
252
302
|
|
253
303
|
assert_equal nil, @filters.date(nil, "%B")
|
254
304
|
|
305
|
+
assert_equal '', @filters.date('', "%B")
|
306
|
+
|
255
307
|
with_timezone("UTC") do
|
256
308
|
assert_equal "07/05/2006", @filters.date(1152098955, "%m/%d/%Y")
|
257
309
|
assert_equal "07/05/2006", @filters.date("1152098955", "%m/%d/%Y")
|
@@ -259,21 +311,25 @@ class StandardFiltersTest < Minitest::Test
|
|
259
311
|
end
|
260
312
|
|
261
313
|
def test_first_last
|
262
|
-
assert_equal 1, @filters.first([1,2,3])
|
263
|
-
assert_equal 3, @filters.last([1,2,3])
|
314
|
+
assert_equal 1, @filters.first([1, 2, 3])
|
315
|
+
assert_equal 3, @filters.last([1, 2, 3])
|
264
316
|
assert_equal nil, @filters.first([])
|
265
317
|
assert_equal nil, @filters.last([])
|
266
318
|
end
|
267
319
|
|
268
320
|
def test_replace
|
269
321
|
assert_equal '2 2 2 2', @filters.replace('1 1 1 1', '1', 2)
|
322
|
+
assert_equal '2 2 2 2', @filters.replace('1 1 1 1', 1, 2)
|
270
323
|
assert_equal '2 1 1 1', @filters.replace_first('1 1 1 1', '1', 2)
|
324
|
+
assert_equal '2 1 1 1', @filters.replace_first('1 1 1 1', 1, 2)
|
271
325
|
assert_template_result '2 1 1 1', "{{ '1 1 1 1' | replace_first: '1', 2 }}"
|
272
326
|
end
|
273
327
|
|
274
328
|
def test_remove
|
275
329
|
assert_equal ' ', @filters.remove("a a a a", 'a')
|
330
|
+
assert_equal ' ', @filters.remove("1 1 1 1", 1)
|
276
331
|
assert_equal 'a a a', @filters.remove_first("a a a a", 'a ')
|
332
|
+
assert_equal ' 1 1 1', @filters.remove_first("1 1 1 1", 1)
|
277
333
|
assert_template_result 'a a a', "{{ 'a a a a' | remove_first: 'a ' }}"
|
278
334
|
end
|
279
335
|
|
@@ -332,38 +388,64 @@ class StandardFiltersTest < Minitest::Test
|
|
332
388
|
assert_equal "Liquid error: divided by 0", Template.parse("{{ 5 | divided_by:0 }}").render
|
333
389
|
|
334
390
|
assert_template_result "0.5", "{{ 2.0 | divided_by:4 }}"
|
391
|
+
assert_raises(Liquid::ZeroDivisionError) do
|
392
|
+
assert_template_result "4", "{{ 1 | modulo: 0 }}"
|
393
|
+
end
|
335
394
|
end
|
336
395
|
|
337
396
|
def test_modulo
|
338
397
|
assert_template_result "1", "{{ 3 | modulo:2 }}"
|
398
|
+
assert_raises(Liquid::ZeroDivisionError) do
|
399
|
+
assert_template_result "4", "{{ 1 | modulo: 0 }}"
|
400
|
+
end
|
339
401
|
end
|
340
402
|
|
341
403
|
def test_round
|
342
404
|
assert_template_result "5", "{{ input | round }}", 'input' => 4.6
|
343
405
|
assert_template_result "4", "{{ '4.3' | round }}"
|
344
406
|
assert_template_result "4.56", "{{ input | round: 2 }}", 'input' => 4.5612
|
407
|
+
assert_raises(Liquid::FloatDomainError) do
|
408
|
+
assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | round }}"
|
409
|
+
end
|
345
410
|
end
|
346
411
|
|
347
412
|
def test_ceil
|
348
413
|
assert_template_result "5", "{{ input | ceil }}", 'input' => 4.6
|
349
414
|
assert_template_result "5", "{{ '4.3' | ceil }}"
|
415
|
+
assert_raises(Liquid::FloatDomainError) do
|
416
|
+
assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | ceil }}"
|
417
|
+
end
|
350
418
|
end
|
351
419
|
|
352
420
|
def test_floor
|
353
421
|
assert_template_result "4", "{{ input | floor }}", 'input' => 4.6
|
354
422
|
assert_template_result "4", "{{ '4.3' | floor }}"
|
423
|
+
assert_raises(Liquid::FloatDomainError) do
|
424
|
+
assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | floor }}"
|
425
|
+
end
|
355
426
|
end
|
356
427
|
|
357
428
|
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)
|
429
|
+
assigns = { 'a' => 'bc', 'b' => 'd' }
|
430
|
+
assert_template_result('bcd', "{{ a | append: 'd'}}", assigns)
|
431
|
+
assert_template_result('bcd', "{{ a | append: b}}", assigns)
|
432
|
+
end
|
433
|
+
|
434
|
+
def test_concat
|
435
|
+
assert_equal [1, 2, 3, 4], @filters.concat([1, 2], [3, 4])
|
436
|
+
assert_equal [1, 2, 'a'], @filters.concat([1, 2], ['a'])
|
437
|
+
assert_equal [1, 2, 10], @filters.concat([1, 2], [10])
|
438
|
+
|
439
|
+
assert_raises(TypeError) do
|
440
|
+
# no implicit conversion of Fixnum into Array
|
441
|
+
@filters.concat([1, 2], 10)
|
442
|
+
end
|
361
443
|
end
|
362
444
|
|
363
445
|
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)
|
446
|
+
assigns = { 'a' => 'bc', 'b' => 'a' }
|
447
|
+
assert_template_result('abc', "{{ a | prepend: 'a'}}", assigns)
|
448
|
+
assert_template_result('abc', "{{ a | prepend: b}}", assigns)
|
367
449
|
end
|
368
450
|
|
369
451
|
def test_default
|
@@ -376,7 +458,7 @@ class StandardFiltersTest < Minitest::Test
|
|
376
458
|
end
|
377
459
|
|
378
460
|
def test_cannot_access_private_methods
|
379
|
-
assert_template_result('a',"{{ 'a' | to_number }}")
|
461
|
+
assert_template_result('a', "{{ 'a' | to_number }}")
|
380
462
|
end
|
381
463
|
|
382
464
|
def test_date_raises_nothing
|