liquid 5.0.1 → 5.3.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.
- checksums.yaml +4 -4
- data/History.md +31 -0
- data/README.md +2 -2
- data/lib/liquid/block_body.rb +2 -2
- data/lib/liquid/condition.rb +10 -4
- data/lib/liquid/context.rb +1 -1
- data/lib/liquid/expression.rb +11 -10
- data/lib/liquid/range_lookup.rb +8 -0
- data/lib/liquid/standardfilters.rb +87 -20
- data/lib/liquid/static_registers.rb +5 -1
- data/lib/liquid/strainer_factory.rb +11 -10
- data/lib/liquid/strainer_template.rb +5 -0
- data/lib/liquid/tags/case.rb +8 -1
- data/lib/liquid/tags/if.rb +5 -1
- data/lib/liquid/tags/unless.rb +10 -2
- data/lib/liquid/tokenizer.rb +2 -2
- data/lib/liquid/utils.rb +8 -0
- data/lib/liquid/variable_lookup.rb +3 -0
- data/lib/liquid/version.rb +1 -1
- data/lib/liquid.rb +2 -2
- data/test/integration/context_test.rb +12 -14
- data/test/integration/filter_kwarg_test.rb +24 -0
- data/test/integration/profiler_test.rb +33 -6
- data/test/integration/standard_filter_test.rb +119 -32
- data/test/integration/template_test.rb +14 -0
- data/test/integration/variable_test.rb +31 -0
- data/test/test_helper.rb +48 -10
- data/test/unit/condition_unit_test.rb +27 -14
- data/test/unit/parse_tree_visitor_test.rb +7 -0
- data/test/unit/strainer_factory_unit_test.rb +2 -1
- data/test/unit/strainer_template_unit_test.rb +1 -1
- metadata +48 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0e965825a9194672f6d2b9c3011db0125eb3dbbb6d44cacf67559140c3f0f9b
|
4
|
+
data.tar.gz: d1d98d881037c5ff8cc2b9da99d3b3e002eb1ca1d2bda593c806830c1607a98a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa9caca36072ca79bb727b7bdb9a671e082039c3c999d6cbb79bf8b1feec0d514159daedf2b54f561e66ca5ab7e11273956fb49afbae3580004d3e1d3780b9ab
|
7
|
+
data.tar.gz: a766a7b068287a7db0a70222a149f8a52a659e93c6593bb53a31e5cee279cbc65b7db14eaa1cc0e89e816bd76020bf352814cd9c2c6b4e32436f743ab0c8e629
|
data/History.md
CHANGED
@@ -1,5 +1,36 @@
|
|
1
1
|
# Liquid Change Log
|
2
2
|
|
3
|
+
## 5.3.0 2022-03-22
|
4
|
+
|
5
|
+
### Fixes
|
6
|
+
* StandardFilter: Fix missing @context on iterations (#1525) [Thierry Joyal]
|
7
|
+
* Test under Ruby 3.1 (#1533) [petergoldstein]
|
8
|
+
* Fix warning about block and default value in `static_registers.rb` (#1531) [Peter Zhu]
|
9
|
+
|
10
|
+
### Deprecation
|
11
|
+
* Condition#evaluate to require mandatory context argument in Liquid 6.0.0 (#1527) [Thierry Joyal]
|
12
|
+
|
13
|
+
## 5.2.0 2022-03-01
|
14
|
+
|
15
|
+
### Features
|
16
|
+
* Add `remove_last`, and `replace_last` filters (#1422) [Anders Hagbard]
|
17
|
+
* Eagerly cache global filters (#1524) [Jean Boussier]
|
18
|
+
|
19
|
+
### Fixes
|
20
|
+
* Fix some internal errors in filters from invalid input (#1476) [Dylan Thacker-Smith]
|
21
|
+
* Allow dash in filter kwarg name for consistency with Liquid::C (#1518) [CP Clermont]
|
22
|
+
|
23
|
+
## 5.1.0 / 2021-09-09
|
24
|
+
|
25
|
+
### Features
|
26
|
+
* Add `base64_encode`, `base64_decode`, `base64_url_safe_encode`, and `base64_url_safe_decode` filters (#1450) [Daniel Insley]
|
27
|
+
* Introduce `to_liquid_value` in `Liquid::Drop` (#1441) [Michael Go]
|
28
|
+
|
29
|
+
### Fixes
|
30
|
+
* Fix support for using a String subclass for the liquid source (#1421) [Dylan Thacker-Smith]
|
31
|
+
* Add `ParseTreeVisitor` to `RangeLookup` (#1470) [CP Clermont]
|
32
|
+
* Translate `RangeError` to `Liquid::Error` for `truncatewords` with large int (#1431) [Dylan Thacker-Smith]
|
33
|
+
|
3
34
|
## 5.0.1 / 2021-03-24
|
4
35
|
|
5
36
|
### Fixes
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
* [Contributing guidelines](CONTRIBUTING.md)
|
7
7
|
* [Version history](History.md)
|
8
|
-
* [Liquid documentation from Shopify](
|
8
|
+
* [Liquid documentation from Shopify](https://shopify.dev/api/liquid)
|
9
9
|
* [Liquid Wiki at GitHub](https://github.com/Shopify/liquid/wiki)
|
10
10
|
* [Website](http://liquidmarkup.org/)
|
11
11
|
|
@@ -56,7 +56,7 @@ For standard use you can just pass it the content of a file and call render with
|
|
56
56
|
|
57
57
|
Setting the error mode of Liquid lets you specify how strictly you want your templates to be interpreted.
|
58
58
|
Normally the parser is very lax and will accept almost anything without error. Unfortunately this can make
|
59
|
-
it very hard to debug and can lead to unexpected behaviour.
|
59
|
+
it very hard to debug and can lead to unexpected behaviour.
|
60
60
|
|
61
61
|
Liquid also comes with a stricter parser that can be used when editing templates to give better error messages
|
62
62
|
when templates are invalid. You can enable this new parser like this:
|
data/lib/liquid/block_body.rb
CHANGED
@@ -231,8 +231,8 @@ module Liquid
|
|
231
231
|
end
|
232
232
|
|
233
233
|
def create_variable(token, parse_context)
|
234
|
-
token
|
235
|
-
markup =
|
234
|
+
if token =~ ContentOfVariable
|
235
|
+
markup = Regexp.last_match(1)
|
236
236
|
return Variable.new(markup, parse_context)
|
237
237
|
end
|
238
238
|
BlockBody.raise_missing_variable_terminator(token, parse_context)
|
data/lib/liquid/condition.rb
CHANGED
@@ -8,7 +8,7 @@ module Liquid
|
|
8
8
|
# c = Condition.new(1, '==', 1)
|
9
9
|
# c.evaluate #=> true
|
10
10
|
#
|
11
|
-
class Condition
|
11
|
+
class Condition # :nodoc:
|
12
12
|
@@operators = {
|
13
13
|
'==' => ->(cond, left, right) { cond.send(:equal_variables, left, right) },
|
14
14
|
'!=' => ->(cond, left, right) { !cond.send(:equal_variables, left, right) },
|
@@ -61,7 +61,7 @@ module Liquid
|
|
61
61
|
@child_condition = nil
|
62
62
|
end
|
63
63
|
|
64
|
-
def evaluate(context =
|
64
|
+
def evaluate(context = deprecated_default_context)
|
65
65
|
condition = self
|
66
66
|
result = nil
|
67
67
|
loop do
|
@@ -134,8 +134,8 @@ module Liquid
|
|
134
134
|
# return this as the result.
|
135
135
|
return context.evaluate(left) if op.nil?
|
136
136
|
|
137
|
-
left = context.evaluate(left)
|
138
|
-
right = context.evaluate(right)
|
137
|
+
left = Liquid::Utils.to_liquid_value(context.evaluate(left))
|
138
|
+
right = Liquid::Utils.to_liquid_value(context.evaluate(right))
|
139
139
|
|
140
140
|
operation = self.class.operators[op] || raise(Liquid::ArgumentError, "Unknown operator #{op}")
|
141
141
|
|
@@ -150,6 +150,12 @@ module Liquid
|
|
150
150
|
end
|
151
151
|
end
|
152
152
|
|
153
|
+
def deprecated_default_context
|
154
|
+
warn("DEPRECATION WARNING: Condition#evaluate without a context argument is deprecated" \
|
155
|
+
" and will be removed from Liquid 6.0.0.")
|
156
|
+
Context.new
|
157
|
+
end
|
158
|
+
|
153
159
|
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
154
160
|
def children
|
155
161
|
[
|
data/lib/liquid/context.rb
CHANGED
data/lib/liquid/expression.rb
CHANGED
@@ -10,21 +10,23 @@ module Liquid
|
|
10
10
|
'empty' => ''
|
11
11
|
}.freeze
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
INTEGERS_REGEX = /\A\s*(-?\d+)\s*\z/
|
16
|
-
FLOATS_REGEX = /\A\s*(-?\d[\d\.]+)\s*\z/
|
13
|
+
INTEGERS_REGEX = /\A(-?\d+)\z/
|
14
|
+
FLOATS_REGEX = /\A(-?\d[\d\.]+)\z/
|
17
15
|
|
18
16
|
# Use an atomic group (?>...) to avoid pathological backtracing from
|
19
17
|
# malicious input as described in https://github.com/Shopify/liquid/issues/1357
|
20
|
-
RANGES_REGEX = /\A\
|
18
|
+
RANGES_REGEX = /\A\(\s*(?>(\S+)\s*\.\.)\s*(\S+)\s*\)\z/
|
21
19
|
|
22
20
|
def self.parse(markup)
|
21
|
+
return nil unless markup
|
22
|
+
|
23
|
+
markup = markup.strip
|
24
|
+
if (markup.start_with?('"') && markup.end_with?('"')) ||
|
25
|
+
(markup.start_with?("'") && markup.end_with?("'"))
|
26
|
+
return markup[1..-2]
|
27
|
+
end
|
28
|
+
|
23
29
|
case markup
|
24
|
-
when nil
|
25
|
-
nil
|
26
|
-
when SINGLE_QUOTED_STRING, DOUBLE_QUOTED_STRING
|
27
|
-
Regexp.last_match(1)
|
28
30
|
when INTEGERS_REGEX
|
29
31
|
Regexp.last_match(1).to_i
|
30
32
|
when RANGES_REGEX
|
@@ -32,7 +34,6 @@ module Liquid
|
|
32
34
|
when FLOATS_REGEX
|
33
35
|
Regexp.last_match(1).to_f
|
34
36
|
else
|
35
|
-
markup = markup.strip
|
36
37
|
if LITERALS.key?(markup)
|
37
38
|
LITERALS[markup]
|
38
39
|
else
|
data/lib/liquid/range_lookup.rb
CHANGED
@@ -12,6 +12,8 @@ module Liquid
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
attr_reader :start_obj, :end_obj
|
16
|
+
|
15
17
|
def initialize(start_obj, end_obj)
|
16
18
|
@start_obj = start_obj
|
17
19
|
@end_obj = end_obj
|
@@ -35,5 +37,11 @@ module Liquid
|
|
35
37
|
Utils.to_integer(input)
|
36
38
|
end
|
37
39
|
end
|
40
|
+
|
41
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
42
|
+
def children
|
43
|
+
[@node.start_obj, @node.end_obj]
|
44
|
+
end
|
45
|
+
end
|
38
46
|
end
|
39
47
|
end
|
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'cgi'
|
4
|
+
require 'base64'
|
4
5
|
require 'bigdecimal'
|
5
6
|
|
6
7
|
module Liquid
|
7
8
|
module StandardFilters
|
9
|
+
MAX_INT = (1 << 31) - 1
|
8
10
|
HTML_ESCAPE = {
|
9
11
|
'&' => '&',
|
10
12
|
'>' => '>',
|
@@ -62,6 +64,26 @@ module Liquid
|
|
62
64
|
result
|
63
65
|
end
|
64
66
|
|
67
|
+
def base64_encode(input)
|
68
|
+
Base64.strict_encode64(input.to_s)
|
69
|
+
end
|
70
|
+
|
71
|
+
def base64_decode(input)
|
72
|
+
Base64.strict_decode64(input.to_s)
|
73
|
+
rescue ::ArgumentError
|
74
|
+
raise Liquid::ArgumentError, "invalid base64 provided to base64_decode"
|
75
|
+
end
|
76
|
+
|
77
|
+
def base64_url_safe_encode(input)
|
78
|
+
Base64.urlsafe_encode64(input.to_s)
|
79
|
+
end
|
80
|
+
|
81
|
+
def base64_url_safe_decode(input)
|
82
|
+
Base64.urlsafe_decode64(input.to_s)
|
83
|
+
rescue ::ArgumentError
|
84
|
+
raise Liquid::ArgumentError, "invalid base64 provided to base64_url_safe_decode"
|
85
|
+
end
|
86
|
+
|
65
87
|
def slice(input, offset, length = nil)
|
66
88
|
offset = Utils.to_integer(offset)
|
67
89
|
length = length ? Utils.to_integer(length) : 1
|
@@ -93,7 +115,13 @@ module Liquid
|
|
93
115
|
words = Utils.to_integer(words)
|
94
116
|
words = 1 if words <= 0
|
95
117
|
|
96
|
-
wordlist =
|
118
|
+
wordlist = begin
|
119
|
+
input.split(" ", words + 1)
|
120
|
+
rescue RangeError
|
121
|
+
raise if words + 1 < MAX_INT
|
122
|
+
# e.g. integer #{words} too big to convert to `int'
|
123
|
+
raise Liquid::ArgumentError, "integer #{words} too big for truncatewords"
|
124
|
+
end
|
97
125
|
return input if wordlist.length <= words
|
98
126
|
|
99
127
|
wordlist.pop
|
@@ -185,17 +213,23 @@ module Liquid
|
|
185
213
|
|
186
214
|
if ary.empty?
|
187
215
|
[]
|
188
|
-
elsif
|
189
|
-
|
190
|
-
|
216
|
+
elsif target_value.nil?
|
217
|
+
ary.select do |item|
|
218
|
+
item[property]
|
191
219
|
rescue TypeError
|
192
220
|
raise_property_error(property)
|
221
|
+
rescue NoMethodError
|
222
|
+
return nil unless item.respond_to?(:[])
|
223
|
+
raise
|
193
224
|
end
|
194
|
-
|
195
|
-
|
196
|
-
|
225
|
+
else
|
226
|
+
ary.select do |item|
|
227
|
+
item[property] == target_value
|
197
228
|
rescue TypeError
|
198
229
|
raise_property_error(property)
|
230
|
+
rescue NoMethodError
|
231
|
+
return nil unless item.respond_to?(:[])
|
232
|
+
raise
|
199
233
|
end
|
200
234
|
end
|
201
235
|
end
|
@@ -209,11 +243,14 @@ module Liquid
|
|
209
243
|
ary.uniq
|
210
244
|
elsif ary.empty? # The next two cases assume a non-empty array.
|
211
245
|
[]
|
212
|
-
|
213
|
-
|
214
|
-
|
246
|
+
else
|
247
|
+
ary.uniq do |item|
|
248
|
+
item[property]
|
215
249
|
rescue TypeError
|
216
250
|
raise_property_error(property)
|
251
|
+
rescue NoMethodError
|
252
|
+
return nil unless item.respond_to?(:[])
|
253
|
+
raise
|
217
254
|
end
|
218
255
|
end
|
219
256
|
end
|
@@ -249,11 +286,14 @@ module Liquid
|
|
249
286
|
ary.compact
|
250
287
|
elsif ary.empty? # The next two cases assume a non-empty array.
|
251
288
|
[]
|
252
|
-
|
253
|
-
|
254
|
-
|
289
|
+
else
|
290
|
+
ary.reject do |item|
|
291
|
+
item[property].nil?
|
255
292
|
rescue TypeError
|
256
293
|
raise_property_error(property)
|
294
|
+
rescue NoMethodError
|
295
|
+
return nil unless item.respond_to?(:[])
|
296
|
+
raise
|
257
297
|
end
|
258
298
|
end
|
259
299
|
end
|
@@ -268,14 +308,34 @@ module Liquid
|
|
268
308
|
input.to_s.sub(string.to_s, replacement.to_s)
|
269
309
|
end
|
270
310
|
|
311
|
+
# Replace the last occurrences of a string with another
|
312
|
+
def replace_last(input, string, replacement)
|
313
|
+
input = input.to_s
|
314
|
+
string = string.to_s
|
315
|
+
replacement = replacement.to_s
|
316
|
+
|
317
|
+
start_index = input.rindex(string)
|
318
|
+
|
319
|
+
return input unless start_index
|
320
|
+
|
321
|
+
output = input.dup
|
322
|
+
output[start_index, string.length] = replacement
|
323
|
+
output
|
324
|
+
end
|
325
|
+
|
271
326
|
# remove a substring
|
272
327
|
def remove(input, string)
|
273
|
-
input
|
328
|
+
replace(input, string, '')
|
274
329
|
end
|
275
330
|
|
276
331
|
# remove the first occurrences of a substring
|
277
332
|
def remove_first(input, string)
|
278
|
-
input
|
333
|
+
replace_first(input, string, '')
|
334
|
+
end
|
335
|
+
|
336
|
+
# remove the last occurences of a substring
|
337
|
+
def remove_last(input, string)
|
338
|
+
replace_last(input, string, '')
|
279
339
|
end
|
280
340
|
|
281
341
|
# add one string to another
|
@@ -440,7 +500,7 @@ module Liquid
|
|
440
500
|
#
|
441
501
|
def default(input, default_value = '', options = {})
|
442
502
|
options = {} unless options.is_a?(Hash)
|
443
|
-
false_check = options['allow_false'] ? input.nil? : !input
|
503
|
+
false_check = options['allow_false'] ? input.nil? : !Liquid::Utils.to_liquid_value(input)
|
444
504
|
false_check || (input.respond_to?(:empty?) && input.empty?) ? default_value : input
|
445
505
|
end
|
446
506
|
|
@@ -458,10 +518,16 @@ module Liquid
|
|
458
518
|
end
|
459
519
|
|
460
520
|
def nil_safe_compare(a, b)
|
461
|
-
|
462
|
-
|
521
|
+
result = a <=> b
|
522
|
+
|
523
|
+
if result
|
524
|
+
result
|
525
|
+
elsif a.nil?
|
526
|
+
1
|
527
|
+
elsif b.nil?
|
528
|
+
-1
|
463
529
|
else
|
464
|
-
|
530
|
+
raise Liquid::ArgumentError, "cannot sort values of incompatible types"
|
465
531
|
end
|
466
532
|
end
|
467
533
|
|
@@ -516,8 +582,9 @@ module Liquid
|
|
516
582
|
|
517
583
|
def each
|
518
584
|
@input.each do |e|
|
585
|
+
e = e.respond_to?(:to_liquid) ? e.to_liquid : e
|
519
586
|
e.context = @context if e.respond_to?(:context=)
|
520
|
-
yield(e
|
587
|
+
yield(e)
|
521
588
|
end
|
522
589
|
end
|
523
590
|
end
|
@@ -31,7 +31,11 @@ module Liquid
|
|
31
31
|
if @registers.key?(key)
|
32
32
|
@registers.fetch(key)
|
33
33
|
elsif default != UNDEFINED
|
34
|
-
|
34
|
+
if block_given?
|
35
|
+
@static.fetch(key, &block)
|
36
|
+
else
|
37
|
+
@static.fetch(key, default)
|
38
|
+
end
|
35
39
|
else
|
36
40
|
@static.fetch(key, &block)
|
37
41
|
end
|
@@ -7,25 +7,26 @@ module Liquid
|
|
7
7
|
|
8
8
|
def add_global_filter(filter)
|
9
9
|
strainer_class_cache.clear
|
10
|
-
|
10
|
+
GlobalCache.add_filter(filter)
|
11
11
|
end
|
12
12
|
|
13
13
|
def create(context, filters = [])
|
14
14
|
strainer_from_cache(filters).new(context)
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
GlobalCache = Class.new(StrainerTemplate)
|
18
18
|
|
19
|
-
|
20
|
-
@global_filters ||= []
|
21
|
-
end
|
19
|
+
private
|
22
20
|
|
23
21
|
def strainer_from_cache(filters)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
filters
|
28
|
-
|
22
|
+
if filters.empty?
|
23
|
+
GlobalCache
|
24
|
+
else
|
25
|
+
strainer_class_cache[filters] ||= begin
|
26
|
+
klass = Class.new(GlobalCache)
|
27
|
+
filters.each { |f| klass.add_filter(f) }
|
28
|
+
klass
|
29
|
+
end
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
data/lib/liquid/tags/case.rb
CHANGED
@@ -52,7 +52,14 @@ module Liquid
|
|
52
52
|
@blocks.each do |block|
|
53
53
|
if block.else?
|
54
54
|
block.attachment.render_to_output_buffer(context, output) if execute_else_block
|
55
|
-
|
55
|
+
next
|
56
|
+
end
|
57
|
+
|
58
|
+
result = Liquid::Utils.to_liquid_value(
|
59
|
+
block.evaluate(context)
|
60
|
+
)
|
61
|
+
|
62
|
+
if result
|
56
63
|
execute_else_block = false
|
57
64
|
block.attachment.render_to_output_buffer(context, output)
|
58
65
|
end
|
data/lib/liquid/tags/if.rb
CHANGED
@@ -50,7 +50,11 @@ module Liquid
|
|
50
50
|
|
51
51
|
def render_to_output_buffer(context, output)
|
52
52
|
@blocks.each do |block|
|
53
|
-
|
53
|
+
result = Liquid::Utils.to_liquid_value(
|
54
|
+
block.evaluate(context)
|
55
|
+
)
|
56
|
+
|
57
|
+
if result
|
54
58
|
return block.attachment.render_to_output_buffer(context, output)
|
55
59
|
end
|
56
60
|
end
|
data/lib/liquid/tags/unless.rb
CHANGED
@@ -11,13 +11,21 @@ module Liquid
|
|
11
11
|
def render_to_output_buffer(context, output)
|
12
12
|
# First condition is interpreted backwards ( if not )
|
13
13
|
first_block = @blocks.first
|
14
|
-
|
14
|
+
result = Liquid::Utils.to_liquid_value(
|
15
|
+
first_block.evaluate(context)
|
16
|
+
)
|
17
|
+
|
18
|
+
unless result
|
15
19
|
return first_block.attachment.render_to_output_buffer(context, output)
|
16
20
|
end
|
17
21
|
|
18
22
|
# After the first condition unless works just like if
|
19
23
|
@blocks[1..-1].each do |block|
|
20
|
-
|
24
|
+
result = Liquid::Utils.to_liquid_value(
|
25
|
+
block.evaluate(context)
|
26
|
+
)
|
27
|
+
|
28
|
+
if result
|
21
29
|
return block.attachment.render_to_output_buffer(context, output)
|
22
30
|
end
|
23
31
|
end
|
data/lib/liquid/tokenizer.rb
CHANGED
@@ -5,7 +5,7 @@ module Liquid
|
|
5
5
|
attr_reader :line_number, :for_liquid_tag
|
6
6
|
|
7
7
|
def initialize(source, line_numbers = false, line_number: nil, for_liquid_tag: false)
|
8
|
-
@source = source
|
8
|
+
@source = source.to_s.to_str
|
9
9
|
@line_number = line_number || (line_numbers ? 1 : nil)
|
10
10
|
@for_liquid_tag = for_liquid_tag
|
11
11
|
@tokens = tokenize
|
@@ -24,7 +24,7 @@ module Liquid
|
|
24
24
|
private
|
25
25
|
|
26
26
|
def tokenize
|
27
|
-
return [] if @source.
|
27
|
+
return [] if @source.empty?
|
28
28
|
|
29
29
|
return @source.split("\n") if @for_liquid_tag
|
30
30
|
|
data/lib/liquid/utils.rb
CHANGED
@@ -81,5 +81,13 @@ module Liquid
|
|
81
81
|
rescue ::ArgumentError
|
82
82
|
nil
|
83
83
|
end
|
84
|
+
|
85
|
+
def self.to_liquid_value(obj)
|
86
|
+
# Enable "obj" to represent itself as a primitive value like integer, string, or boolean
|
87
|
+
return obj.to_liquid_value if obj.respond_to?(:to_liquid_value)
|
88
|
+
|
89
|
+
# Otherwise return the object itself
|
90
|
+
obj
|
91
|
+
end
|
84
92
|
end
|
85
93
|
end
|
@@ -40,6 +40,9 @@ module Liquid
|
|
40
40
|
@lookups.each_index do |i|
|
41
41
|
key = context.evaluate(@lookups[i])
|
42
42
|
|
43
|
+
# Cast "key" to its liquid value to enable it to act as a primitive value
|
44
|
+
key = Liquid::Utils.to_liquid_value(key)
|
45
|
+
|
43
46
|
# If object is a hash- or array-like object we look for the
|
44
47
|
# presence of the key and if its available we return it
|
45
48
|
if object.respond_to?(:[]) &&
|
data/lib/liquid/version.rb
CHANGED
data/lib/liquid.rb
CHANGED
@@ -36,7 +36,7 @@ module Liquid
|
|
36
36
|
VariableIncompleteEnd = /\}\}?/
|
37
37
|
QuotedString = /"[^"]*"|'[^']*'/
|
38
38
|
QuotedFragment = /#{QuotedString}|(?:[^\s,\|'"]|#{QuotedString})+/o
|
39
|
-
TagAttributes = /(\w
|
39
|
+
TagAttributes = /(\w[\w-]*)\s*\:\s*(#{QuotedFragment})/o
|
40
40
|
AnyStartingTag = /#{TagStart}|#{VariableStart}/o
|
41
41
|
PartialTemplateParser = /#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd}/om
|
42
42
|
TemplateParser = /(#{PartialTemplateParser}|#{AnyStartingTag})/om
|
@@ -59,8 +59,8 @@ require 'liquid/forloop_drop'
|
|
59
59
|
require 'liquid/extensions'
|
60
60
|
require 'liquid/errors'
|
61
61
|
require 'liquid/interrupts'
|
62
|
-
require 'liquid/strainer_factory'
|
63
62
|
require 'liquid/strainer_template'
|
63
|
+
require 'liquid/strainer_factory'
|
64
64
|
require 'liquid/expression'
|
65
65
|
require 'liquid/context'
|
66
66
|
require 'liquid/parser_switching'
|
@@ -24,7 +24,7 @@ class ContextSensitiveDrop < Liquid::Drop
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
class Category
|
27
|
+
class Category
|
28
28
|
attr_accessor :name
|
29
29
|
|
30
30
|
def initialize(name)
|
@@ -36,8 +36,9 @@ class Category < Liquid::Drop
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
class CategoryDrop
|
39
|
+
class CategoryDrop < Liquid::Drop
|
40
40
|
attr_accessor :category, :context
|
41
|
+
|
41
42
|
def initialize(category)
|
42
43
|
@category = category
|
43
44
|
end
|
@@ -405,45 +406,42 @@ class ContextTest < Minitest::Test
|
|
405
406
|
end
|
406
407
|
|
407
408
|
def test_lambda_is_called_once
|
409
|
+
@global = 0
|
410
|
+
|
408
411
|
@context['callcount'] = proc {
|
409
|
-
@global
|
410
|
-
@global += 1
|
412
|
+
@global += 1
|
411
413
|
@global.to_s
|
412
414
|
}
|
413
415
|
|
414
416
|
assert_equal('1', @context['callcount'])
|
415
417
|
assert_equal('1', @context['callcount'])
|
416
418
|
assert_equal('1', @context['callcount'])
|
417
|
-
|
418
|
-
@global = nil
|
419
419
|
end
|
420
420
|
|
421
421
|
def test_nested_lambda_is_called_once
|
422
|
+
@global = 0
|
423
|
+
|
422
424
|
@context['callcount'] = { "lambda" => proc {
|
423
|
-
@global
|
424
|
-
@global += 1
|
425
|
+
@global += 1
|
425
426
|
@global.to_s
|
426
427
|
} }
|
427
428
|
|
428
429
|
assert_equal('1', @context['callcount.lambda'])
|
429
430
|
assert_equal('1', @context['callcount.lambda'])
|
430
431
|
assert_equal('1', @context['callcount.lambda'])
|
431
|
-
|
432
|
-
@global = nil
|
433
432
|
end
|
434
433
|
|
435
434
|
def test_lambda_in_array_is_called_once
|
435
|
+
@global = 0
|
436
|
+
|
436
437
|
@context['callcount'] = [1, 2, proc {
|
437
|
-
@global
|
438
|
-
@global += 1
|
438
|
+
@global += 1
|
439
439
|
@global.to_s
|
440
440
|
}, 4, 5]
|
441
441
|
|
442
442
|
assert_equal('1', @context['callcount[2]'])
|
443
443
|
assert_equal('1', @context['callcount[2]'])
|
444
444
|
assert_equal('1', @context['callcount[2]'])
|
445
|
-
|
446
|
-
@global = nil
|
447
445
|
end
|
448
446
|
|
449
447
|
def test_access_to_context_from_proc
|