liquid 4.0.0.rc2 → 4.0.0.rc3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7a15813568dcc19866675ad50444b7939b5eecfa
4
- data.tar.gz: acfb1e49596e266170a25c584978ec8ade8bcf01
3
+ metadata.gz: 3d29364ce9b0e428bfcf9e63df9695f791d8e13e
4
+ data.tar.gz: 08cc19791695840bd1d6230ea9643cfa3ee9147c
5
5
  SHA512:
6
- metadata.gz: 20fa5f4ceec720a9c57219f71bb848c7b407529cf46bf7353fba196452bf9945e33d79e25aff8fb92aceb32ac0f6d2299e6204e7fc5d6eec04134224dae725ef
7
- data.tar.gz: 4ed81d181edfaf21bd25b303ec4e5085c9e734e3fb9679aa3b7a88f664bced5ab60825bb163ffaf7498b650cedf779901ce78917abad1fcbc5be1ec7b27573ee
6
+ metadata.gz: 12c6c427dca1570ce4eee3634d3d6fbfd2f35d231e32678f3d43f19583233a3af8fa2049e04edaf69b41d8df553b75da72a5f5431bfbe2a6d0f1f906b5a97add
7
+ data.tar.gz: 318e400a0ea7e6fedd5d066eda0995b438846d925167a2159885f9806747af683859d4fb5d2ca1853efc9c2bbebc9d3528a2a9013d04bc3c28eb223e56fee1d0
@@ -24,6 +24,7 @@ module Liquid
24
24
  ArgumentSeparator = ','.freeze
25
25
  FilterArgumentSeparator = ':'.freeze
26
26
  VariableAttributeSeparator = '.'.freeze
27
+ WhitespaceControl = '-'.freeze
27
28
  TagStart = /\{\%/
28
29
  TagEnd = /\%\}/
29
30
  VariableSignature = /\(?[\w\-\.\[\]]\)?/
@@ -34,7 +35,7 @@ module Liquid
34
35
  QuotedString = /"[^"]*"|'[^']*'/
35
36
  QuotedFragment = /#{QuotedString}|(?:[^\s,\|'"]|#{QuotedString})+/o
36
37
  TagAttributes = /(\w+)\s*\:\s*(#{QuotedFragment})/o
37
- AnyStartingTag = /\{\{|\{\%/
38
+ AnyStartingTag = /#{TagStart}|#{VariableStart}/o
38
39
  PartialTemplateParser = /#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd}/om
39
40
  TemplateParser = /(#{PartialTemplateParser}|#{AnyStartingTag})/om
40
41
  VariableParser = /\[[^\]]+\]|#{VariableSegment}+\??/o
@@ -1,7 +1,7 @@
1
1
  module Liquid
2
2
  class BlockBody
3
- FullToken = /\A#{TagStart}\s*(\w+)\s*(.*)?#{TagEnd}\z/om
4
- ContentOfVariable = /\A#{VariableStart}(.*)#{VariableEnd}\z/om
3
+ FullToken = /\A#{TagStart}#{WhitespaceControl}?\s*(\w+)\s*(.*?)#{WhitespaceControl}?#{TagEnd}\z/om
4
+ ContentOfVariable = /\A#{VariableStart}#{WhitespaceControl}?(.*?)#{WhitespaceControl}?#{VariableEnd}\z/om
5
5
  TAGSTART = "{%".freeze
6
6
  VARSTART = "{{".freeze
7
7
 
@@ -18,6 +18,7 @@ module Liquid
18
18
  unless token.empty?
19
19
  case
20
20
  when token.start_with?(TAGSTART)
21
+ whitespace_handler(token, parse_context)
21
22
  if token =~ FullToken
22
23
  tag_name = $1
23
24
  markup = $2
@@ -35,9 +36,14 @@ module Liquid
35
36
  raise_missing_tag_terminator(token, parse_context)
36
37
  end
37
38
  when token.start_with?(VARSTART)
39
+ whitespace_handler(token, parse_context)
38
40
  @nodelist << create_variable(token, parse_context)
39
41
  @blank = false
40
42
  else
43
+ if parse_context.trim_whitespace
44
+ token.lstrip!
45
+ end
46
+ parse_context.trim_whitespace = false
41
47
  @nodelist << token
42
48
  @blank &&= !!(token =~ /\A\s*\z/)
43
49
  end
@@ -48,6 +54,16 @@ module Liquid
48
54
  yield nil, nil
49
55
  end
50
56
 
57
+ def whitespace_handler(token, parse_context)
58
+ if token[2] == WhitespaceControl
59
+ previous_token = @nodelist.last
60
+ if previous_token.is_a? String
61
+ previous_token.rstrip!
62
+ end
63
+ end
64
+ parse_context.trim_whitespace = (token[-3] == WhitespaceControl)
65
+ end
66
+
51
67
  def blank?
52
68
  @blank
53
69
  end
@@ -25,6 +25,12 @@ class Numeric # :nodoc:
25
25
  end
26
26
  end
27
27
 
28
+ class Range # :nodoc:
29
+ def to_liquid
30
+ self
31
+ end
32
+ end
33
+
28
34
  class Time # :nodoc:
29
35
  def to_liquid
30
36
  self
@@ -8,8 +8,8 @@ module Liquid
8
8
  #
9
9
  # Example:
10
10
  #
11
- # Liquid::Template.file_system = Liquid::LocalFileSystem.new(template_path)
12
- # liquid = Liquid::Template.parse(template)
11
+ # Liquid::Template.file_system = Liquid::LocalFileSystem.new(template_path)
12
+ # liquid = Liquid::Template.parse(template)
13
13
  #
14
14
  # This will parse the template with a LocalFileSystem implementation rooted at 'template_path'.
15
15
  class BlankFileSystem
@@ -26,10 +26,10 @@ module Liquid
26
26
  #
27
27
  # Example:
28
28
  #
29
- # file_system = Liquid::LocalFileSystem.new("/some/path")
29
+ # file_system = Liquid::LocalFileSystem.new("/some/path")
30
30
  #
31
- # file_system.full_path("mypartial") # => "/some/path/_mypartial.liquid"
32
- # file_system.full_path("dir/mypartial") # => "/some/path/dir/_mypartial.liquid"
31
+ # file_system.full_path("mypartial") # => "/some/path/_mypartial.liquid"
32
+ # file_system.full_path("dir/mypartial") # => "/some/path/dir/_mypartial.liquid"
33
33
  #
34
34
  # Optionally in the second argument you can specify a custom pattern for template filenames.
35
35
  # The Kernel::sprintf format specification is used.
@@ -37,9 +37,9 @@ module Liquid
37
37
  #
38
38
  # Example:
39
39
  #
40
- # file_system = Liquid::LocalFileSystem.new("/some/path", "%s.html")
40
+ # file_system = Liquid::LocalFileSystem.new("/some/path", "%s.html")
41
41
  #
42
- # file_system.full_path("index") # => "/some/path/index.html"
42
+ # file_system.full_path("index") # => "/some/path/index.html"
43
43
  #
44
44
  class LocalFileSystem
45
45
  attr_accessor :root
@@ -22,3 +22,5 @@
22
22
  tag_never_closed: "'%{block_name}' tag was never closed"
23
23
  meta_syntax_error: "Liquid syntax error: #{e.message}"
24
24
  table_row: "Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3"
25
+ argument:
26
+ include: "Argument error in tag 'include' - Illegal template name"
@@ -1,6 +1,6 @@
1
1
  module Liquid
2
2
  class ParseContext
3
- attr_accessor :locale, :line_number
3
+ attr_accessor :locale, :line_number, :trim_whitespace
4
4
  attr_reader :partial, :warnings, :error_mode
5
5
 
6
6
  def initialize(options = {})
@@ -289,6 +289,12 @@ module Liquid
289
289
  array.last if array.respond_to?(:last)
290
290
  end
291
291
 
292
+ # absolute value
293
+ def abs(input)
294
+ result = Utils.to_number(input).abs
295
+ result.is_a?(BigDecimal) ? result.to_f : result
296
+ end
297
+
292
298
  # addition
293
299
  def plus(input, operand)
294
300
  apply_operation(input, operand, :+)
@@ -42,8 +42,9 @@ module Liquid
42
42
 
43
43
  def render(context)
44
44
  template_name = context.evaluate(@template_name_expr)
45
- partial = load_cached_partial(template_name, context)
45
+ raise ArgumentError.new(options[:locale].t("errors.argument.include")) unless template_name
46
46
 
47
+ partial = load_cached_partial(template_name, context)
47
48
  context_variable_name = template_name.split('/'.freeze).last
48
49
 
49
50
  variable = if @variable_name_expr
@@ -6,9 +6,7 @@ module Liquid
6
6
  def initialize(tag_name, markup, parse_context)
7
7
  super
8
8
 
9
- unless markup =~ Syntax
10
- raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_unexpected_args".freeze, tag: tag_name))
11
- end
9
+ ensure_valid_markup(tag_name, markup, parse_context)
12
10
  end
13
11
 
14
12
  def parse(tokens)
@@ -35,6 +33,14 @@ module Liquid
35
33
  def blank?
36
34
  @body.empty?
37
35
  end
36
+
37
+ protected
38
+
39
+ def ensure_valid_markup(tag_name, markup, parse_context)
40
+ unless markup =~ Syntax
41
+ raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_unexpected_args".freeze, tag: tag_name))
42
+ end
43
+ end
38
44
  end
39
45
 
40
46
  Template.register_tag('raw'.freeze, Raw)
@@ -19,6 +19,8 @@ module Liquid
19
19
  @@file_system = BlankFileSystem.new
20
20
 
21
21
  class TagRegistry
22
+ include Enumerable
23
+
22
24
  def initialize
23
25
  @tags = {}
24
26
  @cache = {}
@@ -41,6 +43,10 @@ module Liquid
41
43
  @cache.delete(tag_name)
42
44
  end
43
45
 
46
+ def each(&block)
47
+ @tags.each(&block)
48
+ end
49
+
44
50
  private
45
51
 
46
52
  def lookup_class(name)
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Liquid
3
- VERSION = "4.0.0.rc2"
3
+ VERSION = "4.0.0.rc3"
4
4
  end
@@ -97,6 +97,22 @@ class ErrorHandlingTest < Minitest::Test
97
97
  assert_match(/Liquid syntax error \(line 4\)/, err.message)
98
98
  end
99
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
+
100
116
  def test_parsing_warn_with_line_numbers_adds_numbers_to_lexer_errors
101
117
  template = Liquid::Template.parse('
102
118
  foobar
@@ -385,6 +385,19 @@ class StandardFiltersTest < Minitest::Test
385
385
  assert_template_result "5", "{{ price | minus:'2' }}", 'price' => NumberLikeThing.new(7)
386
386
  end
387
387
 
388
+ def test_abs
389
+ assert_template_result "17", "{{ 17 | abs }}"
390
+ assert_template_result "17", "{{ -17 | abs }}"
391
+ assert_template_result "17", "{{ '17' | abs }}"
392
+ assert_template_result "17", "{{ '-17' | abs }}"
393
+ assert_template_result "0", "{{ 0 | abs }}"
394
+ assert_template_result "0", "{{ '0' | abs }}"
395
+ assert_template_result "17.42", "{{ 17.42 | abs }}"
396
+ assert_template_result "17.42", "{{ -17.42 | abs }}"
397
+ assert_template_result "17.42", "{{ '17.42' | abs }}"
398
+ assert_template_result "17.42", "{{ '-17.42' | abs }}"
399
+ end
400
+
388
401
  def test_times
389
402
  assert_template_result "12", "{{ 3 | times:4 }}"
390
403
  assert_template_result "0", "{{ 'foo' | times:4 }}"
@@ -217,6 +217,17 @@ class IncludeTagTest < Minitest::Test
217
217
  end
218
218
  end
219
219
 
220
+ def test_render_raise_argument_error_when_template_is_undefined
221
+ assert_raises(Liquid::ArgumentError) do
222
+ template = Liquid::Template.parse('{% include undefined_variable %}')
223
+ template.render!
224
+ end
225
+ assert_raises(Liquid::ArgumentError) do
226
+ template = Liquid::Template.parse('{% include nil %}')
227
+ template.render!
228
+ end
229
+ end
230
+
220
231
  def test_including_via_variable_value
221
232
  assert_template_result "from TestFileSystem", "{% assign page = 'pick_a_source' %}{% include page %}"
222
233
 
@@ -306,4 +306,14 @@ class TemplateTest < Minitest::Test
306
306
  t.render!({ 'x' => 'foo' }, { strict_filters: true })
307
307
  end
308
308
  end
309
+
310
+ def test_using_range_literal_works_as_expected
311
+ t = Template.parse("{% assign foo = (x..y) %}{{ foo }}")
312
+ result = t.render({ 'x' => 1, 'y' => 5 })
313
+ assert_equal '1..5', result
314
+
315
+ t = Template.parse("{% assign nums = (x..y) %}{% for num in nums %}{{ num }}{% endfor %}")
316
+ result = t.render({ 'x' => 1, 'y' => 5 })
317
+ assert_equal '12345', result
318
+ end
309
319
  end
@@ -0,0 +1,525 @@
1
+ require 'test_helper'
2
+
3
+ class TrimModeTest < Minitest::Test
4
+ include Liquid
5
+
6
+ # Make sure the trim isn't applied to standard output
7
+ def test_standard_output
8
+ text = <<-END_TEMPLATE
9
+ <div>
10
+ <p>
11
+ {{ 'John' }}
12
+ </p>
13
+ </div>
14
+ END_TEMPLATE
15
+ expected = <<-END_EXPECTED
16
+ <div>
17
+ <p>
18
+ John
19
+ </p>
20
+ </div>
21
+ END_EXPECTED
22
+ assert_template_result(expected, text)
23
+ end
24
+
25
+ def test_variable_output_with_multiple_blank_lines
26
+ text = <<-END_TEMPLATE
27
+ <div>
28
+ <p>
29
+
30
+
31
+ {{- 'John' -}}
32
+
33
+
34
+ </p>
35
+ </div>
36
+ END_TEMPLATE
37
+ expected = <<-END_EXPECTED
38
+ <div>
39
+ <p>John</p>
40
+ </div>
41
+ END_EXPECTED
42
+ assert_template_result(expected, text)
43
+ end
44
+
45
+ def test_tag_output_with_multiple_blank_lines
46
+ text = <<-END_TEMPLATE
47
+ <div>
48
+ <p>
49
+
50
+
51
+ {%- if true -%}
52
+ yes
53
+ {%- endif -%}
54
+
55
+
56
+ </p>
57
+ </div>
58
+ END_TEMPLATE
59
+ expected = <<-END_EXPECTED
60
+ <div>
61
+ <p>yes</p>
62
+ </div>
63
+ END_EXPECTED
64
+ assert_template_result(expected, text)
65
+ end
66
+
67
+ # Make sure the trim isn't applied to standard tags
68
+ def test_standard_tags
69
+ whitespace = ' '
70
+ text = <<-END_TEMPLATE
71
+ <div>
72
+ <p>
73
+ {% if true %}
74
+ yes
75
+ {% endif %}
76
+ </p>
77
+ </div>
78
+ END_TEMPLATE
79
+ expected = <<-END_EXPECTED
80
+ <div>
81
+ <p>
82
+ #{whitespace}
83
+ yes
84
+ #{whitespace}
85
+ </p>
86
+ </div>
87
+ END_EXPECTED
88
+ assert_template_result(expected, text)
89
+
90
+ text = <<-END_TEMPLATE
91
+ <div>
92
+ <p>
93
+ {% if false %}
94
+ no
95
+ {% endif %}
96
+ </p>
97
+ </div>
98
+ END_TEMPLATE
99
+ expected = <<-END_EXPECTED
100
+ <div>
101
+ <p>
102
+ #{whitespace}
103
+ </p>
104
+ </div>
105
+ END_EXPECTED
106
+ assert_template_result(expected, text)
107
+ end
108
+
109
+ # Make sure the trim isn't too agressive
110
+ def test_no_trim_output
111
+ text = '<p>{{- \'John\' -}}</p>'
112
+ expected = '<p>John</p>'
113
+ assert_template_result(expected, text)
114
+ end
115
+
116
+ # Make sure the trim isn't too agressive
117
+ def test_no_trim_tags
118
+ text = '<p>{%- if true -%}yes{%- endif -%}</p>'
119
+ expected = '<p>yes</p>'
120
+ assert_template_result(expected, text)
121
+
122
+ text = '<p>{%- if false -%}no{%- endif -%}</p>'
123
+ expected = '<p></p>'
124
+ assert_template_result(expected, text)
125
+ end
126
+
127
+ def test_single_line_outer_tag
128
+ text = '<p> {%- if true %} yes {% endif -%} </p>'
129
+ expected = '<p> yes </p>'
130
+ assert_template_result(expected, text)
131
+
132
+ text = '<p> {%- if false %} no {% endif -%} </p>'
133
+ expected = '<p></p>'
134
+ assert_template_result(expected, text)
135
+ end
136
+
137
+ def test_single_line_inner_tag
138
+ text = '<p> {% if true -%} yes {%- endif %} </p>'
139
+ expected = '<p> yes </p>'
140
+ assert_template_result(expected, text)
141
+
142
+ text = '<p> {% if false -%} no {%- endif %} </p>'
143
+ expected = '<p> </p>'
144
+ assert_template_result(expected, text)
145
+ end
146
+
147
+ def test_single_line_post_tag
148
+ text = '<p> {% if true -%} yes {% endif -%} </p>'
149
+ expected = '<p> yes </p>'
150
+ assert_template_result(expected, text)
151
+
152
+ text = '<p> {% if false -%} no {% endif -%} </p>'
153
+ expected = '<p> </p>'
154
+ assert_template_result(expected, text)
155
+ end
156
+
157
+ def test_single_line_pre_tag
158
+ text = '<p> {%- if true %} yes {%- endif %} </p>'
159
+ expected = '<p> yes </p>'
160
+ assert_template_result(expected, text)
161
+
162
+ text = '<p> {%- if false %} no {%- endif %} </p>'
163
+ expected = '<p> </p>'
164
+ assert_template_result(expected, text)
165
+ end
166
+
167
+ def test_pre_trim_output
168
+ text = <<-END_TEMPLATE
169
+ <div>
170
+ <p>
171
+ {{- 'John' }}
172
+ </p>
173
+ </div>
174
+ END_TEMPLATE
175
+ expected = <<-END_EXPECTED
176
+ <div>
177
+ <p>John
178
+ </p>
179
+ </div>
180
+ END_EXPECTED
181
+ assert_template_result(expected, text)
182
+ end
183
+
184
+ def test_pre_trim_tags
185
+ text = <<-END_TEMPLATE
186
+ <div>
187
+ <p>
188
+ {%- if true %}
189
+ yes
190
+ {%- endif %}
191
+ </p>
192
+ </div>
193
+ END_TEMPLATE
194
+ expected = <<-END_EXPECTED
195
+ <div>
196
+ <p>
197
+ yes
198
+ </p>
199
+ </div>
200
+ END_EXPECTED
201
+ assert_template_result(expected, text)
202
+
203
+ text = <<-END_TEMPLATE
204
+ <div>
205
+ <p>
206
+ {%- if false %}
207
+ no
208
+ {%- endif %}
209
+ </p>
210
+ </div>
211
+ END_TEMPLATE
212
+ expected = <<-END_EXPECTED
213
+ <div>
214
+ <p>
215
+ </p>
216
+ </div>
217
+ END_EXPECTED
218
+ assert_template_result(expected, text)
219
+ end
220
+
221
+ def test_post_trim_output
222
+ text = <<-END_TEMPLATE
223
+ <div>
224
+ <p>
225
+ {{ 'John' -}}
226
+ </p>
227
+ </div>
228
+ END_TEMPLATE
229
+ expected = <<-END_EXPECTED
230
+ <div>
231
+ <p>
232
+ John</p>
233
+ </div>
234
+ END_EXPECTED
235
+ assert_template_result(expected, text)
236
+ end
237
+
238
+ def test_post_trim_tags
239
+ text = <<-END_TEMPLATE
240
+ <div>
241
+ <p>
242
+ {% if true -%}
243
+ yes
244
+ {% endif -%}
245
+ </p>
246
+ </div>
247
+ END_TEMPLATE
248
+ expected = <<-END_EXPECTED
249
+ <div>
250
+ <p>
251
+ yes
252
+ </p>
253
+ </div>
254
+ END_EXPECTED
255
+ assert_template_result(expected, text)
256
+
257
+ text = <<-END_TEMPLATE
258
+ <div>
259
+ <p>
260
+ {% if false -%}
261
+ no
262
+ {% endif -%}
263
+ </p>
264
+ </div>
265
+ END_TEMPLATE
266
+ expected = <<-END_EXPECTED
267
+ <div>
268
+ <p>
269
+ </p>
270
+ </div>
271
+ END_EXPECTED
272
+ assert_template_result(expected, text)
273
+ end
274
+
275
+ def test_pre_and_post_trim_tags
276
+ text = <<-END_TEMPLATE
277
+ <div>
278
+ <p>
279
+ {%- if true %}
280
+ yes
281
+ {% endif -%}
282
+ </p>
283
+ </div>
284
+ END_TEMPLATE
285
+ expected = <<-END_EXPECTED
286
+ <div>
287
+ <p>
288
+ yes
289
+ </p>
290
+ </div>
291
+ END_EXPECTED
292
+ assert_template_result(expected, text)
293
+
294
+ text = <<-END_TEMPLATE
295
+ <div>
296
+ <p>
297
+ {%- if false %}
298
+ no
299
+ {% endif -%}
300
+ </p>
301
+ </div>
302
+ END_TEMPLATE
303
+ expected = <<-END_EXPECTED
304
+ <div>
305
+ <p></p>
306
+ </div>
307
+ END_EXPECTED
308
+ assert_template_result(expected, text)
309
+ end
310
+
311
+ def test_post_and_pre_trim_tags
312
+ text = <<-END_TEMPLATE
313
+ <div>
314
+ <p>
315
+ {% if true -%}
316
+ yes
317
+ {%- endif %}
318
+ </p>
319
+ </div>
320
+ END_TEMPLATE
321
+ expected = <<-END_EXPECTED
322
+ <div>
323
+ <p>
324
+ yes
325
+ </p>
326
+ </div>
327
+ END_EXPECTED
328
+ assert_template_result(expected, text)
329
+
330
+ whitespace = ' '
331
+ text = <<-END_TEMPLATE
332
+ <div>
333
+ <p>
334
+ {% if false -%}
335
+ no
336
+ {%- endif %}
337
+ </p>
338
+ </div>
339
+ END_TEMPLATE
340
+ expected = <<-END_EXPECTED
341
+ <div>
342
+ <p>
343
+ #{whitespace}
344
+ </p>
345
+ </div>
346
+ END_EXPECTED
347
+ assert_template_result(expected, text)
348
+ end
349
+
350
+ def test_trim_output
351
+ text = <<-END_TEMPLATE
352
+ <div>
353
+ <p>
354
+ {{- 'John' -}}
355
+ </p>
356
+ </div>
357
+ END_TEMPLATE
358
+ expected = <<-END_EXPECTED
359
+ <div>
360
+ <p>John</p>
361
+ </div>
362
+ END_EXPECTED
363
+ assert_template_result(expected, text)
364
+ end
365
+
366
+ def test_trim_tags
367
+ text = <<-END_TEMPLATE
368
+ <div>
369
+ <p>
370
+ {%- if true -%}
371
+ yes
372
+ {%- endif -%}
373
+ </p>
374
+ </div>
375
+ END_TEMPLATE
376
+ expected = <<-END_EXPECTED
377
+ <div>
378
+ <p>yes</p>
379
+ </div>
380
+ END_EXPECTED
381
+ assert_template_result(expected, text)
382
+
383
+ text = <<-END_TEMPLATE
384
+ <div>
385
+ <p>
386
+ {%- if false -%}
387
+ no
388
+ {%- endif -%}
389
+ </p>
390
+ </div>
391
+ END_TEMPLATE
392
+ expected = <<-END_EXPECTED
393
+ <div>
394
+ <p></p>
395
+ </div>
396
+ END_EXPECTED
397
+ assert_template_result(expected, text)
398
+ end
399
+
400
+ def test_whitespace_trim_output
401
+ text = <<-END_TEMPLATE
402
+ <div>
403
+ <p>
404
+ {{- 'John' -}},
405
+ {{- '30' -}}
406
+ </p>
407
+ </div>
408
+ END_TEMPLATE
409
+ expected = <<-END_EXPECTED
410
+ <div>
411
+ <p>John,30</p>
412
+ </div>
413
+ END_EXPECTED
414
+ assert_template_result(expected, text)
415
+ end
416
+
417
+ def test_whitespace_trim_tags
418
+ text = <<-END_TEMPLATE
419
+ <div>
420
+ <p>
421
+ {%- if true -%}
422
+ yes
423
+ {%- endif -%}
424
+ </p>
425
+ </div>
426
+ END_TEMPLATE
427
+ expected = <<-END_EXPECTED
428
+ <div>
429
+ <p>yes</p>
430
+ </div>
431
+ END_EXPECTED
432
+ assert_template_result(expected, text)
433
+
434
+ text = <<-END_TEMPLATE
435
+ <div>
436
+ <p>
437
+ {%- if false -%}
438
+ no
439
+ {%- endif -%}
440
+ </p>
441
+ </div>
442
+ END_TEMPLATE
443
+ expected = <<-END_EXPECTED
444
+ <div>
445
+ <p></p>
446
+ </div>
447
+ END_EXPECTED
448
+ assert_template_result(expected, text)
449
+ end
450
+
451
+ def test_complex_trim_output
452
+ text = <<-END_TEMPLATE
453
+ <div>
454
+ <p>
455
+ {{- 'John' -}}
456
+ {{- '30' -}}
457
+ </p>
458
+ <b>
459
+ {{ 'John' -}}
460
+ {{- '30' }}
461
+ </b>
462
+ <i>
463
+ {{- 'John' }}
464
+ {{ '30' -}}
465
+ </i>
466
+ </div>
467
+ END_TEMPLATE
468
+ expected = <<-END_EXPECTED
469
+ <div>
470
+ <p>John30</p>
471
+ <b>
472
+ John30
473
+ </b>
474
+ <i>John
475
+ 30</i>
476
+ </div>
477
+ END_EXPECTED
478
+ assert_template_result(expected, text)
479
+ end
480
+
481
+ def test_complex_trim
482
+ text = <<-END_TEMPLATE
483
+ <div>
484
+ {%- if true -%}
485
+ {%- if true -%}
486
+ <p>
487
+ {{- 'John' -}}
488
+ </p>
489
+ {%- endif -%}
490
+ {%- endif -%}
491
+ </div>
492
+ END_TEMPLATE
493
+ expected = <<-END_EXPECTED
494
+ <div><p>John</p></div>
495
+ END_EXPECTED
496
+ assert_template_result(expected, text)
497
+ end
498
+
499
+ def test_raw_output
500
+ whitespace = ' '
501
+ text = <<-END_TEMPLATE
502
+ <div>
503
+ {% raw %}
504
+ {%- if true -%}
505
+ <p>
506
+ {{- 'John' -}}
507
+ </p>
508
+ {%- endif -%}
509
+ {% endraw %}
510
+ </div>
511
+ END_TEMPLATE
512
+ expected = <<-END_EXPECTED
513
+ <div>
514
+ #{whitespace}
515
+ {%- if true -%}
516
+ <p>
517
+ {{- 'John' -}}
518
+ </p>
519
+ {%- endif -%}
520
+ #{whitespace}
521
+ </div>
522
+ END_EXPECTED
523
+ assert_template_result(expected, text)
524
+ end
525
+ end # TrimModeTest
@@ -46,6 +46,8 @@ class BlockUnitTest < Minitest::Test
46
46
  def test_with_custom_tag
47
47
  Liquid::Template.register_tag("testtag", Block)
48
48
  assert Liquid::Template.parse("{% testtag %} {% endtesttag %}")
49
+ ensure
50
+ Liquid::Template.tags.delete('testtag')
49
51
  end
50
52
 
51
53
  private
@@ -67,4 +67,12 @@ class TemplateUnitTest < Minitest::Test
67
67
  Template.tags.delete('fake')
68
68
  assert_nil Template.tags['fake']
69
69
  end
70
+
71
+ def test_tags_can_be_looped_over
72
+ Template.register_tag('fake', FakeTag)
73
+ result = Template.tags.map { |name, klass| [name, klass] }
74
+ assert result.include?(["fake", "TemplateUnitTest::FakeTag"])
75
+ ensure
76
+ Template.tags.delete('fake')
77
+ end
70
78
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: liquid
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.rc2
4
+ version: 4.0.0.rc3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Lütke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-31 00:00:00.000000000 Z
11
+ date: 2016-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -126,6 +126,7 @@ files:
126
126
  - test/integration/tags/table_row_test.rb
127
127
  - test/integration/tags/unless_else_tag_test.rb
128
128
  - test/integration/template_test.rb
129
+ - test/integration/trim_mode_test.rb
129
130
  - test/integration/variable_test.rb
130
131
  - test/test_helper.rb
131
132
  - test/unit/block_unit_test.rb
@@ -164,53 +165,54 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
165
  version: 1.3.7
165
166
  requirements: []
166
167
  rubyforge_project:
167
- rubygems_version: 2.2.3
168
+ rubygems_version: 2.4.5
168
169
  signing_key:
169
170
  specification_version: 4
170
171
  summary: A secure, non-evaling end user template engine with aesthetic markup.
171
172
  test_files:
172
173
  - test/fixtures/en_locale.yml
173
- - test/test_helper.rb
174
- - test/unit/tokenizer_unit_test.rb
175
- - test/unit/regexp_unit_test.rb
176
- - test/unit/lexer_unit_test.rb
177
- - test/unit/strainer_unit_test.rb
178
- - test/unit/i18n_unit_test.rb
179
- - test/unit/condition_unit_test.rb
180
- - test/unit/variable_unit_test.rb
181
- - test/unit/context_unit_test.rb
182
- - test/unit/block_unit_test.rb
183
- - test/unit/template_unit_test.rb
184
- - test/unit/file_system_unit_test.rb
185
- - test/unit/parser_unit_test.rb
186
- - test/unit/tag_unit_test.rb
187
- - test/unit/tags/case_tag_unit_test.rb
188
- - test/unit/tags/if_tag_unit_test.rb
189
- - test/unit/tags/for_tag_unit_test.rb
174
+ - test/integration/assign_test.rb
175
+ - test/integration/blank_test.rb
176
+ - test/integration/capture_test.rb
177
+ - test/integration/context_test.rb
178
+ - test/integration/document_test.rb
190
179
  - test/integration/drop_test.rb
180
+ - test/integration/error_handling_test.rb
181
+ - test/integration/filter_test.rb
191
182
  - test/integration/hash_ordering_test.rb
192
- - test/integration/variable_test.rb
193
- - test/integration/assign_test.rb
194
183
  - test/integration/output_test.rb
195
- - test/integration/error_handling_test.rb
196
- - test/integration/security_test.rb
197
- - test/integration/template_test.rb
198
- - test/integration/document_test.rb
199
- - test/integration/capture_test.rb
200
- - test/integration/render_profiling_test.rb
201
184
  - test/integration/parsing_quirks_test.rb
202
- - test/integration/blank_test.rb
203
- - test/integration/filter_test.rb
204
- - test/integration/context_test.rb
185
+ - test/integration/render_profiling_test.rb
186
+ - test/integration/security_test.rb
205
187
  - test/integration/standard_filter_test.rb
206
- - test/integration/tags/statements_test.rb
207
- - test/integration/tags/increment_tag_test.rb
208
- - test/integration/tags/standard_tag_test.rb
209
188
  - test/integration/tags/break_tag_test.rb
210
189
  - test/integration/tags/continue_tag_test.rb
211
190
  - test/integration/tags/for_tag_test.rb
212
- - test/integration/tags/raw_tag_test.rb
191
+ - test/integration/tags/if_else_tag_test.rb
213
192
  - test/integration/tags/include_tag_test.rb
193
+ - test/integration/tags/increment_tag_test.rb
194
+ - test/integration/tags/raw_tag_test.rb
195
+ - test/integration/tags/standard_tag_test.rb
196
+ - test/integration/tags/statements_test.rb
214
197
  - test/integration/tags/table_row_test.rb
215
198
  - test/integration/tags/unless_else_tag_test.rb
216
- - test/integration/tags/if_else_tag_test.rb
199
+ - test/integration/template_test.rb
200
+ - test/integration/trim_mode_test.rb
201
+ - test/integration/variable_test.rb
202
+ - test/test_helper.rb
203
+ - test/unit/block_unit_test.rb
204
+ - test/unit/condition_unit_test.rb
205
+ - test/unit/context_unit_test.rb
206
+ - test/unit/file_system_unit_test.rb
207
+ - test/unit/i18n_unit_test.rb
208
+ - test/unit/lexer_unit_test.rb
209
+ - test/unit/parser_unit_test.rb
210
+ - test/unit/regexp_unit_test.rb
211
+ - test/unit/strainer_unit_test.rb
212
+ - test/unit/tag_unit_test.rb
213
+ - test/unit/tags/case_tag_unit_test.rb
214
+ - test/unit/tags/for_tag_unit_test.rb
215
+ - test/unit/tags/if_tag_unit_test.rb
216
+ - test/unit/template_unit_test.rb
217
+ - test/unit/tokenizer_unit_test.rb
218
+ - test/unit/variable_unit_test.rb