liquid 5.6.4 → 5.7.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 +44 -2
- data/lib/liquid/standardfilters.rb +167 -61
- data/lib/liquid/utils.rb +96 -0
- data/lib/liquid/variable.rb +2 -2
- data/lib/liquid/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72a0f18697a90c81db846fc86027cbec36198105fb458d40989f88b1acd55687
|
4
|
+
data.tar.gz: ba8f6ecc9612f737f954006109b91759ea7cea41074de2ab38e73221d4e18be2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad608314f023c78123d3cf57a3c9b54229ec7dca712f1b3897218c27880e5f78d7188cdce775d15759960803a31c5e7d1adc81c9282ab784a6f6fa50efeb051e
|
7
|
+
data.tar.gz: 6988a403789ca9a3a3d3d48e5cba0639f81226b3cd8af477dcce1d8eeb9db3693e90b373ea391f5d458a723ec40d7c0c6d28f7e445d3d0562b219e9cbcfff1ee
|
data/History.md
CHANGED
@@ -1,11 +1,53 @@
|
|
1
1
|
# Liquid Change Log
|
2
2
|
|
3
|
-
## 5.
|
3
|
+
## 5.8.0 (unreleased)
|
4
|
+
|
5
|
+
## 5.7.0 2025-01-16
|
6
|
+
|
7
|
+
### Features
|
8
|
+
* Add `find`, `find_index`, `has`, and `reject` filters to arrays
|
9
|
+
* Compatibility with Ruby 3.4
|
10
|
+
|
11
|
+
## 5.6.4 2025-01-14
|
4
12
|
|
5
13
|
### Fixes
|
14
|
+
* Add a default `string_scanner` to avoid errors with `Liquid::VariableLookup.parse("foo.bar")` [Ian Ker-Seymer]
|
6
15
|
|
7
|
-
|
16
|
+
## 5.6.3 2025-01-13
|
17
|
+
* Remove `lru_redux` dependency [Michael Go]
|
18
|
+
|
19
|
+
## 5.6.2 2025-01-13
|
20
|
+
|
21
|
+
### Fixes
|
22
|
+
* Preserve the old behavior of requiring floats to start with a digit [Michael Go]
|
8
23
|
|
24
|
+
## 5.6.1 2025-01-13
|
25
|
+
|
26
|
+
### Performance improvements
|
27
|
+
* Faster Expression parser / Tokenizer with StringScanner [Michael Go]
|
28
|
+
|
29
|
+
## 5.6.0 2024-12-19
|
30
|
+
|
31
|
+
### Architectural changes
|
32
|
+
* Added new `Environment` class to manage configuration and state that was previously stored in `Template` [Ian Ker-Seymer]
|
33
|
+
* Moved tag registration from `Template` to `Environment` [Ian Ker-Seymer]
|
34
|
+
* Removed `StrainerFactory` in favor of `Environment`-based strainer creation [Ian Ker-Seymer]
|
35
|
+
* Consolidated standard tags into a new `Tags` module with `STANDARD_TAGS` constant [Ian Ker-Seymer]
|
36
|
+
|
37
|
+
### Performance improvements
|
38
|
+
* Optimized `Lexer` with a new `Lexer2` implementation using jump tables for faster tokenization, requires Ruby 3.4 [Ian Ker-Seymer]
|
39
|
+
* Improved variable rendering with specialized handling for different types [Michael Go]
|
40
|
+
* Reduced array allocations by using frozen empty constants [Michael Go]
|
41
|
+
|
42
|
+
### API changes
|
43
|
+
* Deprecated several `Template` class methods in favor of `Environment` methods [Ian Ker-Seymer]
|
44
|
+
* Added deprecation warnings system [Ian Ker-Seymer]
|
45
|
+
* Changed how filters and tags are registered to use Environment [Ian Ker-Seymer]
|
46
|
+
|
47
|
+
### Fixes
|
48
|
+
* Fixed table row handling of break interrupts [Alex Coco]
|
49
|
+
* Improved variable output handling for arrays [Ian Ker-Seymer]
|
50
|
+
* Fix Tokenizer to handle null source value (#1873) [Bahar Pourazar]
|
9
51
|
|
10
52
|
## 5.5.0 2024-03-21
|
11
53
|
|
@@ -64,7 +64,7 @@ module Liquid
|
|
64
64
|
# @liquid_syntax string | downcase
|
65
65
|
# @liquid_return [string]
|
66
66
|
def downcase(input)
|
67
|
-
|
67
|
+
Utils.to_s(input).downcase
|
68
68
|
end
|
69
69
|
|
70
70
|
# @liquid_public_docs
|
@@ -75,7 +75,7 @@ module Liquid
|
|
75
75
|
# @liquid_syntax string | upcase
|
76
76
|
# @liquid_return [string]
|
77
77
|
def upcase(input)
|
78
|
-
|
78
|
+
Utils.to_s(input).upcase
|
79
79
|
end
|
80
80
|
|
81
81
|
# @liquid_public_docs
|
@@ -86,7 +86,7 @@ module Liquid
|
|
86
86
|
# @liquid_syntax string | capitalize
|
87
87
|
# @liquid_return [string]
|
88
88
|
def capitalize(input)
|
89
|
-
|
89
|
+
Utils.to_s(input).capitalize
|
90
90
|
end
|
91
91
|
|
92
92
|
# @liquid_public_docs
|
@@ -97,7 +97,7 @@ module Liquid
|
|
97
97
|
# @liquid_syntax string | escape
|
98
98
|
# @liquid_return [string]
|
99
99
|
def escape(input)
|
100
|
-
CGI.escapeHTML(
|
100
|
+
CGI.escapeHTML(Utils.to_s(input)) unless input.nil?
|
101
101
|
end
|
102
102
|
alias_method :h, :escape
|
103
103
|
|
@@ -109,7 +109,7 @@ module Liquid
|
|
109
109
|
# @liquid_syntax string | escape_once
|
110
110
|
# @liquid_return [string]
|
111
111
|
def escape_once(input)
|
112
|
-
|
112
|
+
Utils.to_s(input).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
|
113
113
|
end
|
114
114
|
|
115
115
|
# @liquid_public_docs
|
@@ -124,7 +124,7 @@ module Liquid
|
|
124
124
|
# @liquid_syntax string | url_encode
|
125
125
|
# @liquid_return [string]
|
126
126
|
def url_encode(input)
|
127
|
-
CGI.escape(
|
127
|
+
CGI.escape(Utils.to_s(input)) unless input.nil?
|
128
128
|
end
|
129
129
|
|
130
130
|
# @liquid_public_docs
|
@@ -138,7 +138,7 @@ module Liquid
|
|
138
138
|
def url_decode(input)
|
139
139
|
return if input.nil?
|
140
140
|
|
141
|
-
result = CGI.unescape(
|
141
|
+
result = CGI.unescape(Utils.to_s(input))
|
142
142
|
raise Liquid::ArgumentError, "invalid byte sequence in #{result.encoding}" unless result.valid_encoding?
|
143
143
|
|
144
144
|
result
|
@@ -152,7 +152,7 @@ module Liquid
|
|
152
152
|
# @liquid_syntax string | base64_encode
|
153
153
|
# @liquid_return [string]
|
154
154
|
def base64_encode(input)
|
155
|
-
Base64.strict_encode64(
|
155
|
+
Base64.strict_encode64(Utils.to_s(input))
|
156
156
|
end
|
157
157
|
|
158
158
|
# @liquid_public_docs
|
@@ -163,7 +163,7 @@ module Liquid
|
|
163
163
|
# @liquid_syntax string | base64_decode
|
164
164
|
# @liquid_return [string]
|
165
165
|
def base64_decode(input)
|
166
|
-
input =
|
166
|
+
input = Utils.to_s(input)
|
167
167
|
StandardFilters.try_coerce_encoding(Base64.strict_decode64(input), encoding: input.encoding)
|
168
168
|
rescue ::ArgumentError
|
169
169
|
raise Liquid::ArgumentError, "invalid base64 provided to base64_decode"
|
@@ -177,7 +177,7 @@ module Liquid
|
|
177
177
|
# @liquid_syntax string | base64_url_safe_encode
|
178
178
|
# @liquid_return [string]
|
179
179
|
def base64_url_safe_encode(input)
|
180
|
-
Base64.urlsafe_encode64(
|
180
|
+
Base64.urlsafe_encode64(Utils.to_s(input))
|
181
181
|
end
|
182
182
|
|
183
183
|
# @liquid_public_docs
|
@@ -188,7 +188,7 @@ module Liquid
|
|
188
188
|
# @liquid_syntax string | base64_url_safe_decode
|
189
189
|
# @liquid_return [string]
|
190
190
|
def base64_url_safe_decode(input)
|
191
|
-
input =
|
191
|
+
input = Utils.to_s(input)
|
192
192
|
StandardFilters.try_coerce_encoding(Base64.urlsafe_decode64(input), encoding: input.encoding)
|
193
193
|
rescue ::ArgumentError
|
194
194
|
raise Liquid::ArgumentError, "invalid base64 provided to base64_url_safe_decode"
|
@@ -212,7 +212,7 @@ module Liquid
|
|
212
212
|
if input.is_a?(Array)
|
213
213
|
input.slice(offset, length) || []
|
214
214
|
else
|
215
|
-
|
215
|
+
Utils.to_s(input).slice(offset, length) || ''
|
216
216
|
end
|
217
217
|
rescue RangeError
|
218
218
|
if I64_RANGE.cover?(length) && I64_RANGE.cover?(offset)
|
@@ -236,10 +236,10 @@ module Liquid
|
|
236
236
|
# @liquid_return [string]
|
237
237
|
def truncate(input, length = 50, truncate_string = "...")
|
238
238
|
return if input.nil?
|
239
|
-
input_str =
|
239
|
+
input_str = Utils.to_s(input)
|
240
240
|
length = Utils.to_integer(length)
|
241
241
|
|
242
|
-
truncate_string_str =
|
242
|
+
truncate_string_str = Utils.to_s(truncate_string)
|
243
243
|
|
244
244
|
l = length - truncate_string_str.length
|
245
245
|
l = 0 if l < 0
|
@@ -263,7 +263,7 @@ module Liquid
|
|
263
263
|
# @liquid_return [string]
|
264
264
|
def truncatewords(input, words = 15, truncate_string = "...")
|
265
265
|
return if input.nil?
|
266
|
-
input =
|
266
|
+
input = Utils.to_s(input)
|
267
267
|
words = Utils.to_integer(words)
|
268
268
|
words = 1 if words <= 0
|
269
269
|
|
@@ -277,7 +277,8 @@ module Liquid
|
|
277
277
|
return input if wordlist.length <= words
|
278
278
|
|
279
279
|
wordlist.pop
|
280
|
-
|
280
|
+
truncate_string = Utils.to_s(truncate_string)
|
281
|
+
wordlist.join(" ").concat(truncate_string)
|
281
282
|
end
|
282
283
|
|
283
284
|
# @liquid_public_docs
|
@@ -288,7 +289,9 @@ module Liquid
|
|
288
289
|
# @liquid_syntax string | split: string
|
289
290
|
# @liquid_return [array[string]]
|
290
291
|
def split(input, pattern)
|
291
|
-
|
292
|
+
pattern = Utils.to_s(pattern)
|
293
|
+
input = Utils.to_s(input)
|
294
|
+
input.split(pattern)
|
292
295
|
end
|
293
296
|
|
294
297
|
# @liquid_public_docs
|
@@ -299,7 +302,8 @@ module Liquid
|
|
299
302
|
# @liquid_syntax string | strip
|
300
303
|
# @liquid_return [string]
|
301
304
|
def strip(input)
|
302
|
-
input.to_s
|
305
|
+
input = Utils.to_s(input)
|
306
|
+
input.strip
|
303
307
|
end
|
304
308
|
|
305
309
|
# @liquid_public_docs
|
@@ -310,7 +314,8 @@ module Liquid
|
|
310
314
|
# @liquid_syntax string | lstrip
|
311
315
|
# @liquid_return [string]
|
312
316
|
def lstrip(input)
|
313
|
-
input.to_s
|
317
|
+
input = Utils.to_s(input)
|
318
|
+
input.lstrip
|
314
319
|
end
|
315
320
|
|
316
321
|
# @liquid_public_docs
|
@@ -321,7 +326,8 @@ module Liquid
|
|
321
326
|
# @liquid_syntax string | rstrip
|
322
327
|
# @liquid_return [string]
|
323
328
|
def rstrip(input)
|
324
|
-
input.to_s
|
329
|
+
input = Utils.to_s(input)
|
330
|
+
input.rstrip
|
325
331
|
end
|
326
332
|
|
327
333
|
# @liquid_public_docs
|
@@ -332,8 +338,9 @@ module Liquid
|
|
332
338
|
# @liquid_syntax string | strip_html
|
333
339
|
# @liquid_return [string]
|
334
340
|
def strip_html(input)
|
341
|
+
input = Utils.to_s(input)
|
335
342
|
empty = ''
|
336
|
-
result = input.
|
343
|
+
result = input.gsub(STRIP_HTML_BLOCKS, empty)
|
337
344
|
result.gsub!(STRIP_HTML_TAGS, empty)
|
338
345
|
result
|
339
346
|
end
|
@@ -346,7 +353,8 @@ module Liquid
|
|
346
353
|
# @liquid_syntax string | strip_newlines
|
347
354
|
# @liquid_return [string]
|
348
355
|
def strip_newlines(input)
|
349
|
-
input.to_s
|
356
|
+
input = Utils.to_s(input)
|
357
|
+
input.gsub(/\r?\n/, '')
|
350
358
|
end
|
351
359
|
|
352
360
|
# @liquid_public_docs
|
@@ -357,6 +365,7 @@ module Liquid
|
|
357
365
|
# @liquid_syntax array | join
|
358
366
|
# @liquid_return [string]
|
359
367
|
def join(input, glue = ' ')
|
368
|
+
glue = Utils.to_s(glue)
|
360
369
|
InputIterator.new(input, context).join(glue)
|
361
370
|
end
|
362
371
|
|
@@ -378,7 +387,7 @@ module Liquid
|
|
378
387
|
end
|
379
388
|
elsif ary.all? { |el| el.respond_to?(:[]) }
|
380
389
|
begin
|
381
|
-
ary.sort { |a, b| nil_safe_compare(a
|
390
|
+
ary.sort { |a, b| nil_safe_compare(fetch_property(a, property), fetch_property(b, property)) }
|
382
391
|
rescue TypeError
|
383
392
|
raise_property_error(property)
|
384
393
|
end
|
@@ -407,7 +416,7 @@ module Liquid
|
|
407
416
|
end
|
408
417
|
elsif ary.all? { |el| el.respond_to?(:[]) }
|
409
418
|
begin
|
410
|
-
ary.sort { |a, b| nil_safe_casecmp(a
|
419
|
+
ary.sort { |a, b| nil_safe_casecmp(fetch_property(a, property), fetch_property(b, property)) }
|
411
420
|
rescue TypeError
|
412
421
|
raise_property_error(property)
|
413
422
|
end
|
@@ -424,29 +433,59 @@ module Liquid
|
|
424
433
|
# @liquid_syntax array | where: string, string
|
425
434
|
# @liquid_return [array[untyped]]
|
426
435
|
def where(input, property, target_value = nil)
|
427
|
-
ary
|
436
|
+
filter_array(input, property, target_value) { |ary, &block| ary.select(&block) }
|
437
|
+
end
|
428
438
|
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
439
|
+
# @liquid_public_docs
|
440
|
+
# @liquid_type filter
|
441
|
+
# @liquid_category array
|
442
|
+
# @liquid_summary
|
443
|
+
# Filters an array to exclude items with a specific property value.
|
444
|
+
# @liquid_description
|
445
|
+
# This requires you to provide both the property name and the associated value.
|
446
|
+
# @liquid_syntax array | reject: string, string
|
447
|
+
# @liquid_return [array[untyped]]
|
448
|
+
def reject(input, property, target_value = nil)
|
449
|
+
filter_array(input, property, target_value) { |ary, &block| ary.reject(&block) }
|
450
|
+
end
|
451
|
+
|
452
|
+
# @liquid_public_docs
|
453
|
+
# @liquid_type filter
|
454
|
+
# @liquid_category array
|
455
|
+
# @liquid_summary
|
456
|
+
# Tests if any item in an array has a specific property value.
|
457
|
+
# @liquid_description
|
458
|
+
# This requires you to provide both the property name and the associated value.
|
459
|
+
# @liquid_syntax array | some: string, string
|
460
|
+
# @liquid_return [boolean]
|
461
|
+
def has(input, property, target_value = nil)
|
462
|
+
filter_array(input, property, target_value) { |ary, &block| ary.any?(&block) }
|
463
|
+
end
|
464
|
+
|
465
|
+
# @liquid_public_docs
|
466
|
+
# @liquid_type filter
|
467
|
+
# @liquid_category array
|
468
|
+
# @liquid_summary
|
469
|
+
# Returns the first item in an array with a specific property value.
|
470
|
+
# @liquid_description
|
471
|
+
# This requires you to provide both the property name and the associated value.
|
472
|
+
# @liquid_syntax array | find: string, string
|
473
|
+
# @liquid_return [untyped]
|
474
|
+
def find(input, property, target_value = nil)
|
475
|
+
filter_array(input, property, target_value) { |ary, &block| ary.find(&block) }
|
476
|
+
end
|
477
|
+
|
478
|
+
# @liquid_public_docs
|
479
|
+
# @liquid_type filter
|
480
|
+
# @liquid_category array
|
481
|
+
# @liquid_summary
|
482
|
+
# Returns the index of the first item in an array with a specific property value.
|
483
|
+
# @liquid_description
|
484
|
+
# This requires you to provide both the property name and the associated value.
|
485
|
+
# @liquid_syntax array | find_index: string, string
|
486
|
+
# @liquid_return [number]
|
487
|
+
def find_index(input, property, target_value = nil)
|
488
|
+
filter_array(input, property, target_value) { |ary, &block| ary.find_index(&block) }
|
450
489
|
end
|
451
490
|
|
452
491
|
# @liquid_public_docs
|
@@ -465,7 +504,7 @@ module Liquid
|
|
465
504
|
[]
|
466
505
|
else
|
467
506
|
ary.uniq do |item|
|
468
|
-
item
|
507
|
+
fetch_property(item, property)
|
469
508
|
rescue TypeError
|
470
509
|
raise_property_error(property)
|
471
510
|
rescue NoMethodError
|
@@ -501,7 +540,7 @@ module Liquid
|
|
501
540
|
if property == "to_liquid"
|
502
541
|
e
|
503
542
|
elsif e.respond_to?(:[])
|
504
|
-
r = e
|
543
|
+
r = fetch_property(e, property)
|
505
544
|
r.is_a?(Proc) ? r.call : r
|
506
545
|
end
|
507
546
|
end
|
@@ -525,7 +564,7 @@ module Liquid
|
|
525
564
|
[]
|
526
565
|
else
|
527
566
|
ary.reject do |item|
|
528
|
-
item
|
567
|
+
fetch_property(item, property).nil?
|
529
568
|
rescue TypeError
|
530
569
|
raise_property_error(property)
|
531
570
|
rescue NoMethodError
|
@@ -543,7 +582,10 @@ module Liquid
|
|
543
582
|
# @liquid_syntax string | replace: string, string
|
544
583
|
# @liquid_return [string]
|
545
584
|
def replace(input, string, replacement = '')
|
546
|
-
|
585
|
+
string = Utils.to_s(string)
|
586
|
+
replacement = Utils.to_s(replacement)
|
587
|
+
input = Utils.to_s(input)
|
588
|
+
input.gsub(string, replacement)
|
547
589
|
end
|
548
590
|
|
549
591
|
# @liquid_public_docs
|
@@ -554,7 +596,10 @@ module Liquid
|
|
554
596
|
# @liquid_syntax string | replace_first: string, string
|
555
597
|
# @liquid_return [string]
|
556
598
|
def replace_first(input, string, replacement = '')
|
557
|
-
|
599
|
+
string = Utils.to_s(string)
|
600
|
+
replacement = Utils.to_s(replacement)
|
601
|
+
input = Utils.to_s(input)
|
602
|
+
input.sub(string, replacement)
|
558
603
|
end
|
559
604
|
|
560
605
|
# @liquid_public_docs
|
@@ -565,9 +610,9 @@ module Liquid
|
|
565
610
|
# @liquid_syntax string | replace_last: string, string
|
566
611
|
# @liquid_return [string]
|
567
612
|
def replace_last(input, string, replacement)
|
568
|
-
input =
|
569
|
-
string =
|
570
|
-
replacement =
|
613
|
+
input = Utils.to_s(input)
|
614
|
+
string = Utils.to_s(string)
|
615
|
+
replacement = Utils.to_s(replacement)
|
571
616
|
|
572
617
|
start_index = input.rindex(string)
|
573
618
|
|
@@ -619,7 +664,9 @@ module Liquid
|
|
619
664
|
# @liquid_syntax string | append: string
|
620
665
|
# @liquid_return [string]
|
621
666
|
def append(input, string)
|
622
|
-
input
|
667
|
+
input = Utils.to_s(input)
|
668
|
+
string = Utils.to_s(string)
|
669
|
+
input + string
|
623
670
|
end
|
624
671
|
|
625
672
|
# @liquid_public_docs
|
@@ -648,7 +695,9 @@ module Liquid
|
|
648
695
|
# @liquid_syntax string | prepend: string
|
649
696
|
# @liquid_return [string]
|
650
697
|
def prepend(input, string)
|
651
|
-
|
698
|
+
input = Utils.to_s(input)
|
699
|
+
string = Utils.to_s(string)
|
700
|
+
string + input
|
652
701
|
end
|
653
702
|
|
654
703
|
# @liquid_public_docs
|
@@ -659,7 +708,8 @@ module Liquid
|
|
659
708
|
# @liquid_syntax string | newline_to_br
|
660
709
|
# @liquid_return [string]
|
661
710
|
def newline_to_br(input)
|
662
|
-
input.to_s
|
711
|
+
input = Utils.to_s(input)
|
712
|
+
input.gsub(/\r?\n/, "<br />\n")
|
663
713
|
end
|
664
714
|
|
665
715
|
# Reformat a date using Ruby's core Time#strftime( string ) -> string
|
@@ -694,11 +744,12 @@ module Liquid
|
|
694
744
|
#
|
695
745
|
# See also: http://www.ruby-doc.org/core/Time.html#method-i-strftime
|
696
746
|
def date(input, format)
|
697
|
-
|
747
|
+
str_format = Utils.to_s(format)
|
748
|
+
return input if str_format.empty?
|
698
749
|
|
699
750
|
return input unless (date = Utils.to_date(input))
|
700
751
|
|
701
|
-
date.strftime(
|
752
|
+
date.strftime(str_format)
|
702
753
|
end
|
703
754
|
|
704
755
|
# @liquid_public_docs
|
@@ -899,7 +950,7 @@ module Liquid
|
|
899
950
|
if property.nil?
|
900
951
|
item
|
901
952
|
elsif item.respond_to?(:[])
|
902
|
-
item
|
953
|
+
fetch_property(item, property)
|
903
954
|
else
|
904
955
|
0
|
905
956
|
end
|
@@ -918,6 +969,50 @@ module Liquid
|
|
918
969
|
|
919
970
|
attr_reader :context
|
920
971
|
|
972
|
+
def filter_array(input, property, target_value, &block)
|
973
|
+
ary = InputIterator.new(input, context)
|
974
|
+
|
975
|
+
return [] if ary.empty?
|
976
|
+
|
977
|
+
block.call(ary) do |item|
|
978
|
+
if target_value.nil?
|
979
|
+
fetch_property(item, property)
|
980
|
+
else
|
981
|
+
fetch_property(item, property) == target_value
|
982
|
+
end
|
983
|
+
rescue TypeError
|
984
|
+
raise_property_error(property)
|
985
|
+
rescue NoMethodError
|
986
|
+
return nil unless item.respond_to?(:[])
|
987
|
+
raise
|
988
|
+
end
|
989
|
+
end
|
990
|
+
|
991
|
+
def fetch_property(drop, property_or_keys)
|
992
|
+
##
|
993
|
+
# This keeps backward compatibility by supporting properties containing
|
994
|
+
# dots. This is valid in Liquid syntax and used in some runtimes, such as
|
995
|
+
# Shopify with metafields.
|
996
|
+
#
|
997
|
+
# Using this approach, properties like 'price.value' can be accessed in
|
998
|
+
# both of the following examples:
|
999
|
+
#
|
1000
|
+
# ```
|
1001
|
+
# [
|
1002
|
+
# { 'name' => 'Item 1', 'price.price' => 40000 },
|
1003
|
+
# { 'name' => 'Item 2', 'price' => { 'value' => 39900 } }
|
1004
|
+
# ]
|
1005
|
+
# ```
|
1006
|
+
value = drop[property_or_keys]
|
1007
|
+
|
1008
|
+
return value if !value.nil? || !property_or_keys.is_a?(String)
|
1009
|
+
|
1010
|
+
keys = property_or_keys.split('.')
|
1011
|
+
keys.reduce(drop) do |drop, key|
|
1012
|
+
drop.respond_to?(:[]) ? drop[key] : drop
|
1013
|
+
end
|
1014
|
+
end
|
1015
|
+
|
921
1016
|
def raise_property_error(property)
|
922
1017
|
raise Liquid::ArgumentError, "cannot select the property '#{property}'"
|
923
1018
|
end
|
@@ -968,7 +1063,18 @@ module Liquid
|
|
968
1063
|
end
|
969
1064
|
|
970
1065
|
def join(glue)
|
971
|
-
|
1066
|
+
first = true
|
1067
|
+
output = +""
|
1068
|
+
each do |item|
|
1069
|
+
if first
|
1070
|
+
first = false
|
1071
|
+
else
|
1072
|
+
output << glue
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
output << Liquid::Utils.to_s(item)
|
1076
|
+
end
|
1077
|
+
output
|
972
1078
|
end
|
973
1079
|
|
974
1080
|
def concat(args)
|
data/lib/liquid/utils.rb
CHANGED
@@ -89,5 +89,101 @@ module Liquid
|
|
89
89
|
# Otherwise return the object itself
|
90
90
|
obj
|
91
91
|
end
|
92
|
+
|
93
|
+
def self.to_s(obj, seen = {})
|
94
|
+
case obj
|
95
|
+
when Hash
|
96
|
+
# If the custom hash implementation overrides `#to_s`, use their
|
97
|
+
# custom implementation. Otherwise we use Liquid's default
|
98
|
+
# implementation.
|
99
|
+
if obj.class.instance_method(:to_s) == HASH_TO_S_METHOD
|
100
|
+
hash_inspect(obj, seen)
|
101
|
+
else
|
102
|
+
obj.to_s
|
103
|
+
end
|
104
|
+
when Array
|
105
|
+
array_inspect(obj, seen)
|
106
|
+
else
|
107
|
+
obj.to_s
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.inspect(obj, seen = {})
|
112
|
+
case obj
|
113
|
+
when Hash
|
114
|
+
# If the custom hash implementation overrides `#inspect`, use their
|
115
|
+
# custom implementation. Otherwise we use Liquid's default
|
116
|
+
# implementation.
|
117
|
+
if obj.class.instance_method(:inspect) == HASH_INSPECT_METHOD
|
118
|
+
hash_inspect(obj, seen)
|
119
|
+
else
|
120
|
+
obj.inspect
|
121
|
+
end
|
122
|
+
when Array
|
123
|
+
array_inspect(obj, seen)
|
124
|
+
else
|
125
|
+
obj.inspect
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.array_inspect(arr, seen = {})
|
130
|
+
if seen[arr.object_id]
|
131
|
+
return "[...]"
|
132
|
+
end
|
133
|
+
|
134
|
+
seen[arr.object_id] = true
|
135
|
+
str = +"["
|
136
|
+
cursor = 0
|
137
|
+
len = arr.length
|
138
|
+
|
139
|
+
while cursor < len
|
140
|
+
if cursor > 0
|
141
|
+
str << ", "
|
142
|
+
end
|
143
|
+
|
144
|
+
item_str = inspect(arr[cursor], seen)
|
145
|
+
str << item_str
|
146
|
+
cursor += 1
|
147
|
+
end
|
148
|
+
|
149
|
+
str << "]"
|
150
|
+
str
|
151
|
+
ensure
|
152
|
+
seen.delete(arr.object_id)
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.hash_inspect(hash, seen = {})
|
156
|
+
if seen[hash.object_id]
|
157
|
+
return "{...}"
|
158
|
+
end
|
159
|
+
seen[hash.object_id] = true
|
160
|
+
|
161
|
+
str = +"{"
|
162
|
+
first = true
|
163
|
+
hash.each do |key, value|
|
164
|
+
if first
|
165
|
+
first = false
|
166
|
+
else
|
167
|
+
str << ", "
|
168
|
+
end
|
169
|
+
|
170
|
+
key_str = inspect(key, seen)
|
171
|
+
str << key_str
|
172
|
+
str << "=>"
|
173
|
+
|
174
|
+
value_str = inspect(value, seen)
|
175
|
+
str << value_str
|
176
|
+
end
|
177
|
+
str << "}"
|
178
|
+
str
|
179
|
+
ensure
|
180
|
+
seen.delete(hash.object_id)
|
181
|
+
end
|
182
|
+
|
183
|
+
HASH_TO_S_METHOD = Hash.instance_method(:to_s)
|
184
|
+
private_constant :HASH_TO_S_METHOD
|
185
|
+
|
186
|
+
HASH_INSPECT_METHOD = Hash.instance_method(:inspect)
|
187
|
+
private_constant :HASH_INSPECT_METHOD
|
92
188
|
end
|
93
189
|
end
|
data/lib/liquid/variable.rb
CHANGED
data/lib/liquid/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: liquid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Lütke
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-01-
|
10
|
+
date: 2025-01-17 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: strscan
|