liquid 3.0.6 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +243 -58
  3. data/README.md +43 -4
  4. data/lib/liquid/block.rb +57 -123
  5. data/lib/liquid/block_body.rb +217 -85
  6. data/lib/liquid/condition.rb +92 -45
  7. data/lib/liquid/context.rb +154 -89
  8. data/lib/liquid/document.rb +57 -9
  9. data/lib/liquid/drop.rb +20 -17
  10. data/lib/liquid/errors.rb +27 -29
  11. data/lib/liquid/expression.rb +32 -20
  12. data/lib/liquid/extensions.rb +21 -7
  13. data/lib/liquid/file_system.rb +17 -15
  14. data/lib/liquid/forloop_drop.rb +92 -0
  15. data/lib/liquid/i18n.rb +10 -8
  16. data/lib/liquid/interrupts.rb +4 -3
  17. data/lib/liquid/lexer.rb +37 -26
  18. data/lib/liquid/locales/en.yml +13 -6
  19. data/lib/liquid/parse_context.rb +54 -0
  20. data/lib/liquid/parse_tree_visitor.rb +42 -0
  21. data/lib/liquid/parser.rb +30 -18
  22. data/lib/liquid/parser_switching.rb +20 -6
  23. data/lib/liquid/partial_cache.rb +24 -0
  24. data/lib/liquid/profiler/hooks.rb +26 -14
  25. data/lib/liquid/profiler.rb +72 -92
  26. data/lib/liquid/range_lookup.rb +28 -3
  27. data/lib/liquid/registers.rb +51 -0
  28. data/lib/liquid/resource_limits.rb +62 -0
  29. data/lib/liquid/standardfilters.rb +715 -132
  30. data/lib/liquid/strainer_factory.rb +41 -0
  31. data/lib/liquid/strainer_template.rb +62 -0
  32. data/lib/liquid/tablerowloop_drop.rb +121 -0
  33. data/lib/liquid/tag/disableable.rb +22 -0
  34. data/lib/liquid/tag/disabler.rb +21 -0
  35. data/lib/liquid/tag.rb +35 -12
  36. data/lib/liquid/tags/assign.rb +57 -18
  37. data/lib/liquid/tags/break.rb +15 -5
  38. data/lib/liquid/tags/capture.rb +24 -18
  39. data/lib/liquid/tags/case.rb +79 -30
  40. data/lib/liquid/tags/comment.rb +19 -4
  41. data/lib/liquid/tags/continue.rb +16 -12
  42. data/lib/liquid/tags/cycle.rb +47 -27
  43. data/lib/liquid/tags/decrement.rb +23 -24
  44. data/lib/liquid/tags/echo.rb +41 -0
  45. data/lib/liquid/tags/for.rb +155 -124
  46. data/lib/liquid/tags/if.rb +97 -63
  47. data/lib/liquid/tags/ifchanged.rb +11 -12
  48. data/lib/liquid/tags/include.rb +82 -73
  49. data/lib/liquid/tags/increment.rb +23 -17
  50. data/lib/liquid/tags/inline_comment.rb +43 -0
  51. data/lib/liquid/tags/raw.rb +50 -8
  52. data/lib/liquid/tags/render.rb +109 -0
  53. data/lib/liquid/tags/table_row.rb +57 -41
  54. data/lib/liquid/tags/unless.rb +38 -20
  55. data/lib/liquid/template.rb +71 -103
  56. data/lib/liquid/template_factory.rb +9 -0
  57. data/lib/liquid/tokenizer.rb +39 -0
  58. data/lib/liquid/usage.rb +8 -0
  59. data/lib/liquid/utils.rb +63 -9
  60. data/lib/liquid/variable.rb +74 -56
  61. data/lib/liquid/variable_lookup.rb +31 -15
  62. data/lib/liquid/version.rb +3 -1
  63. data/lib/liquid.rb +27 -12
  64. metadata +30 -106
  65. data/lib/liquid/module_ex.rb +0 -62
  66. data/lib/liquid/strainer.rb +0 -59
  67. data/lib/liquid/token.rb +0 -18
  68. data/test/fixtures/en_locale.yml +0 -9
  69. data/test/integration/assign_test.rb +0 -48
  70. data/test/integration/blank_test.rb +0 -106
  71. data/test/integration/capture_test.rb +0 -50
  72. data/test/integration/context_test.rb +0 -32
  73. data/test/integration/drop_test.rb +0 -271
  74. data/test/integration/error_handling_test.rb +0 -207
  75. data/test/integration/filter_test.rb +0 -138
  76. data/test/integration/hash_ordering_test.rb +0 -23
  77. data/test/integration/output_test.rb +0 -124
  78. data/test/integration/parsing_quirks_test.rb +0 -116
  79. data/test/integration/render_profiling_test.rb +0 -154
  80. data/test/integration/security_test.rb +0 -64
  81. data/test/integration/standard_filter_test.rb +0 -396
  82. data/test/integration/tags/break_tag_test.rb +0 -16
  83. data/test/integration/tags/continue_tag_test.rb +0 -16
  84. data/test/integration/tags/for_tag_test.rb +0 -375
  85. data/test/integration/tags/if_else_tag_test.rb +0 -190
  86. data/test/integration/tags/include_tag_test.rb +0 -234
  87. data/test/integration/tags/increment_tag_test.rb +0 -24
  88. data/test/integration/tags/raw_tag_test.rb +0 -25
  89. data/test/integration/tags/standard_tag_test.rb +0 -297
  90. data/test/integration/tags/statements_test.rb +0 -113
  91. data/test/integration/tags/table_row_test.rb +0 -63
  92. data/test/integration/tags/unless_else_tag_test.rb +0 -26
  93. data/test/integration/template_test.rb +0 -182
  94. data/test/integration/variable_test.rb +0 -82
  95. data/test/test_helper.rb +0 -89
  96. data/test/unit/block_unit_test.rb +0 -55
  97. data/test/unit/condition_unit_test.rb +0 -149
  98. data/test/unit/context_unit_test.rb +0 -492
  99. data/test/unit/file_system_unit_test.rb +0 -35
  100. data/test/unit/i18n_unit_test.rb +0 -37
  101. data/test/unit/lexer_unit_test.rb +0 -48
  102. data/test/unit/module_ex_unit_test.rb +0 -87
  103. data/test/unit/parser_unit_test.rb +0 -82
  104. data/test/unit/regexp_unit_test.rb +0 -44
  105. data/test/unit/strainer_unit_test.rb +0 -69
  106. data/test/unit/tag_unit_test.rb +0 -16
  107. data/test/unit/tags/case_tag_unit_test.rb +0 -10
  108. data/test/unit/tags/for_tag_unit_test.rb +0 -13
  109. data/test/unit/tags/if_tag_unit_test.rb +0 -8
  110. data/test/unit/template_unit_test.rb +0 -69
  111. data/test/unit/tokenizer_unit_test.rb +0 -38
  112. data/test/unit/variable_unit_test.rb +0 -145
  113. /data/{MIT-LICENSE → LICENSE} +0 -0
@@ -1,271 +0,0 @@
1
- require 'test_helper'
2
-
3
- class ContextDrop < Liquid::Drop
4
- def scopes
5
- @context.scopes.size
6
- end
7
-
8
- def scopes_as_array
9
- (1..@context.scopes.size).to_a
10
- end
11
-
12
- def loop_pos
13
- @context['forloop.index']
14
- end
15
-
16
- def before_method(method)
17
- return @context[method]
18
- end
19
- end
20
-
21
- class ProductDrop < Liquid::Drop
22
-
23
- class TextDrop < Liquid::Drop
24
- def array
25
- ['text1', 'text2']
26
- end
27
-
28
- def text
29
- 'text1'
30
- end
31
- end
32
-
33
- class CatchallDrop < Liquid::Drop
34
- def before_method(method)
35
- return 'method: ' << method.to_s
36
- end
37
- end
38
-
39
- def texts
40
- TextDrop.new
41
- end
42
-
43
- def catchall
44
- CatchallDrop.new
45
- end
46
-
47
- def context
48
- ContextDrop.new
49
- end
50
-
51
- def user_input
52
- "foo".taint
53
- end
54
-
55
- protected
56
- def callmenot
57
- "protected"
58
- end
59
- end
60
-
61
- class EnumerableDrop < Liquid::Drop
62
- def before_method(method)
63
- method
64
- end
65
-
66
- def size
67
- 3
68
- end
69
-
70
- def first
71
- 1
72
- end
73
-
74
- def count
75
- 3
76
- end
77
-
78
- def min
79
- 1
80
- end
81
-
82
- def max
83
- 3
84
- end
85
-
86
- def each
87
- yield 1
88
- yield 2
89
- yield 3
90
- end
91
- end
92
-
93
- class RealEnumerableDrop < Liquid::Drop
94
- include Enumerable
95
-
96
- def before_method(method)
97
- method
98
- end
99
-
100
- def each
101
- yield 1
102
- yield 2
103
- yield 3
104
- end
105
- end
106
-
107
- class DropsTest < Minitest::Test
108
- include Liquid
109
-
110
- def test_product_drop
111
- tpl = Liquid::Template.parse(' ')
112
- assert_equal ' ', tpl.render!('product' => ProductDrop.new)
113
- end
114
-
115
- def test_rendering_raises_on_tainted_attr
116
- with_taint_mode(:error) do
117
- tpl = Liquid::Template.parse('{{ product.user_input }}')
118
- assert_raises TaintedError do
119
- tpl.render!('product' => ProductDrop.new)
120
- end
121
- end
122
- end
123
-
124
- def test_rendering_warns_on_tainted_attr
125
- with_taint_mode(:warn) do
126
- tpl = Liquid::Template.parse('{{ product.user_input }}')
127
- tpl.render!('product' => ProductDrop.new)
128
- assert_match /tainted/, tpl.warnings.first
129
- end
130
- end
131
-
132
- def test_rendering_doesnt_raise_on_escaped_tainted_attr
133
- with_taint_mode(:error) do
134
- tpl = Liquid::Template.parse('{{ product.user_input | escape }}')
135
- tpl.render!('product' => ProductDrop.new)
136
- end
137
- end
138
-
139
- def test_drop_does_only_respond_to_whitelisted_methods
140
- assert_equal "", Liquid::Template.parse("{{ product.inspect }}").render!('product' => ProductDrop.new)
141
- assert_equal "", Liquid::Template.parse("{{ product.pretty_inspect }}").render!('product' => ProductDrop.new)
142
- assert_equal "", Liquid::Template.parse("{{ product.whatever }}").render!('product' => ProductDrop.new)
143
- assert_equal "", Liquid::Template.parse('{{ product | map: "inspect" }}').render!('product' => ProductDrop.new)
144
- assert_equal "", Liquid::Template.parse('{{ product | map: "pretty_inspect" }}').render!('product' => ProductDrop.new)
145
- assert_equal "", Liquid::Template.parse('{{ product | map: "whatever" }}').render!('product' => ProductDrop.new)
146
- end
147
-
148
- def test_drops_respond_to_to_liquid
149
- assert_equal "text1", Liquid::Template.parse("{{ product.to_liquid.texts.text }}").render!('product' => ProductDrop.new)
150
- assert_equal "text1", Liquid::Template.parse('{{ product | map: "to_liquid" | map: "texts" | map: "text" }}').render!('product' => ProductDrop.new)
151
- end
152
-
153
- def test_text_drop
154
- output = Liquid::Template.parse( ' {{ product.texts.text }} ' ).render!('product' => ProductDrop.new)
155
- assert_equal ' text1 ', output
156
- end
157
-
158
- def test_unknown_method
159
- output = Liquid::Template.parse( ' {{ product.catchall.unknown }} ' ).render!('product' => ProductDrop.new)
160
- assert_equal ' method: unknown ', output
161
- end
162
-
163
- def test_integer_argument_drop
164
- output = Liquid::Template.parse( ' {{ product.catchall[8] }} ' ).render!('product' => ProductDrop.new)
165
- assert_equal ' method: 8 ', output
166
- end
167
-
168
- def test_text_array_drop
169
- output = Liquid::Template.parse( '{% for text in product.texts.array %} {{text}} {% endfor %}' ).render!('product' => ProductDrop.new)
170
- assert_equal ' text1 text2 ', output
171
- end
172
-
173
- def test_context_drop
174
- output = Liquid::Template.parse( ' {{ context.bar }} ' ).render!('context' => ContextDrop.new, 'bar' => "carrot")
175
- assert_equal ' carrot ', output
176
- end
177
-
178
- def test_nested_context_drop
179
- output = Liquid::Template.parse( ' {{ product.context.foo }} ' ).render!('product' => ProductDrop.new, 'foo' => "monkey")
180
- assert_equal ' monkey ', output
181
- end
182
-
183
- def test_protected
184
- output = Liquid::Template.parse( ' {{ product.callmenot }} ' ).render!('product' => ProductDrop.new)
185
- assert_equal ' ', output
186
- end
187
-
188
- def test_object_methods_not_allowed
189
- [:dup, :clone, :singleton_class, :eval, :class_eval, :inspect].each do |method|
190
- output = Liquid::Template.parse(" {{ product.#{method} }} ").render!('product' => ProductDrop.new)
191
- assert_equal ' ', output
192
- end
193
- end
194
-
195
- def test_scope
196
- assert_equal '1', Liquid::Template.parse( '{{ context.scopes }}' ).render!('context' => ContextDrop.new)
197
- assert_equal '2', Liquid::Template.parse( '{%for i in dummy%}{{ context.scopes }}{%endfor%}' ).render!('context' => ContextDrop.new, 'dummy' => [1])
198
- assert_equal '3', Liquid::Template.parse( '{%for i in dummy%}{%for i in dummy%}{{ context.scopes }}{%endfor%}{%endfor%}' ).render!('context' => ContextDrop.new, 'dummy' => [1])
199
- end
200
-
201
- def test_scope_though_proc
202
- assert_equal '1', Liquid::Template.parse( '{{ s }}' ).render!('context' => ContextDrop.new, 's' => Proc.new{|c| c['context.scopes'] })
203
- assert_equal '2', Liquid::Template.parse( '{%for i in dummy%}{{ s }}{%endfor%}' ).render!('context' => ContextDrop.new, 's' => Proc.new{|c| c['context.scopes'] }, 'dummy' => [1])
204
- assert_equal '3', Liquid::Template.parse( '{%for i in dummy%}{%for i in dummy%}{{ s }}{%endfor%}{%endfor%}' ).render!('context' => ContextDrop.new, 's' => Proc.new{|c| c['context.scopes'] }, 'dummy' => [1])
205
- end
206
-
207
- def test_scope_with_assigns
208
- assert_equal 'variable', Liquid::Template.parse( '{% assign a = "variable"%}{{a}}' ).render!('context' => ContextDrop.new)
209
- assert_equal 'variable', Liquid::Template.parse( '{% assign a = "variable"%}{%for i in dummy%}{{a}}{%endfor%}' ).render!('context' => ContextDrop.new, 'dummy' => [1])
210
- assert_equal 'test', Liquid::Template.parse( '{% assign header_gif = "test"%}{{header_gif}}' ).render!('context' => ContextDrop.new)
211
- assert_equal 'test', Liquid::Template.parse( "{% assign header_gif = 'test'%}{{header_gif}}" ).render!('context' => ContextDrop.new)
212
- end
213
-
214
- def test_scope_from_tags
215
- assert_equal '1', Liquid::Template.parse( '{% for i in context.scopes_as_array %}{{i}}{% endfor %}' ).render!('context' => ContextDrop.new, 'dummy' => [1])
216
- assert_equal '12', Liquid::Template.parse( '{%for a in dummy%}{% for i in context.scopes_as_array %}{{i}}{% endfor %}{% endfor %}' ).render!('context' => ContextDrop.new, 'dummy' => [1])
217
- assert_equal '123', Liquid::Template.parse( '{%for a in dummy%}{%for a in dummy%}{% for i in context.scopes_as_array %}{{i}}{% endfor %}{% endfor %}{% endfor %}' ).render!('context' => ContextDrop.new, 'dummy' => [1])
218
- end
219
-
220
- def test_access_context_from_drop
221
- assert_equal '123', Liquid::Template.parse( '{%for a in dummy%}{{ context.loop_pos }}{% endfor %}' ).render!('context' => ContextDrop.new, 'dummy' => [1,2,3])
222
- end
223
-
224
- def test_enumerable_drop
225
- assert_equal '123', Liquid::Template.parse( '{% for c in collection %}{{c}}{% endfor %}').render!('collection' => EnumerableDrop.new)
226
- end
227
-
228
- def test_enumerable_drop_size
229
- assert_equal '3', Liquid::Template.parse( '{{collection.size}}').render!('collection' => EnumerableDrop.new)
230
- end
231
-
232
- def test_enumerable_drop_will_invoke_before_method_for_clashing_method_names
233
- ["select", "each", "map", "cycle"].each do |method|
234
- assert_equal method.to_s, Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
235
- assert_equal method.to_s, Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
236
- assert_equal method.to_s, Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
237
- assert_equal method.to_s, Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
238
- end
239
- end
240
-
241
- def test_some_enumerable_methods_still_get_invoked
242
- [ :count, :max ].each do |method|
243
- assert_equal "3", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
244
- assert_equal "3", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
245
- assert_equal "3", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
246
- assert_equal "3", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
247
- end
248
-
249
- assert_equal "yes", Liquid::Template.parse("{% if collection contains 3 %}yes{% endif %}").render!('collection' => RealEnumerableDrop.new)
250
-
251
- [ :min, :first ].each do |method|
252
- assert_equal "1", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
253
- assert_equal "1", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
254
- assert_equal "1", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
255
- assert_equal "1", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
256
- end
257
- end
258
-
259
- def test_empty_string_value_access
260
- assert_equal '', Liquid::Template.parse('{{ product[value] }}').render!('product' => ProductDrop.new, 'value' => '')
261
- end
262
-
263
- def test_nil_value_access
264
- assert_equal '', Liquid::Template.parse('{{ product[value] }}').render!('product' => ProductDrop.new, 'value' => nil)
265
- end
266
-
267
- def test_default_to_s_on_drops
268
- assert_equal 'ProductDrop', Liquid::Template.parse("{{ product }}").render!('product' => ProductDrop.new)
269
- assert_equal 'EnumerableDrop', Liquid::Template.parse('{{ collection }}').render!('collection' => EnumerableDrop.new)
270
- end
271
- end # DropsTest
@@ -1,207 +0,0 @@
1
- require 'test_helper'
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
- class ErrorHandlingTest < Minitest::Test
23
- include Liquid
24
-
25
- def test_templates_parsed_with_line_numbers_renders_them_in_errors
26
- template = <<-LIQUID
27
- Hello,
28
-
29
- {{ errors.standard_error }} will raise a standard error.
30
-
31
- Bla bla test.
32
-
33
- {{ errors.syntax_error }} will raise a syntax error.
34
-
35
- This is an argument error: {{ errors.argument_error }}
36
-
37
- Bla.
38
- LIQUID
39
-
40
- expected = <<-TEXT
41
- Hello,
42
-
43
- Liquid error (line 3): standard error will raise a standard error.
44
-
45
- Bla bla test.
46
-
47
- Liquid syntax error (line 7): syntax error will raise a syntax error.
48
-
49
- This is an argument error: Liquid error (line 9): argument error
50
-
51
- Bla.
52
- TEXT
53
-
54
- output = Liquid::Template.parse(template, line_numbers: true).render('errors' => ErrorDrop.new)
55
- assert_equal expected, output
56
- end
57
-
58
- def test_standard_error
59
- template = Liquid::Template.parse( ' {{ errors.standard_error }} ' )
60
- assert_equal ' Liquid error: standard error ', template.render('errors' => ErrorDrop.new)
61
-
62
- assert_equal 1, template.errors.size
63
- assert_equal StandardError, template.errors.first.class
64
- end
65
-
66
- def test_syntax
67
- template = Liquid::Template.parse( ' {{ errors.syntax_error }} ' )
68
- assert_equal ' Liquid syntax error: syntax error ', template.render('errors' => ErrorDrop.new)
69
-
70
- assert_equal 1, template.errors.size
71
- assert_equal SyntaxError, template.errors.first.class
72
- end
73
-
74
- def test_argument
75
- template = Liquid::Template.parse( ' {{ errors.argument_error }} ' )
76
- assert_equal ' Liquid error: argument error ', template.render('errors' => ErrorDrop.new)
77
-
78
- assert_equal 1, template.errors.size
79
- assert_equal ArgumentError, template.errors.first.class
80
- end
81
-
82
- def test_missing_endtag_parse_time_error
83
- assert_raises(Liquid::SyntaxError) do
84
- Liquid::Template.parse(' {% for a in b %} ... ')
85
- end
86
- end
87
-
88
- def test_unrecognized_operator
89
- with_error_mode(:strict) do
90
- assert_raises(SyntaxError) do
91
- Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ')
92
- end
93
- end
94
- end
95
-
96
- def test_lax_unrecognized_operator
97
- template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', :error_mode => :lax)
98
- assert_equal ' Liquid error: Unknown operator =! ', template.render
99
- assert_equal 1, template.errors.size
100
- assert_equal Liquid::ArgumentError, template.errors.first.class
101
- end
102
-
103
- def test_with_line_numbers_adds_numbers_to_parser_errors
104
- err = assert_raises(SyntaxError) do
105
- template = Liquid::Template.parse(%q{
106
- foobar
107
-
108
- {% "cat" | foobar %}
109
-
110
- bla
111
- },
112
- :line_numbers => true
113
- )
114
- end
115
-
116
- assert_match /Liquid syntax error \(line 4\)/, err.message
117
- end
118
-
119
- def test_parsing_warn_with_line_numbers_adds_numbers_to_lexer_errors
120
- template = Liquid::Template.parse(%q{
121
- foobar
122
-
123
- {% if 1 =! 2 %}ok{% endif %}
124
-
125
- bla
126
- },
127
- :error_mode => :warn,
128
- :line_numbers => true
129
- )
130
-
131
- assert_equal ['Liquid syntax error (line 4): Unexpected character = in "1 =! 2"'],
132
- template.warnings.map(&:message)
133
- end
134
-
135
- def test_parsing_strict_with_line_numbers_adds_numbers_to_lexer_errors
136
- err = assert_raises(SyntaxError) do
137
- Liquid::Template.parse(%q{
138
- foobar
139
-
140
- {% if 1 =! 2 %}ok{% endif %}
141
-
142
- bla
143
- },
144
- :error_mode => :strict,
145
- :line_numbers => true
146
- )
147
- end
148
-
149
- assert_equal 'Liquid syntax error (line 4): Unexpected character = in "1 =! 2"', err.message
150
- end
151
-
152
- def test_syntax_errors_in_nested_blocks_have_correct_line_number
153
- err = assert_raises(SyntaxError) do
154
- Liquid::Template.parse(%q{
155
- foobar
156
-
157
- {% if 1 != 2 %}
158
- {% foo %}
159
- {% endif %}
160
-
161
- bla
162
- },
163
- :line_numbers => true
164
- )
165
- end
166
-
167
- assert_equal "Liquid syntax error (line 5): Unknown tag 'foo'", err.message
168
- end
169
-
170
- def test_strict_error_messages
171
- err = assert_raises(SyntaxError) do
172
- Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', :error_mode => :strict)
173
- end
174
- assert_equal 'Liquid syntax error: Unexpected character = in "1 =! 2"', err.message
175
-
176
- err = assert_raises(SyntaxError) do
177
- Liquid::Template.parse('{{%%%}}', :error_mode => :strict)
178
- end
179
- assert_equal 'Liquid syntax error: Unexpected character % in "{{%%%}}"', err.message
180
- end
181
-
182
- def test_warnings
183
- template = Liquid::Template.parse('{% if ~~~ %}{{%%%}}{% else %}{{ hello. }}{% endif %}', :error_mode => :warn)
184
- assert_equal 3, template.warnings.size
185
- assert_equal 'Unexpected character ~ in "~~~"', template.warnings[0].to_s(false)
186
- assert_equal 'Unexpected character % in "{{%%%}}"', template.warnings[1].to_s(false)
187
- assert_equal 'Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].to_s(false)
188
- assert_equal '', template.render
189
- end
190
-
191
- def test_warning_line_numbers
192
- template = Liquid::Template.parse("{% if ~~~ %}\n{{%%%}}{% else %}\n{{ hello. }}{% endif %}", :error_mode => :warn, :line_numbers => true)
193
- assert_equal 'Liquid syntax error (line 1): Unexpected character ~ in "~~~"', template.warnings[0].message
194
- assert_equal 'Liquid syntax error (line 2): Unexpected character % in "{{%%%}}"', template.warnings[1].message
195
- assert_equal 'Liquid syntax error (line 3): Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].message
196
- assert_equal 3, template.warnings.size
197
- assert_equal [1,2,3], template.warnings.map(&:line_number)
198
- end
199
-
200
- # Liquid should not catch Exceptions that are not subclasses of StandardError, like Interrupt and NoMemoryError
201
- def test_exceptions_propagate
202
- assert_raises Exception do
203
- template = Liquid::Template.parse('{{ errors.exception }}')
204
- template.render('errors' => ErrorDrop.new)
205
- end
206
- end
207
- end
@@ -1,138 +0,0 @@
1
- require 'test_helper'
2
-
3
- module MoneyFilter
4
- def money(input)
5
- sprintf(' %d$ ', input)
6
- end
7
-
8
- def money_with_underscore(input)
9
- sprintf(' %d$ ', input)
10
- end
11
- end
12
-
13
- module CanadianMoneyFilter
14
- def money(input)
15
- sprintf(' %d$ CAD ', input)
16
- end
17
- end
18
-
19
- module SubstituteFilter
20
- def substitute(input, params={})
21
- input.gsub(/%\{(\w+)\}/) { |match| params[$1] }
22
- end
23
- end
24
-
25
- class FiltersTest < Minitest::Test
26
- include Liquid
27
-
28
- module OverrideObjectMethodFilter
29
- def tap(input)
30
- "tap overridden"
31
- end
32
- end
33
-
34
- def setup
35
- @context = Context.new
36
- end
37
-
38
- def test_local_filter
39
- @context['var'] = 1000
40
- @context.add_filters(MoneyFilter)
41
-
42
- assert_equal ' 1000$ ', Variable.new("var | money").render(@context)
43
- end
44
-
45
- def test_underscore_in_filter_name
46
- @context['var'] = 1000
47
- @context.add_filters(MoneyFilter)
48
- assert_equal ' 1000$ ', Variable.new("var | money_with_underscore").render(@context)
49
- end
50
-
51
- def test_second_filter_overwrites_first
52
- @context['var'] = 1000
53
- @context.add_filters(MoneyFilter)
54
- @context.add_filters(CanadianMoneyFilter)
55
-
56
- assert_equal ' 1000$ CAD ', Variable.new("var | money").render(@context)
57
- end
58
-
59
- def test_size
60
- @context['var'] = 'abcd'
61
- @context.add_filters(MoneyFilter)
62
-
63
- assert_equal 4, Variable.new("var | size").render(@context)
64
- end
65
-
66
- def test_join
67
- @context['var'] = [1,2,3,4]
68
-
69
- assert_equal "1 2 3 4", Variable.new("var | join").render(@context)
70
- end
71
-
72
- def test_sort
73
- @context['value'] = 3
74
- @context['numbers'] = [2,1,4,3]
75
- @context['words'] = ['expected', 'as', 'alphabetic']
76
- @context['arrays'] = ['flower', 'are']
77
-
78
- assert_equal [1,2,3,4], Variable.new("numbers | sort").render(@context)
79
- assert_equal ['alphabetic', 'as', 'expected'], Variable.new("words | sort").render(@context)
80
- assert_equal [3], Variable.new("value | sort").render(@context)
81
- assert_equal ['are', 'flower'], Variable.new("arrays | sort").render(@context)
82
- end
83
-
84
- def test_strip_html
85
- @context['var'] = "<b>bla blub</a>"
86
-
87
- assert_equal "bla blub", Variable.new("var | strip_html").render(@context)
88
- end
89
-
90
- def test_strip_html_ignore_comments_with_html
91
- @context['var'] = "<!-- split and some <ul> tag --><b>bla blub</a>"
92
-
93
- assert_equal "bla blub", Variable.new("var | strip_html").render(@context)
94
- end
95
-
96
- def test_capitalize
97
- @context['var'] = "blub"
98
-
99
- assert_equal "Blub", Variable.new("var | capitalize").render(@context)
100
- end
101
-
102
- def test_nonexistent_filter_is_ignored
103
- @context['var'] = 1000
104
-
105
- assert_equal 1000, Variable.new("var | xyzzy").render(@context)
106
- end
107
-
108
- def test_filter_with_keyword_arguments
109
- @context['surname'] = 'john'
110
- @context.add_filters(SubstituteFilter)
111
- output = Variable.new(%! 'hello %{first_name}, %{last_name}' | substitute: first_name: surname, last_name: 'doe' !).render(@context)
112
- assert_equal 'hello john, doe', output
113
- end
114
-
115
- def test_override_object_method_in_filter
116
- assert_equal "tap overridden", Template.parse("{{var | tap}}").render!({ 'var' => 1000 }, :filters => [OverrideObjectMethodFilter])
117
-
118
- # tap still treated as a non-existent filter
119
- assert_equal "1000", Template.parse("{{var | tap}}").render!({ 'var' => 1000 })
120
- end
121
- end
122
-
123
- class FiltersInTemplate < Minitest::Test
124
- include Liquid
125
-
126
- def test_local_global
127
- with_global_filter(MoneyFilter) do
128
- assert_equal " 1000$ ", Template.parse("{{1000 | money}}").render!(nil, nil)
129
- assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, :filters => CanadianMoneyFilter)
130
- assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, :filters => [CanadianMoneyFilter])
131
- end
132
- end
133
-
134
- def test_local_filter_with_deprecated_syntax
135
- assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, CanadianMoneyFilter)
136
- assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, [CanadianMoneyFilter])
137
- end
138
- end # FiltersTest
@@ -1,23 +0,0 @@
1
- require 'test_helper'
2
-
3
- module MoneyFilter
4
- def money(input)
5
- sprintf(' %d$ ', input)
6
- end
7
- end
8
-
9
- module CanadianMoneyFilter
10
- def money(input)
11
- sprintf(' %d$ CAD ', input)
12
- end
13
- end
14
-
15
- class HashOrderingTest < Minitest::Test
16
- include Liquid
17
-
18
- def test_global_register_order
19
- with_global_filter(MoneyFilter, CanadianMoneyFilter) do
20
- assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, nil)
21
- end
22
- end
23
- end