liquid 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/History.md +130 -62
- data/README.md +31 -0
- data/lib/liquid/block.rb +31 -124
- data/lib/liquid/block_body.rb +75 -59
- data/lib/liquid/condition.rb +23 -22
- data/lib/liquid/context.rb +51 -60
- 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 +15 -3
- data/lib/liquid/extensions.rb +13 -7
- data/lib/liquid/file_system.rb +11 -11
- 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 +5 -1
- data/lib/liquid/parse_context.rb +37 -0
- data/lib/liquid/parser.rb +1 -1
- 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 +121 -61
- data/lib/liquid/strainer.rb +32 -29
- data/lib/liquid/tablerowloop_drop.rb +62 -0
- data/lib/liquid/tag.rb +9 -8
- data/lib/liquid/tags/assign.rb +17 -4
- data/lib/liquid/tags/break.rb +0 -3
- data/lib/liquid/tags/capture.rb +2 -2
- 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 +95 -75
- data/lib/liquid/tags/if.rb +48 -43
- data/lib/liquid/tags/ifchanged.rb +0 -2
- data/lib/liquid/tags/include.rb +61 -52
- data/lib/liquid/tags/raw.rb +32 -4
- data/lib/liquid/tags/table_row.rb +12 -31
- data/lib/liquid/tags/unless.rb +4 -5
- data/lib/liquid/template.rb +42 -54
- data/lib/liquid/tokenizer.rb +31 -0
- data/lib/liquid/utils.rb +52 -8
- data/lib/liquid/variable.rb +46 -45
- data/lib/liquid/variable_lookup.rb +9 -5
- data/lib/liquid/version.rb +1 -1
- data/lib/liquid.rb +9 -7
- data/test/integration/assign_test.rb +18 -8
- data/test/integration/blank_test.rb +14 -14
- data/test/integration/capture_test.rb +10 -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 +99 -46
- data/test/integration/filter_test.rb +72 -19
- data/test/integration/hash_ordering_test.rb +9 -9
- data/test/integration/output_test.rb +34 -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 +9 -7
- data/test/integration/standard_filter_test.rb +198 -42
- 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 +96 -77
- data/test/integration/tags/include_tag_test.rb +34 -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 +190 -49
- data/test/integration/trim_mode_test.rb +525 -0
- data/test/integration/variable_test.rb +23 -13
- data/test/test_helper.rb +44 -9
- data/test/unit/block_unit_test.rb +8 -5
- data/test/unit/condition_unit_test.rb +86 -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 +85 -8
- 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 +66 -43
- metadata +55 -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
- /data/{MIT-LICENSE → LICENSE} +0 -0
@@ -17,7 +17,7 @@ module CanadianMoneyFilter
|
|
17
17
|
end
|
18
18
|
|
19
19
|
module SubstituteFilter
|
20
|
-
def substitute(input, params={})
|
20
|
+
def substitute(input, params = {})
|
21
21
|
input.gsub(/%\{(\w+)\}/) { |match| params[$1] }
|
22
22
|
end
|
23
23
|
end
|
@@ -25,6 +25,12 @@ end
|
|
25
25
|
class FiltersTest < Minitest::Test
|
26
26
|
include Liquid
|
27
27
|
|
28
|
+
module OverrideObjectMethodFilter
|
29
|
+
def tap(input)
|
30
|
+
"tap overridden"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
28
34
|
def setup
|
29
35
|
@context = Context.new
|
30
36
|
end
|
@@ -33,13 +39,13 @@ class FiltersTest < Minitest::Test
|
|
33
39
|
@context['var'] = 1000
|
34
40
|
@context.add_filters(MoneyFilter)
|
35
41
|
|
36
|
-
assert_equal ' 1000$ ',
|
42
|
+
assert_equal ' 1000$ ', Template.parse("{{var | money}}").render(@context)
|
37
43
|
end
|
38
44
|
|
39
45
|
def test_underscore_in_filter_name
|
40
46
|
@context['var'] = 1000
|
41
47
|
@context.add_filters(MoneyFilter)
|
42
|
-
assert_equal ' 1000$ ',
|
48
|
+
assert_equal ' 1000$ ', Template.parse("{{var | money_with_underscore}}").render(@context)
|
43
49
|
end
|
44
50
|
|
45
51
|
def test_second_filter_overwrites_first
|
@@ -47,64 +53,104 @@ class FiltersTest < Minitest::Test
|
|
47
53
|
@context.add_filters(MoneyFilter)
|
48
54
|
@context.add_filters(CanadianMoneyFilter)
|
49
55
|
|
50
|
-
assert_equal ' 1000$ CAD ',
|
56
|
+
assert_equal ' 1000$ CAD ', Template.parse("{{var | money}}").render(@context)
|
51
57
|
end
|
52
58
|
|
53
59
|
def test_size
|
54
60
|
@context['var'] = 'abcd'
|
55
61
|
@context.add_filters(MoneyFilter)
|
56
62
|
|
57
|
-
assert_equal 4,
|
63
|
+
assert_equal '4', Template.parse("{{var | size}}").render(@context)
|
58
64
|
end
|
59
65
|
|
60
66
|
def test_join
|
61
|
-
@context['var'] = [1,2,3,4]
|
67
|
+
@context['var'] = [1, 2, 3, 4]
|
62
68
|
|
63
|
-
assert_equal "1 2 3 4",
|
69
|
+
assert_equal "1 2 3 4", Template.parse("{{var | join}}").render(@context)
|
64
70
|
end
|
65
71
|
|
66
72
|
def test_sort
|
67
73
|
@context['value'] = 3
|
68
|
-
@context['numbers'] = [2,1,4,3]
|
74
|
+
@context['numbers'] = [2, 1, 4, 3]
|
69
75
|
@context['words'] = ['expected', 'as', 'alphabetic']
|
70
76
|
@context['arrays'] = ['flower', 'are']
|
77
|
+
@context['case_sensitive'] = ['sensitive', 'Expected', 'case']
|
78
|
+
|
79
|
+
assert_equal '1 2 3 4', Template.parse("{{numbers | sort | join}}").render(@context)
|
80
|
+
assert_equal 'alphabetic as expected', Template.parse("{{words | sort | join}}").render(@context)
|
81
|
+
assert_equal '3', Template.parse("{{value | sort}}").render(@context)
|
82
|
+
assert_equal 'are flower', Template.parse("{{arrays | sort | join}}").render(@context)
|
83
|
+
assert_equal 'Expected case sensitive', Template.parse("{{case_sensitive | sort | join}}").render(@context)
|
84
|
+
end
|
71
85
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
86
|
+
def test_sort_natural
|
87
|
+
@context['words'] = ['case', 'Assert', 'Insensitive']
|
88
|
+
@context['hashes'] = [{ 'a' => 'A' }, { 'a' => 'b' }, { 'a' => 'C' }]
|
89
|
+
@context['objects'] = [TestObject.new('A'), TestObject.new('b'), TestObject.new('C')]
|
90
|
+
|
91
|
+
# Test strings
|
92
|
+
assert_equal 'Assert case Insensitive', Template.parse("{{words | sort_natural | join}}").render(@context)
|
93
|
+
|
94
|
+
# Test hashes
|
95
|
+
assert_equal 'A b C', Template.parse("{{hashes | sort_natural: 'a' | map: 'a' | join}}").render(@context)
|
96
|
+
|
97
|
+
# Test objects
|
98
|
+
assert_equal 'A b C', Template.parse("{{objects | sort_natural: 'a' | map: 'a' | join}}").render(@context)
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_compact
|
102
|
+
@context['words'] = ['a', nil, 'b', nil, 'c']
|
103
|
+
@context['hashes'] = [{ 'a' => 'A' }, { 'a' => nil }, { 'a' => 'C' }]
|
104
|
+
@context['objects'] = [TestObject.new('A'), TestObject.new(nil), TestObject.new('C')]
|
105
|
+
|
106
|
+
# Test strings
|
107
|
+
assert_equal 'a b c', Template.parse("{{words | compact | join}}").render(@context)
|
108
|
+
|
109
|
+
# Test hashes
|
110
|
+
assert_equal 'A C', Template.parse("{{hashes | compact: 'a' | map: 'a' | join}}").render(@context)
|
111
|
+
|
112
|
+
# Test objects
|
113
|
+
assert_equal 'A C', Template.parse("{{objects | compact: 'a' | map: 'a' | join}}").render(@context)
|
76
114
|
end
|
77
115
|
|
78
116
|
def test_strip_html
|
79
117
|
@context['var'] = "<b>bla blub</a>"
|
80
118
|
|
81
|
-
assert_equal "bla blub",
|
119
|
+
assert_equal "bla blub", Template.parse("{{ var | strip_html }}").render(@context)
|
82
120
|
end
|
83
121
|
|
84
122
|
def test_strip_html_ignore_comments_with_html
|
85
123
|
@context['var'] = "<!-- split and some <ul> tag --><b>bla blub</a>"
|
86
124
|
|
87
|
-
assert_equal "bla blub",
|
125
|
+
assert_equal "bla blub", Template.parse("{{ var | strip_html }}").render(@context)
|
88
126
|
end
|
89
127
|
|
90
128
|
def test_capitalize
|
91
129
|
@context['var'] = "blub"
|
92
130
|
|
93
|
-
assert_equal "Blub",
|
131
|
+
assert_equal "Blub", Template.parse("{{ var | capitalize }}").render(@context)
|
94
132
|
end
|
95
133
|
|
96
134
|
def test_nonexistent_filter_is_ignored
|
97
135
|
@context['var'] = 1000
|
98
136
|
|
99
|
-
assert_equal 1000,
|
137
|
+
assert_equal '1000', Template.parse("{{ var | xyzzy }}").render(@context)
|
100
138
|
end
|
101
139
|
|
102
140
|
def test_filter_with_keyword_arguments
|
103
141
|
@context['surname'] = 'john'
|
142
|
+
@context['input'] = 'hello %{first_name}, %{last_name}'
|
104
143
|
@context.add_filters(SubstituteFilter)
|
105
|
-
output =
|
144
|
+
output = Template.parse(%({{ input | substitute: first_name: surname, last_name: 'doe' }})).render(@context)
|
106
145
|
assert_equal 'hello john, doe', output
|
107
146
|
end
|
147
|
+
|
148
|
+
def test_override_object_method_in_filter
|
149
|
+
assert_equal "tap overridden", Template.parse("{{var | tap}}").render!({ 'var' => 1000 }, filters: [OverrideObjectMethodFilter])
|
150
|
+
|
151
|
+
# tap still treated as a non-existent filter
|
152
|
+
assert_equal "1000", Template.parse("{{var | tap}}").render!({ 'var' => 1000 })
|
153
|
+
end
|
108
154
|
end
|
109
155
|
|
110
156
|
class FiltersInTemplate < Minitest::Test
|
@@ -113,8 +159,8 @@ class FiltersInTemplate < Minitest::Test
|
|
113
159
|
def test_local_global
|
114
160
|
with_global_filter(MoneyFilter) do
|
115
161
|
assert_equal " 1000$ ", Template.parse("{{1000 | money}}").render!(nil, nil)
|
116
|
-
assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, :
|
117
|
-
assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, :
|
162
|
+
assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, filters: CanadianMoneyFilter)
|
163
|
+
assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, filters: [CanadianMoneyFilter])
|
118
164
|
end
|
119
165
|
end
|
120
166
|
|
@@ -123,3 +169,10 @@ class FiltersInTemplate < Minitest::Test
|
|
123
169
|
assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, [CanadianMoneyFilter])
|
124
170
|
end
|
125
171
|
end # FiltersTest
|
172
|
+
|
173
|
+
class TestObject < Liquid::Drop
|
174
|
+
attr_accessor :a
|
175
|
+
def initialize(a)
|
176
|
+
@a = a
|
177
|
+
end
|
178
|
+
end
|
@@ -1,18 +1,18 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
class HashOrderingTest < Minitest::Test
|
4
|
+
module MoneyFilter
|
5
|
+
def money(input)
|
6
|
+
sprintf(' %d$ ', input)
|
7
|
+
end
|
6
8
|
end
|
7
|
-
end
|
8
9
|
|
9
|
-
module CanadianMoneyFilter
|
10
|
-
|
11
|
-
|
10
|
+
module CanadianMoneyFilter
|
11
|
+
def money(input)
|
12
|
+
sprintf(' %d$ CAD ', input)
|
13
|
+
end
|
12
14
|
end
|
13
|
-
end
|
14
15
|
|
15
|
-
class HashOrderingTest < Minitest::Test
|
16
16
|
include Liquid
|
17
17
|
|
18
18
|
def test_global_register_order
|
@@ -14,7 +14,7 @@ module FunnyFilter
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def add_tag(input, tag = "p", id = "foo")
|
17
|
-
|
17
|
+
%(<#{tag} id="#{id}">#{input}</#{tag}>)
|
18
18
|
end
|
19
19
|
|
20
20
|
def paragraph(input)
|
@@ -22,9 +22,8 @@ module FunnyFilter
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def link_to(name, url)
|
25
|
-
|
25
|
+
%(<a href="#{url}">#{name}</a>)
|
26
26
|
end
|
27
|
-
|
28
27
|
end
|
29
28
|
|
30
29
|
class OutputTest < Minitest::Test
|
@@ -33,84 +32,92 @@ class OutputTest < Minitest::Test
|
|
33
32
|
def setup
|
34
33
|
@assigns = {
|
35
34
|
'best_cars' => 'bmw',
|
36
|
-
'car' => {'bmw' => 'good', 'gm' => 'bad'}
|
37
|
-
|
35
|
+
'car' => { 'bmw' => 'good', 'gm' => 'bad' }
|
36
|
+
}
|
38
37
|
end
|
39
38
|
|
40
39
|
def test_variable
|
41
|
-
text =
|
40
|
+
text = %( {{best_cars}} )
|
42
41
|
|
43
|
-
expected =
|
42
|
+
expected = %( bmw )
|
44
43
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
45
44
|
end
|
46
45
|
|
46
|
+
def test_variable_traversing_with_two_brackets
|
47
|
+
text = %({{ site.data.menu[include.menu][include.locale] }})
|
48
|
+
assert_equal "it works!", Template.parse(text).render!(
|
49
|
+
"site" => { "data" => { "menu" => { "foo" => { "bar" => "it works!" } } } },
|
50
|
+
"include" => { "menu" => "foo", "locale" => "bar" }
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
47
54
|
def test_variable_traversing
|
48
|
-
text =
|
55
|
+
text = %( {{car.bmw}} {{car.gm}} {{car.bmw}} )
|
49
56
|
|
50
|
-
expected =
|
57
|
+
expected = %( good bad good )
|
51
58
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
52
59
|
end
|
53
60
|
|
54
61
|
def test_variable_piping
|
55
62
|
text = %( {{ car.gm | make_funny }} )
|
56
|
-
expected =
|
63
|
+
expected = %( LOL )
|
57
64
|
|
58
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
65
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
59
66
|
end
|
60
67
|
|
61
68
|
def test_variable_piping_with_input
|
62
69
|
text = %( {{ car.gm | cite_funny }} )
|
63
|
-
expected =
|
70
|
+
expected = %( LOL: bad )
|
64
71
|
|
65
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
72
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
66
73
|
end
|
67
74
|
|
68
75
|
def test_variable_piping_with_args
|
69
76
|
text = %! {{ car.gm | add_smiley : ':-(' }} !
|
70
77
|
expected = %| bad :-( |
|
71
78
|
|
72
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
79
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
73
80
|
end
|
74
81
|
|
75
82
|
def test_variable_piping_with_no_args
|
76
|
-
text =
|
83
|
+
text = %( {{ car.gm | add_smiley }} )
|
77
84
|
expected = %| bad :-) |
|
78
85
|
|
79
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
86
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
80
87
|
end
|
81
88
|
|
82
89
|
def test_multiple_variable_piping_with_args
|
83
90
|
text = %! {{ car.gm | add_smiley : ':-(' | add_smiley : ':-('}} !
|
84
91
|
expected = %| bad :-( :-( |
|
85
92
|
|
86
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
93
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
87
94
|
end
|
88
95
|
|
89
96
|
def test_variable_piping_with_multiple_args
|
90
|
-
text =
|
91
|
-
expected =
|
97
|
+
text = %( {{ car.gm | add_tag : 'span', 'bar'}} )
|
98
|
+
expected = %( <span id="bar">bad</span> )
|
92
99
|
|
93
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
100
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
94
101
|
end
|
95
102
|
|
96
103
|
def test_variable_piping_with_variable_args
|
97
|
-
text =
|
98
|
-
expected =
|
104
|
+
text = %( {{ car.gm | add_tag : 'span', car.bmw}} )
|
105
|
+
expected = %( <span id="good">bad</span> )
|
99
106
|
|
100
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
107
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
101
108
|
end
|
102
109
|
|
103
110
|
def test_multiple_pipings
|
104
111
|
text = %( {{ best_cars | cite_funny | paragraph }} )
|
105
|
-
expected =
|
112
|
+
expected = %( <p>LOL: bmw</p> )
|
106
113
|
|
107
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
114
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
108
115
|
end
|
109
116
|
|
110
117
|
def test_link_to
|
111
118
|
text = %( {{ 'Typo' | link_to: 'http://typo.leetsoft.com' }} )
|
112
|
-
expected =
|
119
|
+
expected = %( <a href="http://typo.leetsoft.com">Typo</a> )
|
113
120
|
|
114
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
121
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
115
122
|
end
|
116
123
|
end # OutputTest
|
@@ -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
|
@@ -9,34 +9,36 @@ end
|
|
9
9
|
class SecurityTest < Minitest::Test
|
10
10
|
include Liquid
|
11
11
|
|
12
|
+
def setup
|
13
|
+
@assigns = {}
|
14
|
+
end
|
15
|
+
|
12
16
|
def test_no_instance_eval
|
13
17
|
text = %( {{ '1+1' | instance_eval }} )
|
14
|
-
expected =
|
18
|
+
expected = %( 1+1 )
|
15
19
|
|
16
20
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
17
21
|
end
|
18
22
|
|
19
23
|
def test_no_existing_instance_eval
|
20
24
|
text = %( {{ '1+1' | __instance_eval__ }} )
|
21
|
-
expected =
|
25
|
+
expected = %( 1+1 )
|
22
26
|
|
23
27
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
24
28
|
end
|
25
29
|
|
26
|
-
|
27
30
|
def test_no_instance_eval_after_mixing_in_new_filter
|
28
31
|
text = %( {{ '1+1' | instance_eval }} )
|
29
|
-
expected =
|
32
|
+
expected = %( 1+1 )
|
30
33
|
|
31
34
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
32
35
|
end
|
33
36
|
|
34
|
-
|
35
37
|
def test_no_instance_eval_later_in_chain
|
36
38
|
text = %( {{ '1+1' | add_one | instance_eval }} )
|
37
|
-
expected =
|
39
|
+
expected = %( 1+1 + 1 )
|
38
40
|
|
39
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
41
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: SecurityFilter)
|
40
42
|
end
|
41
43
|
|
42
44
|
def test_does_not_add_filters_to_symbol_table
|