liquid 2.6.1 → 4.0.3

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 (130) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +194 -29
  3. data/{MIT-LICENSE → LICENSE} +0 -0
  4. data/README.md +60 -2
  5. data/lib/liquid.rb +25 -14
  6. data/lib/liquid/block.rb +47 -96
  7. data/lib/liquid/block_body.rb +143 -0
  8. data/lib/liquid/condition.rb +70 -39
  9. data/lib/liquid/context.rb +116 -157
  10. data/lib/liquid/document.rb +19 -9
  11. data/lib/liquid/drop.rb +31 -14
  12. data/lib/liquid/errors.rb +54 -10
  13. data/lib/liquid/expression.rb +49 -0
  14. data/lib/liquid/extensions.rb +19 -7
  15. data/lib/liquid/file_system.rb +25 -14
  16. data/lib/liquid/forloop_drop.rb +42 -0
  17. data/lib/liquid/i18n.rb +39 -0
  18. data/lib/liquid/interrupts.rb +2 -3
  19. data/lib/liquid/lexer.rb +55 -0
  20. data/lib/liquid/locales/en.yml +26 -0
  21. data/lib/liquid/parse_context.rb +38 -0
  22. data/lib/liquid/parse_tree_visitor.rb +42 -0
  23. data/lib/liquid/parser.rb +90 -0
  24. data/lib/liquid/parser_switching.rb +31 -0
  25. data/lib/liquid/profiler.rb +158 -0
  26. data/lib/liquid/profiler/hooks.rb +23 -0
  27. data/lib/liquid/range_lookup.rb +37 -0
  28. data/lib/liquid/resource_limits.rb +23 -0
  29. data/lib/liquid/standardfilters.rb +311 -77
  30. data/lib/liquid/strainer.rb +39 -26
  31. data/lib/liquid/tablerowloop_drop.rb +62 -0
  32. data/lib/liquid/tag.rb +28 -11
  33. data/lib/liquid/tags/assign.rb +34 -10
  34. data/lib/liquid/tags/break.rb +1 -4
  35. data/lib/liquid/tags/capture.rb +11 -9
  36. data/lib/liquid/tags/case.rb +37 -22
  37. data/lib/liquid/tags/comment.rb +10 -3
  38. data/lib/liquid/tags/continue.rb +1 -4
  39. data/lib/liquid/tags/cycle.rb +20 -14
  40. data/lib/liquid/tags/decrement.rb +4 -8
  41. data/lib/liquid/tags/for.rb +121 -60
  42. data/lib/liquid/tags/if.rb +73 -30
  43. data/lib/liquid/tags/ifchanged.rb +3 -5
  44. data/lib/liquid/tags/include.rb +77 -46
  45. data/lib/liquid/tags/increment.rb +4 -8
  46. data/lib/liquid/tags/raw.rb +35 -10
  47. data/lib/liquid/tags/table_row.rb +62 -0
  48. data/lib/liquid/tags/unless.rb +6 -9
  49. data/lib/liquid/template.rb +130 -32
  50. data/lib/liquid/tokenizer.rb +31 -0
  51. data/lib/liquid/truffle.rb +5 -0
  52. data/lib/liquid/utils.rb +57 -4
  53. data/lib/liquid/variable.rb +121 -30
  54. data/lib/liquid/variable_lookup.rb +88 -0
  55. data/lib/liquid/version.rb +2 -1
  56. data/test/fixtures/en_locale.yml +9 -0
  57. data/test/integration/assign_test.rb +48 -0
  58. data/test/integration/blank_test.rb +106 -0
  59. data/test/integration/block_test.rb +12 -0
  60. data/test/{liquid → integration}/capture_test.rb +13 -3
  61. data/test/integration/context_test.rb +32 -0
  62. data/test/integration/document_test.rb +19 -0
  63. data/test/integration/drop_test.rb +273 -0
  64. data/test/integration/error_handling_test.rb +260 -0
  65. data/test/integration/filter_test.rb +178 -0
  66. data/test/integration/hash_ordering_test.rb +23 -0
  67. data/test/integration/output_test.rb +123 -0
  68. data/test/integration/parse_tree_visitor_test.rb +247 -0
  69. data/test/integration/parsing_quirks_test.rb +122 -0
  70. data/test/integration/render_profiling_test.rb +154 -0
  71. data/test/integration/security_test.rb +80 -0
  72. data/test/integration/standard_filter_test.rb +776 -0
  73. data/test/{liquid → integration}/tags/break_tag_test.rb +2 -3
  74. data/test/{liquid → integration}/tags/continue_tag_test.rb +1 -2
  75. data/test/integration/tags/for_tag_test.rb +410 -0
  76. data/test/integration/tags/if_else_tag_test.rb +188 -0
  77. data/test/integration/tags/include_tag_test.rb +253 -0
  78. data/test/integration/tags/increment_tag_test.rb +23 -0
  79. data/test/{liquid → integration}/tags/raw_tag_test.rb +9 -2
  80. data/test/integration/tags/standard_tag_test.rb +296 -0
  81. data/test/integration/tags/statements_test.rb +111 -0
  82. data/test/{liquid/tags/html_tag_test.rb → integration/tags/table_row_test.rb} +25 -24
  83. data/test/integration/tags/unless_else_tag_test.rb +26 -0
  84. data/test/integration/template_test.rb +332 -0
  85. data/test/integration/trim_mode_test.rb +529 -0
  86. data/test/integration/variable_test.rb +96 -0
  87. data/test/test_helper.rb +106 -19
  88. data/test/truffle/truffle_test.rb +9 -0
  89. data/test/{liquid/block_test.rb → unit/block_unit_test.rb} +9 -9
  90. data/test/unit/condition_unit_test.rb +166 -0
  91. data/test/{liquid/context_test.rb → unit/context_unit_test.rb} +85 -74
  92. data/test/unit/file_system_unit_test.rb +35 -0
  93. data/test/unit/i18n_unit_test.rb +37 -0
  94. data/test/unit/lexer_unit_test.rb +51 -0
  95. data/test/unit/parser_unit_test.rb +82 -0
  96. data/test/{liquid/regexp_test.rb → unit/regexp_unit_test.rb} +4 -4
  97. data/test/unit/strainer_unit_test.rb +164 -0
  98. data/test/unit/tag_unit_test.rb +21 -0
  99. data/test/unit/tags/case_tag_unit_test.rb +10 -0
  100. data/test/unit/tags/for_tag_unit_test.rb +13 -0
  101. data/test/unit/tags/if_tag_unit_test.rb +8 -0
  102. data/test/unit/template_unit_test.rb +78 -0
  103. data/test/unit/tokenizer_unit_test.rb +55 -0
  104. data/test/unit/variable_unit_test.rb +162 -0
  105. metadata +157 -77
  106. data/lib/extras/liquid_view.rb +0 -51
  107. data/lib/liquid/htmltags.rb +0 -74
  108. data/lib/liquid/module_ex.rb +0 -62
  109. data/test/liquid/assign_test.rb +0 -21
  110. data/test/liquid/condition_test.rb +0 -127
  111. data/test/liquid/drop_test.rb +0 -180
  112. data/test/liquid/error_handling_test.rb +0 -81
  113. data/test/liquid/file_system_test.rb +0 -29
  114. data/test/liquid/filter_test.rb +0 -125
  115. data/test/liquid/hash_ordering_test.rb +0 -25
  116. data/test/liquid/module_ex_test.rb +0 -87
  117. data/test/liquid/output_test.rb +0 -116
  118. data/test/liquid/parsing_quirks_test.rb +0 -52
  119. data/test/liquid/security_test.rb +0 -64
  120. data/test/liquid/standard_filter_test.rb +0 -251
  121. data/test/liquid/strainer_test.rb +0 -52
  122. data/test/liquid/tags/for_tag_test.rb +0 -297
  123. data/test/liquid/tags/if_else_tag_test.rb +0 -166
  124. data/test/liquid/tags/include_tag_test.rb +0 -166
  125. data/test/liquid/tags/increment_tag_test.rb +0 -24
  126. data/test/liquid/tags/standard_tag_test.rb +0 -295
  127. data/test/liquid/tags/statements_test.rb +0 -134
  128. data/test/liquid/tags/unless_else_tag_test.rb +0 -26
  129. data/test/liquid/template_test.rb +0 -146
  130. data/test/liquid/variable_test.rb +0 -186
@@ -0,0 +1,260 @@
1
+ require 'test_helper'
2
+
3
+ class ErrorHandlingTest < Minitest::Test
4
+ include Liquid
5
+
6
+ def test_templates_parsed_with_line_numbers_renders_them_in_errors
7
+ template = <<-LIQUID
8
+ Hello,
9
+
10
+ {{ errors.standard_error }} will raise a standard error.
11
+
12
+ Bla bla test.
13
+
14
+ {{ errors.syntax_error }} will raise a syntax error.
15
+
16
+ This is an argument error: {{ errors.argument_error }}
17
+
18
+ Bla.
19
+ LIQUID
20
+
21
+ expected = <<-TEXT
22
+ Hello,
23
+
24
+ Liquid error (line 3): standard error will raise a standard error.
25
+
26
+ Bla bla test.
27
+
28
+ Liquid syntax error (line 7): syntax error will raise a syntax error.
29
+
30
+ This is an argument error: Liquid error (line 9): argument error
31
+
32
+ Bla.
33
+ TEXT
34
+
35
+ output = Liquid::Template.parse(template, line_numbers: true).render('errors' => ErrorDrop.new)
36
+ assert_equal expected, output
37
+ end
38
+
39
+ def test_standard_error
40
+ template = Liquid::Template.parse(' {{ errors.standard_error }} ')
41
+ assert_equal ' Liquid error: standard error ', template.render('errors' => ErrorDrop.new)
42
+
43
+ assert_equal 1, template.errors.size
44
+ assert_equal StandardError, template.errors.first.class
45
+ end
46
+
47
+ def test_syntax
48
+ template = Liquid::Template.parse(' {{ errors.syntax_error }} ')
49
+ assert_equal ' Liquid syntax error: syntax error ', template.render('errors' => ErrorDrop.new)
50
+
51
+ assert_equal 1, template.errors.size
52
+ assert_equal SyntaxError, template.errors.first.class
53
+ end
54
+
55
+ def test_argument
56
+ template = Liquid::Template.parse(' {{ errors.argument_error }} ')
57
+ assert_equal ' Liquid error: argument error ', template.render('errors' => ErrorDrop.new)
58
+
59
+ assert_equal 1, template.errors.size
60
+ assert_equal ArgumentError, template.errors.first.class
61
+ end
62
+
63
+ def test_missing_endtag_parse_time_error
64
+ assert_raises(Liquid::SyntaxError) do
65
+ Liquid::Template.parse(' {% for a in b %} ... ')
66
+ end
67
+ end
68
+
69
+ def test_unrecognized_operator
70
+ with_error_mode(:strict) do
71
+ assert_raises(SyntaxError) do
72
+ Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ')
73
+ end
74
+ end
75
+ end
76
+
77
+ def test_lax_unrecognized_operator
78
+ template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', error_mode: :lax)
79
+ assert_equal ' Liquid error: Unknown operator =! ', template.render
80
+ assert_equal 1, template.errors.size
81
+ assert_equal Liquid::ArgumentError, template.errors.first.class
82
+ end
83
+
84
+ def test_with_line_numbers_adds_numbers_to_parser_errors
85
+ err = assert_raises(SyntaxError) do
86
+ Liquid::Template.parse(%q(
87
+ foobar
88
+
89
+ {% "cat" | foobar %}
90
+
91
+ bla
92
+ ),
93
+ line_numbers: true
94
+ )
95
+ end
96
+
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)
114
+ end
115
+
116
+ def test_parsing_warn_with_line_numbers_adds_numbers_to_lexer_errors
117
+ template = Liquid::Template.parse('
118
+ foobar
119
+
120
+ {% if 1 =! 2 %}ok{% endif %}
121
+
122
+ bla
123
+ ',
124
+ error_mode: :warn,
125
+ line_numbers: true
126
+ )
127
+
128
+ assert_equal ['Liquid syntax error (line 4): Unexpected character = in "1 =! 2"'],
129
+ template.warnings.map(&:message)
130
+ end
131
+
132
+ def test_parsing_strict_with_line_numbers_adds_numbers_to_lexer_errors
133
+ err = assert_raises(SyntaxError) do
134
+ Liquid::Template.parse('
135
+ foobar
136
+
137
+ {% if 1 =! 2 %}ok{% endif %}
138
+
139
+ bla
140
+ ',
141
+ error_mode: :strict,
142
+ line_numbers: true
143
+ )
144
+ end
145
+
146
+ assert_equal 'Liquid syntax error (line 4): Unexpected character = in "1 =! 2"', err.message
147
+ end
148
+
149
+ def test_syntax_errors_in_nested_blocks_have_correct_line_number
150
+ err = assert_raises(SyntaxError) do
151
+ Liquid::Template.parse('
152
+ foobar
153
+
154
+ {% if 1 != 2 %}
155
+ {% foo %}
156
+ {% endif %}
157
+
158
+ bla
159
+ ',
160
+ line_numbers: true
161
+ )
162
+ end
163
+
164
+ assert_equal "Liquid syntax error (line 5): Unknown tag 'foo'", err.message
165
+ end
166
+
167
+ def test_strict_error_messages
168
+ err = assert_raises(SyntaxError) do
169
+ Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', error_mode: :strict)
170
+ end
171
+ assert_equal 'Liquid syntax error: Unexpected character = in "1 =! 2"', err.message
172
+
173
+ err = assert_raises(SyntaxError) do
174
+ Liquid::Template.parse('{{%%%}}', error_mode: :strict)
175
+ end
176
+ assert_equal 'Liquid syntax error: Unexpected character % in "{{%%%}}"', err.message
177
+ end
178
+
179
+ def test_warnings
180
+ template = Liquid::Template.parse('{% if ~~~ %}{{%%%}}{% else %}{{ hello. }}{% endif %}', error_mode: :warn)
181
+ assert_equal 3, template.warnings.size
182
+ assert_equal 'Unexpected character ~ in "~~~"', template.warnings[0].to_s(false)
183
+ assert_equal 'Unexpected character % in "{{%%%}}"', template.warnings[1].to_s(false)
184
+ assert_equal 'Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].to_s(false)
185
+ assert_equal '', template.render
186
+ end
187
+
188
+ def test_warning_line_numbers
189
+ template = Liquid::Template.parse("{% if ~~~ %}\n{{%%%}}{% else %}\n{{ hello. }}{% endif %}", error_mode: :warn, line_numbers: true)
190
+ assert_equal 'Liquid syntax error (line 1): Unexpected character ~ in "~~~"', template.warnings[0].message
191
+ assert_equal 'Liquid syntax error (line 2): Unexpected character % in "{{%%%}}"', template.warnings[1].message
192
+ assert_equal 'Liquid syntax error (line 3): Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].message
193
+ assert_equal 3, template.warnings.size
194
+ assert_equal [1, 2, 3], template.warnings.map(&:line_number)
195
+ end
196
+
197
+ # Liquid should not catch Exceptions that are not subclasses of StandardError, like Interrupt and NoMemoryError
198
+ def test_exceptions_propagate
199
+ assert_raises Exception do
200
+ template = Liquid::Template.parse('{{ errors.exception }}')
201
+ template.render('errors' => ErrorDrop.new)
202
+ end
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
260
+ end
@@ -0,0 +1,178 @@
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$ ', Template.parse("{{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$ ', Template.parse("{{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 ', Template.parse("{{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', Template.parse("{{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", Template.parse("{{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
+ @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
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)
114
+ end
115
+
116
+ def test_strip_html
117
+ @context['var'] = "<b>bla blub</a>"
118
+
119
+ assert_equal "bla blub", Template.parse("{{ var | strip_html }}").render(@context)
120
+ end
121
+
122
+ def test_strip_html_ignore_comments_with_html
123
+ @context['var'] = "<!-- split and some <ul> tag --><b>bla blub</a>"
124
+
125
+ assert_equal "bla blub", Template.parse("{{ var | strip_html }}").render(@context)
126
+ end
127
+
128
+ def test_capitalize
129
+ @context['var'] = "blub"
130
+
131
+ assert_equal "Blub", Template.parse("{{ var | capitalize }}").render(@context)
132
+ end
133
+
134
+ def test_nonexistent_filter_is_ignored
135
+ @context['var'] = 1000
136
+
137
+ assert_equal '1000', Template.parse("{{ var | xyzzy }}").render(@context)
138
+ end
139
+
140
+ def test_filter_with_keyword_arguments
141
+ @context['surname'] = 'john'
142
+ @context['input'] = 'hello %{first_name}, %{last_name}'
143
+ @context.add_filters(SubstituteFilter)
144
+ output = Template.parse(%({{ input | substitute: first_name: surname, last_name: 'doe' }})).render(@context)
145
+ assert_equal 'hello john, doe', output
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
154
+ end
155
+
156
+ class FiltersInTemplate < Minitest::Test
157
+ include Liquid
158
+
159
+ def test_local_global
160
+ with_global_filter(MoneyFilter) do
161
+ assert_equal " 1000$ ", Template.parse("{{1000 | money}}").render!(nil, 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])
164
+ end
165
+ end
166
+
167
+ def test_local_filter_with_deprecated_syntax
168
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, CanadianMoneyFilter)
169
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, [CanadianMoneyFilter])
170
+ end
171
+ end # FiltersTest
172
+
173
+ class TestObject < Liquid::Drop
174
+ attr_accessor :a
175
+ def initialize(a)
176
+ @a = a
177
+ end
178
+ end
@@ -0,0 +1,23 @@
1
+ require 'test_helper'
2
+
3
+ class HashOrderingTest < Minitest::Test
4
+ module MoneyFilter
5
+ def money(input)
6
+ sprintf(' %d$ ', input)
7
+ end
8
+ end
9
+
10
+ module CanadianMoneyFilter
11
+ def money(input)
12
+ sprintf(' %d$ CAD ', input)
13
+ end
14
+ end
15
+
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