liquid 3.0.6 → 5.4.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.
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