liquid 4.0.3 → 5.1.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 +4 -4
- data/History.md +54 -0
- data/README.md +6 -0
- data/lib/liquid/block.rb +31 -14
- data/lib/liquid/block_body.rb +166 -54
- data/lib/liquid/condition.rb +41 -20
- data/lib/liquid/context.rb +107 -52
- data/lib/liquid/document.rb +47 -9
- data/lib/liquid/drop.rb +4 -2
- data/lib/liquid/errors.rb +20 -18
- data/lib/liquid/expression.rb +29 -34
- data/lib/liquid/extensions.rb +2 -0
- data/lib/liquid/file_system.rb +6 -4
- data/lib/liquid/forloop_drop.rb +11 -4
- data/lib/liquid/i18n.rb +5 -3
- data/lib/liquid/interrupts.rb +3 -1
- data/lib/liquid/lexer.rb +30 -23
- data/lib/liquid/locales/en.yml +3 -1
- data/lib/liquid/parse_context.rb +20 -4
- data/lib/liquid/parse_tree_visitor.rb +2 -2
- data/lib/liquid/parser.rb +30 -18
- data/lib/liquid/parser_switching.rb +17 -3
- data/lib/liquid/partial_cache.rb +24 -0
- data/lib/liquid/profiler/hooks.rb +26 -14
- data/lib/liquid/profiler.rb +67 -86
- data/lib/liquid/range_lookup.rb +13 -3
- data/lib/liquid/register.rb +6 -0
- data/lib/liquid/resource_limits.rb +47 -8
- data/lib/liquid/standardfilters.rb +95 -46
- data/lib/liquid/static_registers.rb +44 -0
- data/lib/liquid/strainer_factory.rb +36 -0
- data/lib/liquid/strainer_template.rb +53 -0
- data/lib/liquid/tablerowloop_drop.rb +6 -4
- data/lib/liquid/tag/disableable.rb +22 -0
- data/lib/liquid/tag/disabler.rb +21 -0
- data/lib/liquid/tag.rb +28 -6
- data/lib/liquid/tags/assign.rb +24 -10
- data/lib/liquid/tags/break.rb +8 -3
- data/lib/liquid/tags/capture.rb +11 -8
- data/lib/liquid/tags/case.rb +40 -27
- data/lib/liquid/tags/comment.rb +5 -3
- data/lib/liquid/tags/continue.rb +8 -3
- data/lib/liquid/tags/cycle.rb +25 -14
- data/lib/liquid/tags/decrement.rb +6 -3
- data/lib/liquid/tags/echo.rb +34 -0
- data/lib/liquid/tags/for.rb +68 -44
- data/lib/liquid/tags/if.rb +39 -23
- data/lib/liquid/tags/ifchanged.rb +11 -10
- data/lib/liquid/tags/include.rb +34 -47
- data/lib/liquid/tags/increment.rb +7 -3
- data/lib/liquid/tags/raw.rb +14 -11
- data/lib/liquid/tags/render.rb +84 -0
- data/lib/liquid/tags/table_row.rb +23 -19
- data/lib/liquid/tags/unless.rb +23 -15
- data/lib/liquid/template.rb +53 -72
- data/lib/liquid/template_factory.rb +9 -0
- data/lib/liquid/tokenizer.rb +18 -10
- data/lib/liquid/usage.rb +8 -0
- data/lib/liquid/utils.rb +13 -3
- data/lib/liquid/variable.rb +46 -41
- data/lib/liquid/variable_lookup.rb +11 -6
- data/lib/liquid/version.rb +2 -1
- data/lib/liquid.rb +17 -5
- data/test/integration/assign_test.rb +74 -5
- data/test/integration/blank_test.rb +11 -8
- data/test/integration/block_test.rb +47 -1
- data/test/integration/capture_test.rb +18 -10
- data/test/integration/context_test.rb +609 -5
- data/test/integration/document_test.rb +4 -2
- data/test/integration/drop_test.rb +67 -83
- data/test/integration/error_handling_test.rb +73 -61
- data/test/integration/expression_test.rb +46 -0
- data/test/integration/filter_test.rb +53 -42
- data/test/integration/hash_ordering_test.rb +5 -3
- data/test/integration/output_test.rb +26 -24
- data/test/integration/parsing_quirks_test.rb +19 -7
- data/test/integration/{render_profiling_test.rb → profiler_test.rb} +84 -25
- data/test/integration/security_test.rb +30 -21
- data/test/integration/standard_filter_test.rb +385 -281
- data/test/integration/tag/disableable_test.rb +59 -0
- data/test/integration/tag_test.rb +45 -0
- data/test/integration/tags/break_tag_test.rb +4 -2
- data/test/integration/tags/continue_tag_test.rb +4 -2
- data/test/integration/tags/echo_test.rb +13 -0
- data/test/integration/tags/for_tag_test.rb +107 -51
- data/test/integration/tags/if_else_tag_test.rb +5 -3
- data/test/integration/tags/include_tag_test.rb +70 -54
- data/test/integration/tags/increment_tag_test.rb +4 -2
- data/test/integration/tags/liquid_tag_test.rb +116 -0
- data/test/integration/tags/raw_tag_test.rb +14 -11
- data/test/integration/tags/render_tag_test.rb +213 -0
- data/test/integration/tags/standard_tag_test.rb +38 -31
- data/test/integration/tags/statements_test.rb +23 -21
- data/test/integration/tags/table_row_test.rb +2 -0
- data/test/integration/tags/unless_else_tag_test.rb +4 -2
- data/test/integration/template_test.rb +132 -124
- data/test/integration/trim_mode_test.rb +78 -44
- data/test/integration/variable_test.rb +74 -32
- data/test/test_helper.rb +113 -22
- data/test/unit/block_unit_test.rb +19 -24
- data/test/unit/condition_unit_test.rb +79 -77
- data/test/unit/file_system_unit_test.rb +6 -4
- data/test/unit/i18n_unit_test.rb +7 -5
- data/test/unit/lexer_unit_test.rb +11 -9
- data/test/{integration → unit}/parse_tree_visitor_test.rb +16 -2
- data/test/unit/parser_unit_test.rb +37 -35
- data/test/unit/partial_cache_unit_test.rb +128 -0
- data/test/unit/regexp_unit_test.rb +17 -15
- data/test/unit/static_registers_unit_test.rb +156 -0
- data/test/unit/strainer_factory_unit_test.rb +100 -0
- data/test/unit/strainer_template_unit_test.rb +82 -0
- data/test/unit/tag_unit_test.rb +5 -3
- data/test/unit/tags/case_tag_unit_test.rb +3 -1
- data/test/unit/tags/for_tag_unit_test.rb +4 -2
- data/test/unit/tags/if_tag_unit_test.rb +3 -1
- data/test/unit/template_factory_unit_test.rb +12 -0
- data/test/unit/template_unit_test.rb +19 -10
- data/test/unit/tokenizer_unit_test.rb +26 -19
- data/test/unit/variable_unit_test.rb +51 -49
- metadata +76 -50
- data/lib/liquid/strainer.rb +0 -66
- data/lib/liquid/truffle.rb +0 -5
- data/test/truffle/truffle_test.rb +0 -9
- data/test/unit/context_unit_test.rb +0 -489
- data/test/unit/strainer_unit_test.rb +0 -164
@@ -1,24 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
module MoneyFilter
|
4
6
|
def money(input)
|
5
|
-
|
7
|
+
format(' %d$ ', input)
|
6
8
|
end
|
7
9
|
|
8
10
|
def money_with_underscore(input)
|
9
|
-
|
11
|
+
format(' %d$ ', input)
|
10
12
|
end
|
11
13
|
end
|
12
14
|
|
13
15
|
module CanadianMoneyFilter
|
14
16
|
def money(input)
|
15
|
-
|
17
|
+
format(' %d$ CAD ', input)
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
19
21
|
module SubstituteFilter
|
20
22
|
def substitute(input, params = {})
|
21
|
-
input.gsub(/%\{(\w+)\}/) { |
|
23
|
+
input.gsub(/%\{(\w+)\}/) { |_match| params[Regexp.last_match(1)] }
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
@@ -26,7 +28,7 @@ class FiltersTest < Minitest::Test
|
|
26
28
|
include Liquid
|
27
29
|
|
28
30
|
module OverrideObjectMethodFilter
|
29
|
-
def tap(
|
31
|
+
def tap(_input)
|
30
32
|
"tap overridden"
|
31
33
|
end
|
32
34
|
end
|
@@ -39,13 +41,13 @@ class FiltersTest < Minitest::Test
|
|
39
41
|
@context['var'] = 1000
|
40
42
|
@context.add_filters(MoneyFilter)
|
41
43
|
|
42
|
-
assert_equal
|
44
|
+
assert_equal(' 1000$ ', Template.parse("{{var | money}}").render(@context))
|
43
45
|
end
|
44
46
|
|
45
47
|
def test_underscore_in_filter_name
|
46
48
|
@context['var'] = 1000
|
47
49
|
@context.add_filters(MoneyFilter)
|
48
|
-
assert_equal
|
50
|
+
assert_equal(' 1000$ ', Template.parse("{{var | money_with_underscore}}").render(@context))
|
49
51
|
end
|
50
52
|
|
51
53
|
def test_second_filter_overwrites_first
|
@@ -53,103 +55,112 @@ class FiltersTest < Minitest::Test
|
|
53
55
|
@context.add_filters(MoneyFilter)
|
54
56
|
@context.add_filters(CanadianMoneyFilter)
|
55
57
|
|
56
|
-
assert_equal
|
58
|
+
assert_equal(' 1000$ CAD ', Template.parse("{{var | money}}").render(@context))
|
57
59
|
end
|
58
60
|
|
59
61
|
def test_size
|
60
62
|
@context['var'] = 'abcd'
|
61
63
|
@context.add_filters(MoneyFilter)
|
62
64
|
|
63
|
-
assert_equal
|
65
|
+
assert_equal('4', Template.parse("{{var | size}}").render(@context))
|
64
66
|
end
|
65
67
|
|
66
68
|
def test_join
|
67
69
|
@context['var'] = [1, 2, 3, 4]
|
68
70
|
|
69
|
-
assert_equal
|
71
|
+
assert_equal("1 2 3 4", Template.parse("{{var | join}}").render(@context))
|
70
72
|
end
|
71
73
|
|
72
74
|
def test_sort
|
73
|
-
@context['value']
|
75
|
+
@context['value'] = 3
|
74
76
|
@context['numbers'] = [2, 1, 4, 3]
|
75
|
-
@context['words']
|
76
|
-
@context['arrays']
|
77
|
+
@context['words'] = ['expected', 'as', 'alphabetic']
|
78
|
+
@context['arrays'] = ['flower', 'are']
|
77
79
|
@context['case_sensitive'] = ['sensitive', 'Expected', 'case']
|
78
80
|
|
79
|
-
assert_equal
|
80
|
-
assert_equal
|
81
|
-
assert_equal
|
82
|
-
assert_equal
|
83
|
-
assert_equal
|
81
|
+
assert_equal('1 2 3 4', Template.parse("{{numbers | sort | join}}").render(@context))
|
82
|
+
assert_equal('alphabetic as expected', Template.parse("{{words | sort | join}}").render(@context))
|
83
|
+
assert_equal('3', Template.parse("{{value | sort}}").render(@context))
|
84
|
+
assert_equal('are flower', Template.parse("{{arrays | sort | join}}").render(@context))
|
85
|
+
assert_equal('Expected case sensitive', Template.parse("{{case_sensitive | sort | join}}").render(@context))
|
84
86
|
end
|
85
87
|
|
86
88
|
def test_sort_natural
|
87
|
-
@context['words']
|
88
|
-
@context['hashes']
|
89
|
+
@context['words'] = ['case', 'Assert', 'Insensitive']
|
90
|
+
@context['hashes'] = [{ 'a' => 'A' }, { 'a' => 'b' }, { 'a' => 'C' }]
|
89
91
|
@context['objects'] = [TestObject.new('A'), TestObject.new('b'), TestObject.new('C')]
|
90
92
|
|
91
93
|
# Test strings
|
92
|
-
assert_equal
|
94
|
+
assert_equal('Assert case Insensitive', Template.parse("{{words | sort_natural | join}}").render(@context))
|
93
95
|
|
94
96
|
# Test hashes
|
95
|
-
assert_equal
|
97
|
+
assert_equal('A b C', Template.parse("{{hashes | sort_natural: 'a' | map: 'a' | join}}").render(@context))
|
96
98
|
|
97
99
|
# Test objects
|
98
|
-
assert_equal
|
100
|
+
assert_equal('A b C', Template.parse("{{objects | sort_natural: 'a' | map: 'a' | join}}").render(@context))
|
99
101
|
end
|
100
102
|
|
101
103
|
def test_compact
|
102
|
-
@context['words']
|
103
|
-
@context['hashes']
|
104
|
+
@context['words'] = ['a', nil, 'b', nil, 'c']
|
105
|
+
@context['hashes'] = [{ 'a' => 'A' }, { 'a' => nil }, { 'a' => 'C' }]
|
104
106
|
@context['objects'] = [TestObject.new('A'), TestObject.new(nil), TestObject.new('C')]
|
105
107
|
|
106
108
|
# Test strings
|
107
|
-
assert_equal
|
109
|
+
assert_equal('a b c', Template.parse("{{words | compact | join}}").render(@context))
|
108
110
|
|
109
111
|
# Test hashes
|
110
|
-
assert_equal
|
112
|
+
assert_equal('A C', Template.parse("{{hashes | compact: 'a' | map: 'a' | join}}").render(@context))
|
111
113
|
|
112
114
|
# Test objects
|
113
|
-
assert_equal
|
115
|
+
assert_equal('A C', Template.parse("{{objects | compact: 'a' | map: 'a' | join}}").render(@context))
|
114
116
|
end
|
115
117
|
|
116
118
|
def test_strip_html
|
117
119
|
@context['var'] = "<b>bla blub</a>"
|
118
120
|
|
119
|
-
assert_equal
|
121
|
+
assert_equal("bla blub", Template.parse("{{ var | strip_html }}").render(@context))
|
120
122
|
end
|
121
123
|
|
122
124
|
def test_strip_html_ignore_comments_with_html
|
123
125
|
@context['var'] = "<!-- split and some <ul> tag --><b>bla blub</a>"
|
124
126
|
|
125
|
-
assert_equal
|
127
|
+
assert_equal("bla blub", Template.parse("{{ var | strip_html }}").render(@context))
|
126
128
|
end
|
127
129
|
|
128
130
|
def test_capitalize
|
129
131
|
@context['var'] = "blub"
|
130
132
|
|
131
|
-
assert_equal
|
133
|
+
assert_equal("Blub", Template.parse("{{ var | capitalize }}").render(@context))
|
132
134
|
end
|
133
135
|
|
134
136
|
def test_nonexistent_filter_is_ignored
|
135
137
|
@context['var'] = 1000
|
136
138
|
|
137
|
-
assert_equal
|
139
|
+
assert_equal('1000', Template.parse("{{ var | xyzzy }}").render(@context))
|
138
140
|
end
|
139
141
|
|
140
142
|
def test_filter_with_keyword_arguments
|
141
143
|
@context['surname'] = 'john'
|
142
|
-
@context['input']
|
144
|
+
@context['input'] = 'hello %{first_name}, %{last_name}'
|
143
145
|
@context.add_filters(SubstituteFilter)
|
144
|
-
output
|
145
|
-
assert_equal
|
146
|
+
output = Template.parse(%({{ input | substitute: first_name: surname, last_name: 'doe' }})).render(@context)
|
147
|
+
assert_equal('hello john, doe', output)
|
146
148
|
end
|
147
149
|
|
148
150
|
def test_override_object_method_in_filter
|
149
|
-
assert_equal
|
151
|
+
assert_equal("tap overridden", Template.parse("{{var | tap}}").render!({ 'var' => 1000 }, filters: [OverrideObjectMethodFilter]))
|
150
152
|
|
151
153
|
# tap still treated as a non-existent filter
|
152
|
-
assert_equal
|
154
|
+
assert_equal("1000", Template.parse("{{var | tap}}").render!('var' => 1000))
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_liquid_argument_error
|
158
|
+
source = "{{ '' | size: 'too many args' }}"
|
159
|
+
exc = assert_raises(Liquid::ArgumentError) do
|
160
|
+
Template.parse(source).render!
|
161
|
+
end
|
162
|
+
assert_match(/\ALiquid error: wrong number of arguments /, exc.message)
|
163
|
+
assert_equal(exc.message, Template.parse(source).render)
|
153
164
|
end
|
154
165
|
end
|
155
166
|
|
@@ -158,15 +169,15 @@ class FiltersInTemplate < Minitest::Test
|
|
158
169
|
|
159
170
|
def test_local_global
|
160
171
|
with_global_filter(MoneyFilter) do
|
161
|
-
assert_equal
|
162
|
-
assert_equal
|
163
|
-
assert_equal
|
172
|
+
assert_equal(" 1000$ ", Template.parse("{{1000 | money}}").render!(nil, nil))
|
173
|
+
assert_equal(" 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, filters: CanadianMoneyFilter))
|
174
|
+
assert_equal(" 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, filters: [CanadianMoneyFilter]))
|
164
175
|
end
|
165
176
|
end
|
166
177
|
|
167
178
|
def test_local_filter_with_deprecated_syntax
|
168
|
-
assert_equal
|
169
|
-
assert_equal
|
179
|
+
assert_equal(" 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, CanadianMoneyFilter))
|
180
|
+
assert_equal(" 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, [CanadianMoneyFilter]))
|
170
181
|
end
|
171
182
|
end # FiltersTest
|
172
183
|
|
@@ -1,15 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class HashOrderingTest < Minitest::Test
|
4
6
|
module MoneyFilter
|
5
7
|
def money(input)
|
6
|
-
|
8
|
+
format(' %d$ ', input)
|
7
9
|
end
|
8
10
|
end
|
9
11
|
|
10
12
|
module CanadianMoneyFilter
|
11
13
|
def money(input)
|
12
|
-
|
14
|
+
format(' %d$ CAD ', input)
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
@@ -17,7 +19,7 @@ class HashOrderingTest < Minitest::Test
|
|
17
19
|
|
18
20
|
def test_global_register_order
|
19
21
|
with_global_filter(MoneyFilter, CanadianMoneyFilter) do
|
20
|
-
assert_equal
|
22
|
+
assert_equal(" 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, nil))
|
21
23
|
end
|
22
24
|
end
|
23
25
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
module FunnyFilter
|
4
|
-
def make_funny(
|
6
|
+
def make_funny(_input)
|
5
7
|
'LOL'
|
6
8
|
end
|
7
9
|
|
@@ -32,7 +34,7 @@ class OutputTest < Minitest::Test
|
|
32
34
|
def setup
|
33
35
|
@assigns = {
|
34
36
|
'best_cars' => 'bmw',
|
35
|
-
'car' => { 'bmw' => 'good', 'gm' => 'bad' }
|
37
|
+
'car' => { 'bmw' => 'good', 'gm' => 'bad' },
|
36
38
|
}
|
37
39
|
end
|
38
40
|
|
@@ -40,84 +42,84 @@ class OutputTest < Minitest::Test
|
|
40
42
|
text = %( {{best_cars}} )
|
41
43
|
|
42
44
|
expected = %( bmw )
|
43
|
-
assert_equal
|
45
|
+
assert_equal(expected, Template.parse(text).render!(@assigns))
|
44
46
|
end
|
45
47
|
|
46
48
|
def test_variable_traversing_with_two_brackets
|
47
49
|
text = %({{ site.data.menu[include.menu][include.locale] }})
|
48
|
-
assert_equal
|
50
|
+
assert_equal("it works!", Template.parse(text).render!(
|
49
51
|
"site" => { "data" => { "menu" => { "foo" => { "bar" => "it works!" } } } },
|
50
52
|
"include" => { "menu" => "foo", "locale" => "bar" }
|
51
|
-
)
|
53
|
+
))
|
52
54
|
end
|
53
55
|
|
54
56
|
def test_variable_traversing
|
55
57
|
text = %( {{car.bmw}} {{car.gm}} {{car.bmw}} )
|
56
58
|
|
57
59
|
expected = %( good bad good )
|
58
|
-
assert_equal
|
60
|
+
assert_equal(expected, Template.parse(text).render!(@assigns))
|
59
61
|
end
|
60
62
|
|
61
63
|
def test_variable_piping
|
62
|
-
text
|
64
|
+
text = %( {{ car.gm | make_funny }} )
|
63
65
|
expected = %( LOL )
|
64
66
|
|
65
|
-
assert_equal
|
67
|
+
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
66
68
|
end
|
67
69
|
|
68
70
|
def test_variable_piping_with_input
|
69
|
-
text
|
71
|
+
text = %( {{ car.gm | cite_funny }} )
|
70
72
|
expected = %( LOL: bad )
|
71
73
|
|
72
|
-
assert_equal
|
74
|
+
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
73
75
|
end
|
74
76
|
|
75
77
|
def test_variable_piping_with_args
|
76
|
-
text
|
78
|
+
text = %! {{ car.gm | add_smiley : ':-(' }} !
|
77
79
|
expected = %| bad :-( |
|
78
80
|
|
79
|
-
assert_equal
|
81
|
+
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
80
82
|
end
|
81
83
|
|
82
84
|
def test_variable_piping_with_no_args
|
83
|
-
text
|
85
|
+
text = %( {{ car.gm | add_smiley }} )
|
84
86
|
expected = %| bad :-) |
|
85
87
|
|
86
|
-
assert_equal
|
88
|
+
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
87
89
|
end
|
88
90
|
|
89
91
|
def test_multiple_variable_piping_with_args
|
90
|
-
text
|
92
|
+
text = %! {{ car.gm | add_smiley : ':-(' | add_smiley : ':-('}} !
|
91
93
|
expected = %| bad :-( :-( |
|
92
94
|
|
93
|
-
assert_equal
|
95
|
+
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
94
96
|
end
|
95
97
|
|
96
98
|
def test_variable_piping_with_multiple_args
|
97
|
-
text
|
99
|
+
text = %( {{ car.gm | add_tag : 'span', 'bar'}} )
|
98
100
|
expected = %( <span id="bar">bad</span> )
|
99
101
|
|
100
|
-
assert_equal
|
102
|
+
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
101
103
|
end
|
102
104
|
|
103
105
|
def test_variable_piping_with_variable_args
|
104
|
-
text
|
106
|
+
text = %( {{ car.gm | add_tag : 'span', car.bmw}} )
|
105
107
|
expected = %( <span id="good">bad</span> )
|
106
108
|
|
107
|
-
assert_equal
|
109
|
+
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
108
110
|
end
|
109
111
|
|
110
112
|
def test_multiple_pipings
|
111
|
-
text
|
113
|
+
text = %( {{ best_cars | cite_funny | paragraph }} )
|
112
114
|
expected = %( <p>LOL: bmw</p> )
|
113
115
|
|
114
|
-
assert_equal
|
116
|
+
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
115
117
|
end
|
116
118
|
|
117
119
|
def test_link_to
|
118
|
-
text
|
120
|
+
text = %( {{ 'Typo' | link_to: 'http://typo.leetsoft.com' }} )
|
119
121
|
expected = %( <a href="http://typo.leetsoft.com">Typo</a> )
|
120
122
|
|
121
|
-
assert_equal
|
123
|
+
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
|
122
124
|
end
|
123
125
|
end # OutputTest
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class ParsingQuirksTest < Minitest::Test
|
@@ -5,7 +7,7 @@ class ParsingQuirksTest < Minitest::Test
|
|
5
7
|
|
6
8
|
def test_parsing_css
|
7
9
|
text = " div { font-weight: bold; } "
|
8
|
-
assert_equal
|
10
|
+
assert_equal(text, Template.parse(text).render!)
|
9
11
|
end
|
10
12
|
|
11
13
|
def test_raise_on_single_close_bracet
|
@@ -27,10 +29,10 @@ class ParsingQuirksTest < Minitest::Test
|
|
27
29
|
end
|
28
30
|
|
29
31
|
def test_error_on_empty_filter
|
30
|
-
assert
|
32
|
+
assert(Template.parse("{{test}}"))
|
31
33
|
|
32
34
|
with_error_mode(:lax) do
|
33
|
-
assert
|
35
|
+
assert(Template.parse("{{|test}}"))
|
34
36
|
end
|
35
37
|
|
36
38
|
with_error_mode(:strict) do
|
@@ -62,15 +64,15 @@ class ParsingQuirksTest < Minitest::Test
|
|
62
64
|
end
|
63
65
|
|
64
66
|
def test_no_error_on_lax_empty_filter
|
65
|
-
assert
|
66
|
-
assert
|
67
|
-
assert
|
67
|
+
assert(Template.parse("{{test |a|b|}}", error_mode: :lax))
|
68
|
+
assert(Template.parse("{{test}}", error_mode: :lax))
|
69
|
+
assert(Template.parse("{{|test|}}", error_mode: :lax))
|
68
70
|
end
|
69
71
|
|
70
72
|
def test_meaningless_parens_lax
|
71
73
|
with_error_mode(:lax) do
|
72
74
|
assigns = { 'b' => 'bar', 'c' => 'baz' }
|
73
|
-
markup
|
75
|
+
markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false"
|
74
76
|
assert_template_result(' YES ', "{% if #{markup} %} YES {% endif %}", assigns)
|
75
77
|
end
|
76
78
|
end
|
@@ -116,6 +118,16 @@ class ParsingQuirksTest < Minitest::Test
|
|
116
118
|
end
|
117
119
|
end
|
118
120
|
|
121
|
+
def test_blank_variable_markup
|
122
|
+
assert_template_result('', "{{}}")
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_lookup_on_var_with_literal_name
|
126
|
+
assigns = { "blank" => { "x" => "result" } }
|
127
|
+
assert_template_result('result', "{{ blank.x }}", assigns)
|
128
|
+
assert_template_result('result', "{{ blank['x'] }}", assigns)
|
129
|
+
end
|
130
|
+
|
119
131
|
def test_contains_in_id
|
120
132
|
assert_template_result(' YES ', '{% if containsallshipments == true %} YES {% endif %}', 'containsallshipments' => true)
|
121
133
|
end
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
|
-
class
|
5
|
+
class ProfilerTest < Minitest::Test
|
4
6
|
include Liquid
|
5
7
|
|
6
8
|
class ProfilingFileSystem
|
@@ -17,35 +19,35 @@ class RenderProfilingTest < Minitest::Test
|
|
17
19
|
t = Template.parse("{{ 'a string' | upcase }}")
|
18
20
|
t.render!
|
19
21
|
|
20
|
-
assert_nil
|
22
|
+
assert_nil(t.profiler)
|
21
23
|
end
|
22
24
|
|
23
25
|
def test_parse_makes_available_simple_profiling
|
24
26
|
t = Template.parse("{{ 'a string' | upcase }}", profile: true)
|
25
27
|
t.render!
|
26
28
|
|
27
|
-
assert_equal
|
29
|
+
assert_equal(1, t.profiler.length)
|
28
30
|
|
29
31
|
node = t.profiler[0]
|
30
|
-
assert_equal
|
32
|
+
assert_equal(" 'a string' | upcase ", node.code)
|
31
33
|
end
|
32
34
|
|
33
35
|
def test_render_ignores_raw_strings_when_profiling
|
34
36
|
t = Template.parse("This is raw string\nstuff\nNewline", profile: true)
|
35
37
|
t.render!
|
36
38
|
|
37
|
-
assert_equal
|
39
|
+
assert_equal(0, t.profiler.length)
|
38
40
|
end
|
39
41
|
|
40
42
|
def test_profiling_includes_line_numbers_of_liquid_nodes
|
41
43
|
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", profile: true)
|
42
44
|
t.render!
|
43
|
-
assert_equal
|
45
|
+
assert_equal(2, t.profiler.length)
|
44
46
|
|
45
47
|
# {{ 'a string' | upcase }}
|
46
|
-
assert_equal
|
48
|
+
assert_equal(1, t.profiler[0].line_number)
|
47
49
|
# {{ increment test }}
|
48
|
-
assert_equal
|
50
|
+
assert_equal(2, t.profiler[1].line_number)
|
49
51
|
end
|
50
52
|
|
51
53
|
def test_profiling_includes_line_numbers_of_included_partials
|
@@ -55,9 +57,20 @@ class RenderProfilingTest < Minitest::Test
|
|
55
57
|
included_children = t.profiler[0].children
|
56
58
|
|
57
59
|
# {% assign template_name = 'a_template' %}
|
58
|
-
assert_equal
|
60
|
+
assert_equal(1, included_children[0].line_number)
|
59
61
|
# {{ template_name }}
|
60
|
-
assert_equal
|
62
|
+
assert_equal(2, included_children[1].line_number)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_profiling_render_tag
|
66
|
+
t = Template.parse("{% render 'a_template' %}", profile: true)
|
67
|
+
t.render!
|
68
|
+
|
69
|
+
render_children = t.profiler[0].children
|
70
|
+
render_children.each do |timing|
|
71
|
+
assert_equal('a_template', timing.partial)
|
72
|
+
end
|
73
|
+
assert_equal([1, 2], render_children.map(&:line_number))
|
61
74
|
end
|
62
75
|
|
63
76
|
def test_profiling_times_the_rendering_of_tokens
|
@@ -65,14 +78,45 @@ class RenderProfilingTest < Minitest::Test
|
|
65
78
|
t.render!
|
66
79
|
|
67
80
|
node = t.profiler[0]
|
68
|
-
refute_nil
|
81
|
+
refute_nil(node.render_time)
|
69
82
|
end
|
70
83
|
|
71
84
|
def test_profiling_times_the_entire_render
|
72
85
|
t = Template.parse("{% include 'a_template' %}", profile: true)
|
73
86
|
t.render!
|
74
87
|
|
75
|
-
assert
|
88
|
+
assert(t.profiler.total_render_time >= 0, "Total render time was not calculated")
|
89
|
+
end
|
90
|
+
|
91
|
+
class SleepTag < Liquid::Tag
|
92
|
+
def initialize(tag_name, markup, parse_context)
|
93
|
+
super
|
94
|
+
@duration = Float(markup)
|
95
|
+
end
|
96
|
+
|
97
|
+
def render_to_output_buffer(_context, _output)
|
98
|
+
sleep(@duration)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_profiling_multiple_renders
|
103
|
+
with_custom_tag('sleep', SleepTag) do
|
104
|
+
context = Liquid::Context.new
|
105
|
+
t = Liquid::Template.parse("{% sleep 0.001 %}", profile: true)
|
106
|
+
context.template_name = 'index'
|
107
|
+
t.render!(context)
|
108
|
+
context.template_name = 'layout'
|
109
|
+
first_render_time = context.profiler.total_time
|
110
|
+
t.render!(context)
|
111
|
+
|
112
|
+
profiler = context.profiler
|
113
|
+
children = profiler.children
|
114
|
+
assert_operator(first_render_time, :>=, 0.001)
|
115
|
+
assert_operator(profiler.total_time, :>=, 0.001 + first_render_time)
|
116
|
+
assert_equal(["index", "layout"], children.map(&:template_name))
|
117
|
+
assert_equal([nil, nil], children.map(&:code))
|
118
|
+
assert_equal(profiler.total_time, children.map(&:total_time).reduce(&:+))
|
119
|
+
end
|
76
120
|
end
|
77
121
|
|
78
122
|
def test_profiling_uses_include_to_mark_children
|
@@ -80,7 +124,7 @@ class RenderProfilingTest < Minitest::Test
|
|
80
124
|
t.render!
|
81
125
|
|
82
126
|
include_node = t.profiler[1]
|
83
|
-
assert_equal
|
127
|
+
assert_equal(2, include_node.children.length)
|
84
128
|
end
|
85
129
|
|
86
130
|
def test_profiling_marks_children_with_the_name_of_included_partial
|
@@ -89,7 +133,7 @@ class RenderProfilingTest < Minitest::Test
|
|
89
133
|
|
90
134
|
include_node = t.profiler[1]
|
91
135
|
include_node.children.each do |child|
|
92
|
-
assert_equal
|
136
|
+
assert_equal("a_template", child.partial)
|
93
137
|
end
|
94
138
|
end
|
95
139
|
|
@@ -99,12 +143,12 @@ class RenderProfilingTest < Minitest::Test
|
|
99
143
|
|
100
144
|
a_template = t.profiler[1]
|
101
145
|
a_template.children.each do |child|
|
102
|
-
assert_equal
|
146
|
+
assert_equal("a_template", child.partial)
|
103
147
|
end
|
104
148
|
|
105
149
|
b_template = t.profiler[2]
|
106
150
|
b_template.children.each do |child|
|
107
|
-
assert_equal
|
151
|
+
assert_equal("b_template", child.partial)
|
108
152
|
end
|
109
153
|
end
|
110
154
|
|
@@ -114,12 +158,12 @@ class RenderProfilingTest < Minitest::Test
|
|
114
158
|
|
115
159
|
a_template1 = t.profiler[1]
|
116
160
|
a_template1.children.each do |child|
|
117
|
-
assert_equal
|
161
|
+
assert_equal("a_template", child.partial)
|
118
162
|
end
|
119
163
|
|
120
164
|
a_template2 = t.profiler[2]
|
121
165
|
a_template2.children.each do |child|
|
122
|
-
assert_equal
|
166
|
+
assert_equal("a_template", child.partial)
|
123
167
|
end
|
124
168
|
end
|
125
169
|
|
@@ -128,27 +172,42 @@ class RenderProfilingTest < Minitest::Test
|
|
128
172
|
t.render!
|
129
173
|
|
130
174
|
timing_count = 0
|
131
|
-
t.profiler.each do |
|
175
|
+
t.profiler.each do |_timing|
|
132
176
|
timing_count += 1
|
133
177
|
end
|
134
178
|
|
135
|
-
assert_equal
|
179
|
+
assert_equal(2, timing_count)
|
136
180
|
end
|
137
181
|
|
138
182
|
def test_profiling_marks_children_of_if_blocks
|
139
183
|
t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", profile: true)
|
140
184
|
t.render!
|
141
185
|
|
142
|
-
assert_equal
|
143
|
-
assert_equal
|
186
|
+
assert_equal(1, t.profiler.length)
|
187
|
+
assert_equal(2, t.profiler[0].children.length)
|
144
188
|
end
|
145
189
|
|
146
190
|
def test_profiling_marks_children_of_for_blocks
|
147
191
|
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", profile: true)
|
148
|
-
t.render!(
|
192
|
+
t.render!("collection" => ["one", "two"])
|
149
193
|
|
150
|
-
assert_equal
|
194
|
+
assert_equal(1, t.profiler.length)
|
151
195
|
# Will profile each invocation of the for block
|
152
|
-
assert_equal
|
196
|
+
assert_equal(2, t.profiler[0].children.length)
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_profiling_supports_self_time
|
200
|
+
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", profile: true)
|
201
|
+
t.render!("collection" => ["one", "two"])
|
202
|
+
leaf = t.profiler[0].children[0]
|
203
|
+
|
204
|
+
assert_operator(leaf.self_time, :>, 0)
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_profiling_supports_total_time
|
208
|
+
t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", profile: true)
|
209
|
+
t.render!
|
210
|
+
|
211
|
+
assert_operator(t.profiler[0].total_time, :>, 0)
|
153
212
|
end
|
154
213
|
end
|