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.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +98 -58
  3. data/README.md +31 -0
  4. data/lib/liquid/block.rb +31 -124
  5. data/lib/liquid/block_body.rb +75 -59
  6. data/lib/liquid/condition.rb +23 -22
  7. data/lib/liquid/context.rb +50 -46
  8. data/lib/liquid/document.rb +19 -9
  9. data/lib/liquid/drop.rb +17 -16
  10. data/lib/liquid/errors.rb +20 -24
  11. data/lib/liquid/expression.rb +15 -3
  12. data/lib/liquid/extensions.rb +13 -7
  13. data/lib/liquid/file_system.rb +11 -11
  14. data/lib/liquid/forloop_drop.rb +42 -0
  15. data/lib/liquid/i18n.rb +5 -5
  16. data/lib/liquid/interrupts.rb +1 -2
  17. data/lib/liquid/lexer.rb +6 -4
  18. data/lib/liquid/locales/en.yml +5 -1
  19. data/lib/liquid/parse_context.rb +37 -0
  20. data/lib/liquid/parser_switching.rb +4 -4
  21. data/lib/liquid/profiler/hooks.rb +7 -7
  22. data/lib/liquid/profiler.rb +18 -19
  23. data/lib/liquid/range_lookup.rb +16 -1
  24. data/lib/liquid/resource_limits.rb +23 -0
  25. data/lib/liquid/standardfilters.rb +121 -61
  26. data/lib/liquid/strainer.rb +14 -7
  27. data/lib/liquid/tablerowloop_drop.rb +62 -0
  28. data/lib/liquid/tag.rb +9 -8
  29. data/lib/liquid/tags/assign.rb +17 -4
  30. data/lib/liquid/tags/break.rb +0 -3
  31. data/lib/liquid/tags/capture.rb +1 -1
  32. data/lib/liquid/tags/case.rb +19 -12
  33. data/lib/liquid/tags/comment.rb +2 -2
  34. data/lib/liquid/tags/cycle.rb +6 -6
  35. data/lib/liquid/tags/decrement.rb +1 -4
  36. data/lib/liquid/tags/for.rb +95 -75
  37. data/lib/liquid/tags/if.rb +49 -44
  38. data/lib/liquid/tags/ifchanged.rb +0 -2
  39. data/lib/liquid/tags/include.rb +61 -52
  40. data/lib/liquid/tags/raw.rb +32 -4
  41. data/lib/liquid/tags/table_row.rb +12 -30
  42. data/lib/liquid/tags/unless.rb +3 -4
  43. data/lib/liquid/template.rb +42 -54
  44. data/lib/liquid/tokenizer.rb +31 -0
  45. data/lib/liquid/utils.rb +52 -8
  46. data/lib/liquid/variable.rb +46 -45
  47. data/lib/liquid/variable_lookup.rb +7 -5
  48. data/lib/liquid/version.rb +1 -1
  49. data/lib/liquid.rb +9 -7
  50. data/test/integration/assign_test.rb +8 -8
  51. data/test/integration/blank_test.rb +14 -14
  52. data/test/integration/context_test.rb +2 -2
  53. data/test/integration/document_test.rb +19 -0
  54. data/test/integration/drop_test.rb +42 -40
  55. data/test/integration/error_handling_test.rb +99 -46
  56. data/test/integration/filter_test.rb +60 -20
  57. data/test/integration/hash_ordering_test.rb +9 -9
  58. data/test/integration/output_test.rb +26 -27
  59. data/test/integration/parsing_quirks_test.rb +15 -13
  60. data/test/integration/render_profiling_test.rb +20 -20
  61. data/test/integration/security_test.rb +9 -7
  62. data/test/integration/standard_filter_test.rb +179 -40
  63. data/test/integration/tags/break_tag_test.rb +1 -2
  64. data/test/integration/tags/continue_tag_test.rb +0 -1
  65. data/test/integration/tags/for_tag_test.rb +133 -98
  66. data/test/integration/tags/if_else_tag_test.rb +75 -77
  67. data/test/integration/tags/include_tag_test.rb +34 -30
  68. data/test/integration/tags/increment_tag_test.rb +10 -11
  69. data/test/integration/tags/raw_tag_test.rb +7 -1
  70. data/test/integration/tags/standard_tag_test.rb +121 -122
  71. data/test/integration/tags/statements_test.rb +3 -5
  72. data/test/integration/tags/table_row_test.rb +20 -19
  73. data/test/integration/tags/unless_else_tag_test.rb +6 -6
  74. data/test/integration/template_test.rb +190 -49
  75. data/test/integration/trim_mode_test.rb +525 -0
  76. data/test/integration/variable_test.rb +23 -13
  77. data/test/test_helper.rb +33 -5
  78. data/test/unit/block_unit_test.rb +8 -5
  79. data/test/unit/condition_unit_test.rb +86 -77
  80. data/test/unit/context_unit_test.rb +48 -57
  81. data/test/unit/file_system_unit_test.rb +3 -3
  82. data/test/unit/i18n_unit_test.rb +2 -2
  83. data/test/unit/lexer_unit_test.rb +11 -8
  84. data/test/unit/parser_unit_test.rb +2 -2
  85. data/test/unit/regexp_unit_test.rb +1 -1
  86. data/test/unit/strainer_unit_test.rb +80 -1
  87. data/test/unit/tag_unit_test.rb +7 -2
  88. data/test/unit/tags/case_tag_unit_test.rb +1 -1
  89. data/test/unit/tags/for_tag_unit_test.rb +2 -2
  90. data/test/unit/tags/if_tag_unit_test.rb +1 -1
  91. data/test/unit/template_unit_test.rb +14 -5
  92. data/test/unit/tokenizer_unit_test.rb +24 -7
  93. data/test/unit/variable_unit_test.rb +60 -43
  94. metadata +19 -14
  95. data/lib/liquid/module_ex.rb +0 -62
  96. data/lib/liquid/token.rb +0 -18
  97. data/test/unit/module_ex_unit_test.rb +0 -87
  98. /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( ' {{ errors.standard_error }} ' )
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( ' {{ errors.syntax_error }} ' )
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( ' {{ errors.argument_error }} ' )
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 %} ', :error_mode => :lax)
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
- template = Liquid::Template.parse(%q{
86
+ Liquid::Template.parse(%q(
106
87
  foobar
107
88
 
108
89
  {% "cat" | foobar %}
109
90
 
110
91
  bla
111
- },
112
- :line_numbers => true
92
+ ),
93
+ line_numbers: true
113
94
  )
114
95
  end
115
96
 
116
- assert_match /Liquid syntax error \(line 4\)/, err.message
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(%q{
117
+ template = Liquid::Template.parse('
121
118
  foobar
122
119
 
123
120
  {% if 1 =! 2 %}ok{% endif %}
124
121
 
125
122
  bla
126
- },
127
- :error_mode => :warn,
128
- :line_numbers => true
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(%q{
134
+ Liquid::Template.parse('
138
135
  foobar
139
136
 
140
137
  {% if 1 =! 2 %}ok{% endif %}
141
138
 
142
139
  bla
143
- },
144
- :error_mode => :strict,
145
- :line_numbers => true
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(%q{
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
- :line_numbers => true
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 %} ', :error_mode => :strict)
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('{{%%%}}', :error_mode => :strict)
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 %}', :error_mode => :warn)
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 %}", :error_mode => :warn, :line_numbers => true)
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$ ', Variable.new("var | money").render(@context)
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$ ', Variable.new("var | money_with_underscore").render(@context)
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 ', Variable.new("var | money").render(@context)
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, Variable.new("var | size").render(@context)
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", Variable.new("var | join").render(@context)
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 [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)
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", Variable.new("var | strip_html").render(@context)
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", Variable.new("var | strip_html").render(@context)
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", Variable.new("var | capitalize").render(@context)
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, Variable.new("var | xyzzy").render(@context)
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 = Variable.new(%! 'hello %{first_name}, %{last_name}' | substitute: first_name: surname, last_name: 'doe' !).render(@context)
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 }, :filters => [OverrideObjectMethodFilter])
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, :filters => CanadianMoneyFilter)
130
- assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, :filters => [CanadianMoneyFilter])
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
- module MoneyFilter
4
- def money(input)
5
- sprintf(' %d$ ', input)
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
- def money(input)
11
- sprintf(' %d$ CAD ', input)
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
- %|<#{tag} id="#{id}">#{input}</#{tag}>|
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
- %|<a href="#{url}">#{name}</a>|
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 = %| {{best_cars}} |
40
+ text = %( {{best_cars}} )
42
41
 
43
- expected = %| bmw |
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 = %| {{car.bmw}} {{car.gm}} {{car.bmw}} |
55
+ text = %( {{car.bmw}} {{car.gm}} {{car.bmw}} )
57
56
 
58
- expected = %| good bad good |
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 = %| LOL |
63
+ expected = %( LOL )
65
64
 
66
- assert_equal expected, Template.parse(text).render!(@assigns, :filters => [FunnyFilter])
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 = %| LOL: bad |
70
+ expected = %( LOL: bad )
72
71
 
73
- assert_equal expected, Template.parse(text).render!(@assigns, :filters => [FunnyFilter])
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, :filters => [FunnyFilter])
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 = %! {{ car.gm | add_smiley }} !
83
+ text = %( {{ car.gm | add_smiley }} )
85
84
  expected = %| bad :-) |
86
85
 
87
- assert_equal expected, Template.parse(text).render!(@assigns, :filters => [FunnyFilter])
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, :filters => [FunnyFilter])
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 = %! {{ car.gm | add_tag : 'span', 'bar'}} !
99
- expected = %| <span id="bar">bad</span> |
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, :filters => [FunnyFilter])
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 = %! {{ car.gm | add_tag : 'span', car.bmw}} !
106
- expected = %| <span id="good">bad</span> |
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, :filters => [FunnyFilter])
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 = %| <p>LOL: bmw</p> |
112
+ expected = %( <p>LOL: bmw</p> )
114
113
 
115
- assert_equal expected, Template.parse(text).render!(@assigns, :filters => [FunnyFilter])
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 = %| <a href="http://typo.leetsoft.com">Typo</a> |
119
+ expected = %( <a href="http://typo.leetsoft.com">Typo</a> )
121
120
 
122
- assert_equal expected, Template.parse(text).render!(@assigns, :filters => [FunnyFilter])
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
- assert Template.parse("{{|test}}")
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) do
34
- Template.parse("{{test |a|b|}}")
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|}}", :error_mode => :lax)
63
- assert Template.parse("{{test}}", :error_mode => :lax)
64
- assert Template.parse("{{|test|}}", :error_mode => :lax)
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