liquid 3.0.6 → 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 +98 -58
- 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 +50 -46
- 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_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 +14 -7
- 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 +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 +95 -75
- data/lib/liquid/tags/if.rb +49 -44
- 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 -30
- data/lib/liquid/tags/unless.rb +3 -4
- data/lib/liquid/template.rb +42 -54
- data/lib/liquid/tokenizer.rb +31 -0
- data/lib/liquid/utils.rb +52 -8
- data/lib/liquid/variable.rb +46 -45
- data/lib/liquid/variable_lookup.rb +7 -5
- data/lib/liquid/version.rb +1 -1
- data/lib/liquid.rb +9 -7
- 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 +99 -46
- data/test/integration/filter_test.rb +60 -20
- data/test/integration/hash_ordering_test.rb +9 -9
- data/test/integration/output_test.rb +26 -27
- data/test/integration/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 +179 -40
- 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 +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 +33 -5
- 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 +80 -1
- data/test/unit/tag_unit_test.rb +7 -2
- data/test/unit/tags/case_tag_unit_test.rb +1 -1
- data/test/unit/tags/for_tag_unit_test.rb +2 -2
- data/test/unit/tags/if_tag_unit_test.rb +1 -1
- data/test/unit/template_unit_test.rb +14 -5
- data/test/unit/tokenizer_unit_test.rb +24 -7
- data/test/unit/variable_unit_test.rb +60 -43
- metadata +19 -14
- 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
@@ -1,24 +1,5 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class ErrorDrop < Liquid::Drop
|
4
|
-
def standard_error
|
5
|
-
raise Liquid::StandardError, 'standard error'
|
6
|
-
end
|
7
|
-
|
8
|
-
def argument_error
|
9
|
-
raise Liquid::ArgumentError, 'argument error'
|
10
|
-
end
|
11
|
-
|
12
|
-
def syntax_error
|
13
|
-
raise Liquid::SyntaxError, 'syntax error'
|
14
|
-
end
|
15
|
-
|
16
|
-
def exception
|
17
|
-
raise Exception, 'exception'
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
3
|
class ErrorHandlingTest < Minitest::Test
|
23
4
|
include Liquid
|
24
5
|
|
@@ -56,7 +37,7 @@ class ErrorHandlingTest < Minitest::Test
|
|
56
37
|
end
|
57
38
|
|
58
39
|
def test_standard_error
|
59
|
-
template = Liquid::Template.parse(
|
40
|
+
template = Liquid::Template.parse(' {{ errors.standard_error }} ')
|
60
41
|
assert_equal ' Liquid error: standard error ', template.render('errors' => ErrorDrop.new)
|
61
42
|
|
62
43
|
assert_equal 1, template.errors.size
|
@@ -64,7 +45,7 @@ class ErrorHandlingTest < Minitest::Test
|
|
64
45
|
end
|
65
46
|
|
66
47
|
def test_syntax
|
67
|
-
template = Liquid::Template.parse(
|
48
|
+
template = Liquid::Template.parse(' {{ errors.syntax_error }} ')
|
68
49
|
assert_equal ' Liquid syntax error: syntax error ', template.render('errors' => ErrorDrop.new)
|
69
50
|
|
70
51
|
assert_equal 1, template.errors.size
|
@@ -72,7 +53,7 @@ class ErrorHandlingTest < Minitest::Test
|
|
72
53
|
end
|
73
54
|
|
74
55
|
def test_argument
|
75
|
-
template = Liquid::Template.parse(
|
56
|
+
template = Liquid::Template.parse(' {{ errors.argument_error }} ')
|
76
57
|
assert_equal ' Liquid error: argument error ', template.render('errors' => ErrorDrop.new)
|
77
58
|
|
78
59
|
assert_equal 1, template.errors.size
|
@@ -94,7 +75,7 @@ class ErrorHandlingTest < Minitest::Test
|
|
94
75
|
end
|
95
76
|
|
96
77
|
def test_lax_unrecognized_operator
|
97
|
-
template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', :
|
78
|
+
template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', error_mode: :lax)
|
98
79
|
assert_equal ' Liquid error: Unknown operator =! ', template.render
|
99
80
|
assert_equal 1, template.errors.size
|
100
81
|
assert_equal Liquid::ArgumentError, template.errors.first.class
|
@@ -102,31 +83,47 @@ class ErrorHandlingTest < Minitest::Test
|
|
102
83
|
|
103
84
|
def test_with_line_numbers_adds_numbers_to_parser_errors
|
104
85
|
err = assert_raises(SyntaxError) do
|
105
|
-
|
86
|
+
Liquid::Template.parse(%q(
|
106
87
|
foobar
|
107
88
|
|
108
89
|
{% "cat" | foobar %}
|
109
90
|
|
110
91
|
bla
|
111
|
-
|
112
|
-
:
|
92
|
+
),
|
93
|
+
line_numbers: true
|
113
94
|
)
|
114
95
|
end
|
115
96
|
|
116
|
-
assert_match
|
97
|
+
assert_match(/Liquid syntax error \(line 4\)/, err.message)
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_with_line_numbers_adds_numbers_to_parser_errors_with_whitespace_trim
|
101
|
+
err = assert_raises(SyntaxError) do
|
102
|
+
Liquid::Template.parse(%q(
|
103
|
+
foobar
|
104
|
+
|
105
|
+
{%- "cat" | foobar -%}
|
106
|
+
|
107
|
+
bla
|
108
|
+
),
|
109
|
+
line_numbers: true
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
113
|
+
assert_match(/Liquid syntax error \(line 4\)/, err.message)
|
117
114
|
end
|
118
115
|
|
119
116
|
def test_parsing_warn_with_line_numbers_adds_numbers_to_lexer_errors
|
120
|
-
template = Liquid::Template.parse(
|
117
|
+
template = Liquid::Template.parse('
|
121
118
|
foobar
|
122
119
|
|
123
120
|
{% if 1 =! 2 %}ok{% endif %}
|
124
121
|
|
125
122
|
bla
|
126
|
-
|
127
|
-
:
|
128
|
-
:
|
129
|
-
|
123
|
+
',
|
124
|
+
error_mode: :warn,
|
125
|
+
line_numbers: true
|
126
|
+
)
|
130
127
|
|
131
128
|
assert_equal ['Liquid syntax error (line 4): Unexpected character = in "1 =! 2"'],
|
132
129
|
template.warnings.map(&:message)
|
@@ -134,16 +131,16 @@ class ErrorHandlingTest < Minitest::Test
|
|
134
131
|
|
135
132
|
def test_parsing_strict_with_line_numbers_adds_numbers_to_lexer_errors
|
136
133
|
err = assert_raises(SyntaxError) do
|
137
|
-
Liquid::Template.parse(
|
134
|
+
Liquid::Template.parse('
|
138
135
|
foobar
|
139
136
|
|
140
137
|
{% if 1 =! 2 %}ok{% endif %}
|
141
138
|
|
142
139
|
bla
|
143
|
-
|
144
|
-
:
|
145
|
-
:
|
146
|
-
|
140
|
+
',
|
141
|
+
error_mode: :strict,
|
142
|
+
line_numbers: true
|
143
|
+
)
|
147
144
|
end
|
148
145
|
|
149
146
|
assert_equal 'Liquid syntax error (line 4): Unexpected character = in "1 =! 2"', err.message
|
@@ -151,7 +148,7 @@ class ErrorHandlingTest < Minitest::Test
|
|
151
148
|
|
152
149
|
def test_syntax_errors_in_nested_blocks_have_correct_line_number
|
153
150
|
err = assert_raises(SyntaxError) do
|
154
|
-
Liquid::Template.parse(
|
151
|
+
Liquid::Template.parse('
|
155
152
|
foobar
|
156
153
|
|
157
154
|
{% if 1 != 2 %}
|
@@ -159,9 +156,9 @@ class ErrorHandlingTest < Minitest::Test
|
|
159
156
|
{% endif %}
|
160
157
|
|
161
158
|
bla
|
162
|
-
|
163
|
-
:
|
164
|
-
|
159
|
+
',
|
160
|
+
line_numbers: true
|
161
|
+
)
|
165
162
|
end
|
166
163
|
|
167
164
|
assert_equal "Liquid syntax error (line 5): Unknown tag 'foo'", err.message
|
@@ -169,18 +166,18 @@ class ErrorHandlingTest < Minitest::Test
|
|
169
166
|
|
170
167
|
def test_strict_error_messages
|
171
168
|
err = assert_raises(SyntaxError) do
|
172
|
-
Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', :
|
169
|
+
Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', error_mode: :strict)
|
173
170
|
end
|
174
171
|
assert_equal 'Liquid syntax error: Unexpected character = in "1 =! 2"', err.message
|
175
172
|
|
176
173
|
err = assert_raises(SyntaxError) do
|
177
|
-
Liquid::Template.parse('{{%%%}}', :
|
174
|
+
Liquid::Template.parse('{{%%%}}', error_mode: :strict)
|
178
175
|
end
|
179
176
|
assert_equal 'Liquid syntax error: Unexpected character % in "{{%%%}}"', err.message
|
180
177
|
end
|
181
178
|
|
182
179
|
def test_warnings
|
183
|
-
template = Liquid::Template.parse('{% if ~~~ %}{{%%%}}{% else %}{{ hello. }}{% endif %}', :
|
180
|
+
template = Liquid::Template.parse('{% if ~~~ %}{{%%%}}{% else %}{{ hello. }}{% endif %}', error_mode: :warn)
|
184
181
|
assert_equal 3, template.warnings.size
|
185
182
|
assert_equal 'Unexpected character ~ in "~~~"', template.warnings[0].to_s(false)
|
186
183
|
assert_equal 'Unexpected character % in "{{%%%}}"', template.warnings[1].to_s(false)
|
@@ -189,12 +186,12 @@ class ErrorHandlingTest < Minitest::Test
|
|
189
186
|
end
|
190
187
|
|
191
188
|
def test_warning_line_numbers
|
192
|
-
template = Liquid::Template.parse("{% if ~~~ %}\n{{%%%}}{% else %}\n{{ hello. }}{% endif %}", :
|
189
|
+
template = Liquid::Template.parse("{% if ~~~ %}\n{{%%%}}{% else %}\n{{ hello. }}{% endif %}", error_mode: :warn, line_numbers: true)
|
193
190
|
assert_equal 'Liquid syntax error (line 1): Unexpected character ~ in "~~~"', template.warnings[0].message
|
194
191
|
assert_equal 'Liquid syntax error (line 2): Unexpected character % in "{{%%%}}"', template.warnings[1].message
|
195
192
|
assert_equal 'Liquid syntax error (line 3): Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].message
|
196
193
|
assert_equal 3, template.warnings.size
|
197
|
-
assert_equal [1,2,3], template.warnings.map(&:line_number)
|
194
|
+
assert_equal [1, 2, 3], template.warnings.map(&:line_number)
|
198
195
|
end
|
199
196
|
|
200
197
|
# Liquid should not catch Exceptions that are not subclasses of StandardError, like Interrupt and NoMemoryError
|
@@ -204,4 +201,60 @@ class ErrorHandlingTest < Minitest::Test
|
|
204
201
|
template.render('errors' => ErrorDrop.new)
|
205
202
|
end
|
206
203
|
end
|
204
|
+
|
205
|
+
def test_default_exception_renderer_with_internal_error
|
206
|
+
template = Liquid::Template.parse('This is a runtime error: {{ errors.runtime_error }}', line_numbers: true)
|
207
|
+
|
208
|
+
output = template.render({ 'errors' => ErrorDrop.new })
|
209
|
+
|
210
|
+
assert_equal 'This is a runtime error: Liquid error (line 1): internal', output
|
211
|
+
assert_equal [Liquid::InternalError], template.errors.map(&:class)
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_setting_default_exception_renderer
|
215
|
+
old_exception_renderer = Liquid::Template.default_exception_renderer
|
216
|
+
exceptions = []
|
217
|
+
Liquid::Template.default_exception_renderer = ->(e) { exceptions << e; '' }
|
218
|
+
template = Liquid::Template.parse('This is a runtime error: {{ errors.argument_error }}')
|
219
|
+
|
220
|
+
output = template.render({ 'errors' => ErrorDrop.new })
|
221
|
+
|
222
|
+
assert_equal 'This is a runtime error: ', output
|
223
|
+
assert_equal [Liquid::ArgumentError], template.errors.map(&:class)
|
224
|
+
ensure
|
225
|
+
Liquid::Template.default_exception_renderer = old_exception_renderer if old_exception_renderer
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_exception_renderer_exposing_non_liquid_error
|
229
|
+
template = Liquid::Template.parse('This is a runtime error: {{ errors.runtime_error }}', line_numbers: true)
|
230
|
+
exceptions = []
|
231
|
+
handler = ->(e) { exceptions << e; e.cause }
|
232
|
+
|
233
|
+
output = template.render({ 'errors' => ErrorDrop.new }, exception_renderer: handler)
|
234
|
+
|
235
|
+
assert_equal 'This is a runtime error: runtime error', output
|
236
|
+
assert_equal [Liquid::InternalError], exceptions.map(&:class)
|
237
|
+
assert_equal exceptions, template.errors
|
238
|
+
assert_equal '#<RuntimeError: runtime error>', exceptions.first.cause.inspect
|
239
|
+
end
|
240
|
+
|
241
|
+
class TestFileSystem
|
242
|
+
def read_template_file(template_path)
|
243
|
+
"{{ errors.argument_error }}"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def test_included_template_name_with_line_numbers
|
248
|
+
old_file_system = Liquid::Template.file_system
|
249
|
+
|
250
|
+
begin
|
251
|
+
Liquid::Template.file_system = TestFileSystem.new
|
252
|
+
template = Liquid::Template.parse("Argument error:\n{% include 'product' %}", line_numbers: true)
|
253
|
+
page = template.render('errors' => ErrorDrop.new)
|
254
|
+
ensure
|
255
|
+
Liquid::Template.file_system = old_file_system
|
256
|
+
end
|
257
|
+
assert_equal "Argument error:\nLiquid error (product line 1): argument error", page
|
258
|
+
assert_equal "product", template.errors.first.template_name
|
259
|
+
end
|
207
260
|
end
|
@@ -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
|
@@ -39,13 +39,13 @@ class FiltersTest < Minitest::Test
|
|
39
39
|
@context['var'] = 1000
|
40
40
|
@context.add_filters(MoneyFilter)
|
41
41
|
|
42
|
-
assert_equal ' 1000$ ',
|
42
|
+
assert_equal ' 1000$ ', Template.parse("{{var | money}}").render(@context)
|
43
43
|
end
|
44
44
|
|
45
45
|
def test_underscore_in_filter_name
|
46
46
|
@context['var'] = 1000
|
47
47
|
@context.add_filters(MoneyFilter)
|
48
|
-
assert_equal ' 1000$ ',
|
48
|
+
assert_equal ' 1000$ ', Template.parse("{{var | money_with_underscore}}").render(@context)
|
49
49
|
end
|
50
50
|
|
51
51
|
def test_second_filter_overwrites_first
|
@@ -53,67 +53,100 @@ class FiltersTest < Minitest::Test
|
|
53
53
|
@context.add_filters(MoneyFilter)
|
54
54
|
@context.add_filters(CanadianMoneyFilter)
|
55
55
|
|
56
|
-
assert_equal ' 1000$ CAD ',
|
56
|
+
assert_equal ' 1000$ CAD ', Template.parse("{{var | money}}").render(@context)
|
57
57
|
end
|
58
58
|
|
59
59
|
def test_size
|
60
60
|
@context['var'] = 'abcd'
|
61
61
|
@context.add_filters(MoneyFilter)
|
62
62
|
|
63
|
-
assert_equal 4,
|
63
|
+
assert_equal '4', Template.parse("{{var | size}}").render(@context)
|
64
64
|
end
|
65
65
|
|
66
66
|
def test_join
|
67
|
-
@context['var'] = [1,2,3,4]
|
67
|
+
@context['var'] = [1, 2, 3, 4]
|
68
68
|
|
69
|
-
assert_equal "1 2 3 4",
|
69
|
+
assert_equal "1 2 3 4", Template.parse("{{var | join}}").render(@context)
|
70
70
|
end
|
71
71
|
|
72
72
|
def test_sort
|
73
73
|
@context['value'] = 3
|
74
|
-
@context['numbers'] = [2,1,4,3]
|
74
|
+
@context['numbers'] = [2, 1, 4, 3]
|
75
75
|
@context['words'] = ['expected', 'as', 'alphabetic']
|
76
76
|
@context['arrays'] = ['flower', 'are']
|
77
|
+
@context['case_sensitive'] = ['sensitive', 'Expected', 'case']
|
77
78
|
|
78
|
-
assert_equal
|
79
|
-
assert_equal
|
80
|
-
assert_equal
|
81
|
-
assert_equal
|
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
|
85
|
+
|
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)
|
82
114
|
end
|
83
115
|
|
84
116
|
def test_strip_html
|
85
117
|
@context['var'] = "<b>bla blub</a>"
|
86
118
|
|
87
|
-
assert_equal "bla blub",
|
119
|
+
assert_equal "bla blub", Template.parse("{{ var | strip_html }}").render(@context)
|
88
120
|
end
|
89
121
|
|
90
122
|
def test_strip_html_ignore_comments_with_html
|
91
123
|
@context['var'] = "<!-- split and some <ul> tag --><b>bla blub</a>"
|
92
124
|
|
93
|
-
assert_equal "bla blub",
|
125
|
+
assert_equal "bla blub", Template.parse("{{ var | strip_html }}").render(@context)
|
94
126
|
end
|
95
127
|
|
96
128
|
def test_capitalize
|
97
129
|
@context['var'] = "blub"
|
98
130
|
|
99
|
-
assert_equal "Blub",
|
131
|
+
assert_equal "Blub", Template.parse("{{ var | capitalize }}").render(@context)
|
100
132
|
end
|
101
133
|
|
102
134
|
def test_nonexistent_filter_is_ignored
|
103
135
|
@context['var'] = 1000
|
104
136
|
|
105
|
-
assert_equal 1000,
|
137
|
+
assert_equal '1000', Template.parse("{{ var | xyzzy }}").render(@context)
|
106
138
|
end
|
107
139
|
|
108
140
|
def test_filter_with_keyword_arguments
|
109
141
|
@context['surname'] = 'john'
|
142
|
+
@context['input'] = 'hello %{first_name}, %{last_name}'
|
110
143
|
@context.add_filters(SubstituteFilter)
|
111
|
-
output =
|
144
|
+
output = Template.parse(%({{ input | substitute: first_name: surname, last_name: 'doe' }})).render(@context)
|
112
145
|
assert_equal 'hello john, doe', output
|
113
146
|
end
|
114
147
|
|
115
148
|
def test_override_object_method_in_filter
|
116
|
-
assert_equal "tap overridden", Template.parse("{{var | tap}}").render!({ 'var' => 1000 }, :
|
149
|
+
assert_equal "tap overridden", Template.parse("{{var | tap}}").render!({ 'var' => 1000 }, filters: [OverrideObjectMethodFilter])
|
117
150
|
|
118
151
|
# tap still treated as a non-existent filter
|
119
152
|
assert_equal "1000", Template.parse("{{var | tap}}").render!({ 'var' => 1000 })
|
@@ -126,8 +159,8 @@ class FiltersInTemplate < Minitest::Test
|
|
126
159
|
def test_local_global
|
127
160
|
with_global_filter(MoneyFilter) do
|
128
161
|
assert_equal " 1000$ ", Template.parse("{{1000 | money}}").render!(nil, nil)
|
129
|
-
assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, :
|
130
|
-
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])
|
131
164
|
end
|
132
165
|
end
|
133
166
|
|
@@ -136,3 +169,10 @@ class FiltersInTemplate < Minitest::Test
|
|
136
169
|
assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, [CanadianMoneyFilter])
|
137
170
|
end
|
138
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,14 +32,14 @@ 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
|
|
@@ -53,72 +52,72 @@ class OutputTest < Minitest::Test
|
|
53
52
|
end
|
54
53
|
|
55
54
|
def test_variable_traversing
|
56
|
-
text =
|
55
|
+
text = %( {{car.bmw}} {{car.gm}} {{car.bmw}} )
|
57
56
|
|
58
|
-
expected =
|
57
|
+
expected = %( good bad good )
|
59
58
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
60
59
|
end
|
61
60
|
|
62
61
|
def test_variable_piping
|
63
62
|
text = %( {{ car.gm | make_funny }} )
|
64
|
-
expected =
|
63
|
+
expected = %( LOL )
|
65
64
|
|
66
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
65
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
67
66
|
end
|
68
67
|
|
69
68
|
def test_variable_piping_with_input
|
70
69
|
text = %( {{ car.gm | cite_funny }} )
|
71
|
-
expected =
|
70
|
+
expected = %( LOL: bad )
|
72
71
|
|
73
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
72
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
74
73
|
end
|
75
74
|
|
76
75
|
def test_variable_piping_with_args
|
77
76
|
text = %! {{ car.gm | add_smiley : ':-(' }} !
|
78
77
|
expected = %| bad :-( |
|
79
78
|
|
80
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
79
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
81
80
|
end
|
82
81
|
|
83
82
|
def test_variable_piping_with_no_args
|
84
|
-
text =
|
83
|
+
text = %( {{ car.gm | add_smiley }} )
|
85
84
|
expected = %| bad :-) |
|
86
85
|
|
87
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
86
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
88
87
|
end
|
89
88
|
|
90
89
|
def test_multiple_variable_piping_with_args
|
91
90
|
text = %! {{ car.gm | add_smiley : ':-(' | add_smiley : ':-('}} !
|
92
91
|
expected = %| bad :-( :-( |
|
93
92
|
|
94
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
93
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
95
94
|
end
|
96
95
|
|
97
96
|
def test_variable_piping_with_multiple_args
|
98
|
-
text =
|
99
|
-
expected =
|
97
|
+
text = %( {{ car.gm | add_tag : 'span', 'bar'}} )
|
98
|
+
expected = %( <span id="bar">bad</span> )
|
100
99
|
|
101
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
100
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
102
101
|
end
|
103
102
|
|
104
103
|
def test_variable_piping_with_variable_args
|
105
|
-
text =
|
106
|
-
expected =
|
104
|
+
text = %( {{ car.gm | add_tag : 'span', car.bmw}} )
|
105
|
+
expected = %( <span id="good">bad</span> )
|
107
106
|
|
108
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
107
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
109
108
|
end
|
110
109
|
|
111
110
|
def test_multiple_pipings
|
112
111
|
text = %( {{ best_cars | cite_funny | paragraph }} )
|
113
|
-
expected =
|
112
|
+
expected = %( <p>LOL: bmw</p> )
|
114
113
|
|
115
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
114
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
116
115
|
end
|
117
116
|
|
118
117
|
def test_link_to
|
119
118
|
text = %( {{ 'Typo' | link_to: 'http://typo.leetsoft.com' }} )
|
120
|
-
expected =
|
119
|
+
expected = %( <a href="http://typo.leetsoft.com">Typo</a> )
|
121
120
|
|
122
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
121
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
123
122
|
end
|
124
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
|