liquid 4.0.0 → 5.0.1
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 +5 -5
- data/History.md +101 -2
- data/README.md +8 -0
- data/lib/liquid.rb +18 -5
- data/lib/liquid/block.rb +47 -20
- data/lib/liquid/block_body.rb +192 -76
- data/lib/liquid/condition.rb +69 -29
- data/lib/liquid/context.rb +110 -53
- data/lib/liquid/document.rb +47 -9
- data/lib/liquid/drop.rb +4 -2
- data/lib/liquid/errors.rb +20 -18
- data/lib/liquid/expression.rb +30 -31
- data/lib/liquid/extensions.rb +8 -0
- data/lib/liquid/file_system.rb +6 -4
- data/lib/liquid/forloop_drop.rb +11 -4
- data/lib/liquid/i18n.rb +5 -3
- data/lib/liquid/interrupts.rb +3 -1
- data/lib/liquid/lexer.rb +35 -26
- data/lib/liquid/locales/en.yml +4 -2
- data/lib/liquid/parse_context.rb +21 -4
- data/lib/liquid/parse_tree_visitor.rb +42 -0
- data/lib/liquid/parser.rb +30 -18
- data/lib/liquid/parser_switching.rb +17 -3
- data/lib/liquid/partial_cache.rb +24 -0
- data/lib/liquid/profiler.rb +67 -86
- data/lib/liquid/profiler/hooks.rb +26 -14
- data/lib/liquid/range_lookup.rb +5 -3
- data/lib/liquid/register.rb +6 -0
- data/lib/liquid/resource_limits.rb +47 -8
- data/lib/liquid/standardfilters.rb +170 -63
- data/lib/liquid/static_registers.rb +44 -0
- data/lib/liquid/strainer_factory.rb +36 -0
- data/lib/liquid/strainer_template.rb +53 -0
- data/lib/liquid/tablerowloop_drop.rb +6 -4
- data/lib/liquid/tag.rb +28 -6
- data/lib/liquid/tag/disableable.rb +22 -0
- data/lib/liquid/tag/disabler.rb +21 -0
- data/lib/liquid/tags/assign.rb +32 -10
- data/lib/liquid/tags/break.rb +8 -3
- data/lib/liquid/tags/capture.rb +11 -8
- data/lib/liquid/tags/case.rb +41 -27
- data/lib/liquid/tags/comment.rb +5 -3
- data/lib/liquid/tags/continue.rb +8 -3
- data/lib/liquid/tags/cycle.rb +35 -16
- data/lib/liquid/tags/decrement.rb +6 -3
- data/lib/liquid/tags/echo.rb +34 -0
- data/lib/liquid/tags/for.rb +79 -47
- data/lib/liquid/tags/if.rb +53 -30
- data/lib/liquid/tags/ifchanged.rb +11 -10
- data/lib/liquid/tags/include.rb +42 -44
- data/lib/liquid/tags/increment.rb +7 -3
- data/lib/liquid/tags/raw.rb +14 -11
- data/lib/liquid/tags/render.rb +84 -0
- data/lib/liquid/tags/table_row.rb +32 -20
- data/lib/liquid/tags/unless.rb +15 -15
- data/lib/liquid/template.rb +53 -72
- data/lib/liquid/template_factory.rb +9 -0
- data/lib/liquid/tokenizer.rb +17 -9
- data/lib/liquid/usage.rb +8 -0
- data/lib/liquid/utils.rb +6 -4
- data/lib/liquid/variable.rb +55 -38
- data/lib/liquid/variable_lookup.rb +14 -6
- data/lib/liquid/version.rb +3 -1
- data/test/integration/assign_test.rb +74 -5
- data/test/integration/blank_test.rb +11 -8
- data/test/integration/block_test.rb +58 -0
- data/test/integration/capture_test.rb +18 -10
- data/test/integration/context_test.rb +609 -5
- data/test/integration/document_test.rb +4 -2
- data/test/integration/drop_test.rb +67 -83
- data/test/integration/error_handling_test.rb +73 -61
- data/test/integration/expression_test.rb +46 -0
- data/test/integration/filter_test.rb +53 -42
- data/test/integration/hash_ordering_test.rb +5 -3
- data/test/integration/output_test.rb +26 -24
- data/test/integration/parsing_quirks_test.rb +24 -8
- data/test/integration/{render_profiling_test.rb → profiler_test.rb} +84 -25
- data/test/integration/security_test.rb +41 -18
- data/test/integration/standard_filter_test.rb +513 -210
- data/test/integration/tag/disableable_test.rb +59 -0
- data/test/integration/tag_test.rb +45 -0
- data/test/integration/tags/break_tag_test.rb +4 -2
- data/test/integration/tags/continue_tag_test.rb +4 -2
- data/test/integration/tags/echo_test.rb +13 -0
- data/test/integration/tags/for_tag_test.rb +109 -53
- data/test/integration/tags/if_else_tag_test.rb +5 -3
- data/test/integration/tags/include_tag_test.rb +83 -52
- data/test/integration/tags/increment_tag_test.rb +4 -2
- data/test/integration/tags/liquid_tag_test.rb +116 -0
- data/test/integration/tags/raw_tag_test.rb +14 -11
- data/test/integration/tags/render_tag_test.rb +213 -0
- data/test/integration/tags/standard_tag_test.rb +38 -31
- data/test/integration/tags/statements_test.rb +23 -21
- data/test/integration/tags/table_row_test.rb +2 -0
- data/test/integration/tags/unless_else_tag_test.rb +4 -2
- data/test/integration/template_test.rb +123 -120
- data/test/integration/trim_mode_test.rb +82 -44
- data/test/integration/variable_test.rb +46 -31
- data/test/test_helper.rb +75 -23
- data/test/unit/block_unit_test.rb +19 -24
- data/test/unit/condition_unit_test.rb +82 -72
- data/test/unit/file_system_unit_test.rb +6 -4
- data/test/unit/i18n_unit_test.rb +7 -5
- data/test/unit/lexer_unit_test.rb +12 -10
- data/test/unit/parse_tree_visitor_test.rb +254 -0
- data/test/unit/parser_unit_test.rb +37 -35
- data/test/unit/partial_cache_unit_test.rb +128 -0
- data/test/unit/regexp_unit_test.rb +17 -15
- data/test/unit/static_registers_unit_test.rb +156 -0
- data/test/unit/strainer_factory_unit_test.rb +100 -0
- data/test/unit/strainer_template_unit_test.rb +82 -0
- data/test/unit/tag_unit_test.rb +5 -3
- data/test/unit/tags/case_tag_unit_test.rb +3 -1
- data/test/unit/tags/for_tag_unit_test.rb +4 -2
- data/test/unit/tags/if_tag_unit_test.rb +3 -1
- data/test/unit/template_factory_unit_test.rb +12 -0
- data/test/unit/template_unit_test.rb +19 -10
- data/test/unit/tokenizer_unit_test.rb +26 -19
- data/test/unit/variable_unit_test.rb +51 -49
- metadata +79 -46
- data/lib/liquid/strainer.rb +0 -66
- data/test/unit/context_unit_test.rb +0 -483
- data/test/unit/strainer_unit_test.rb +0 -148
@@ -1,16 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cgi'
|
2
4
|
require 'bigdecimal'
|
3
5
|
|
4
6
|
module Liquid
|
5
7
|
module StandardFilters
|
6
8
|
HTML_ESCAPE = {
|
7
|
-
'&'
|
8
|
-
'>'
|
9
|
-
'<'
|
10
|
-
'"'
|
11
|
-
"'"
|
12
|
-
}
|
9
|
+
'&' => '&',
|
10
|
+
'>' => '>',
|
11
|
+
'<' => '<',
|
12
|
+
'"' => '"',
|
13
|
+
"'" => ''',
|
14
|
+
}.freeze
|
13
15
|
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
|
16
|
+
STRIP_HTML_BLOCKS = Regexp.union(
|
17
|
+
%r{<script.*?</script>}m,
|
18
|
+
/<!--.*?-->/m,
|
19
|
+
%r{<style.*?</style>}m
|
20
|
+
)
|
21
|
+
STRIP_HTML_TAGS = /<.*?>/m
|
14
22
|
|
15
23
|
# Return the size of an array or of an string
|
16
24
|
def size(input)
|
@@ -33,7 +41,7 @@ module Liquid
|
|
33
41
|
end
|
34
42
|
|
35
43
|
def escape(input)
|
36
|
-
CGI.escapeHTML(input)
|
44
|
+
CGI.escapeHTML(input.to_s) unless input.nil?
|
37
45
|
end
|
38
46
|
alias_method :h, :escape
|
39
47
|
|
@@ -42,11 +50,16 @@ module Liquid
|
|
42
50
|
end
|
43
51
|
|
44
52
|
def url_encode(input)
|
45
|
-
CGI.escape(input) unless input.nil?
|
53
|
+
CGI.escape(input.to_s) unless input.nil?
|
46
54
|
end
|
47
55
|
|
48
56
|
def url_decode(input)
|
49
|
-
|
57
|
+
return if input.nil?
|
58
|
+
|
59
|
+
result = CGI.unescape(input.to_s)
|
60
|
+
raise Liquid::ArgumentError, "invalid byte sequence in #{result.encoding}" unless result.valid_encoding?
|
61
|
+
|
62
|
+
result
|
50
63
|
end
|
51
64
|
|
52
65
|
def slice(input, offset, length = nil)
|
@@ -61,23 +74,30 @@ module Liquid
|
|
61
74
|
end
|
62
75
|
|
63
76
|
# Truncate a string down to x characters
|
64
|
-
def truncate(input, length = 50, truncate_string = "..."
|
77
|
+
def truncate(input, length = 50, truncate_string = "...")
|
65
78
|
return if input.nil?
|
66
79
|
input_str = input.to_s
|
67
|
-
length
|
80
|
+
length = Utils.to_integer(length)
|
81
|
+
|
68
82
|
truncate_string_str = truncate_string.to_s
|
83
|
+
|
69
84
|
l = length - truncate_string_str.length
|
70
85
|
l = 0 if l < 0
|
71
|
-
|
86
|
+
|
87
|
+
input_str.length > length ? input_str[0...l].concat(truncate_string_str) : input_str
|
72
88
|
end
|
73
89
|
|
74
|
-
def truncatewords(input, words = 15, truncate_string = "..."
|
90
|
+
def truncatewords(input, words = 15, truncate_string = "...")
|
75
91
|
return if input.nil?
|
76
|
-
|
92
|
+
input = input.to_s
|
77
93
|
words = Utils.to_integer(words)
|
78
|
-
|
79
|
-
|
80
|
-
wordlist
|
94
|
+
words = 1 if words <= 0
|
95
|
+
|
96
|
+
wordlist = input.split(" ", words + 1)
|
97
|
+
return input if wordlist.length <= words
|
98
|
+
|
99
|
+
wordlist.pop
|
100
|
+
wordlist.join(" ").concat(truncate_string.to_s)
|
81
101
|
end
|
82
102
|
|
83
103
|
# Split input string into an array of substrings separated by given pattern.
|
@@ -102,37 +122,38 @@ module Liquid
|
|
102
122
|
end
|
103
123
|
|
104
124
|
def strip_html(input)
|
105
|
-
empty
|
106
|
-
input.to_s.gsub(
|
125
|
+
empty = ''
|
126
|
+
result = input.to_s.gsub(STRIP_HTML_BLOCKS, empty)
|
127
|
+
result.gsub!(STRIP_HTML_TAGS, empty)
|
128
|
+
result
|
107
129
|
end
|
108
130
|
|
109
131
|
# Remove all newlines from the string
|
110
132
|
def strip_newlines(input)
|
111
|
-
input.to_s.gsub(/\r?\n/, ''
|
133
|
+
input.to_s.gsub(/\r?\n/, '')
|
112
134
|
end
|
113
135
|
|
114
136
|
# Join elements of the array with certain character between them
|
115
|
-
def join(input, glue = ' '
|
116
|
-
InputIterator.new(input).join(glue)
|
137
|
+
def join(input, glue = ' ')
|
138
|
+
InputIterator.new(input, context).join(glue)
|
117
139
|
end
|
118
140
|
|
119
141
|
# Sort elements of the array
|
120
142
|
# provide optional property with which to sort an array of hashes or drops
|
121
143
|
def sort(input, property = nil)
|
122
|
-
ary = InputIterator.new(input)
|
144
|
+
ary = InputIterator.new(input, context)
|
145
|
+
|
146
|
+
return [] if ary.empty?
|
147
|
+
|
123
148
|
if property.nil?
|
124
|
-
ary.sort
|
125
|
-
elsif ary.empty? # The next two cases assume a non-empty array.
|
126
|
-
[]
|
127
|
-
elsif ary.first.respond_to?(:[]) && !ary.first[property].nil?
|
128
149
|
ary.sort do |a, b|
|
129
|
-
a
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
150
|
+
nil_safe_compare(a, b)
|
151
|
+
end
|
152
|
+
elsif ary.all? { |el| el.respond_to?(:[]) }
|
153
|
+
begin
|
154
|
+
ary.sort { |a, b| nil_safe_compare(a[property], b[property]) }
|
155
|
+
rescue TypeError
|
156
|
+
raise_property_error(property)
|
136
157
|
end
|
137
158
|
end
|
138
159
|
end
|
@@ -140,83 +161,121 @@ module Liquid
|
|
140
161
|
# Sort elements of an array ignoring case if strings
|
141
162
|
# provide optional property with which to sort an array of hashes or drops
|
142
163
|
def sort_natural(input, property = nil)
|
143
|
-
ary = InputIterator.new(input)
|
164
|
+
ary = InputIterator.new(input, context)
|
165
|
+
|
166
|
+
return [] if ary.empty?
|
144
167
|
|
145
168
|
if property.nil?
|
146
|
-
ary.sort
|
147
|
-
|
169
|
+
ary.sort do |a, b|
|
170
|
+
nil_safe_casecmp(a, b)
|
171
|
+
end
|
172
|
+
elsif ary.all? { |el| el.respond_to?(:[]) }
|
173
|
+
begin
|
174
|
+
ary.sort { |a, b| nil_safe_casecmp(a[property], b[property]) }
|
175
|
+
rescue TypeError
|
176
|
+
raise_property_error(property)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Filter the elements of an array to those with a certain property value.
|
182
|
+
# By default the target is any truthy value.
|
183
|
+
def where(input, property, target_value = nil)
|
184
|
+
ary = InputIterator.new(input, context)
|
185
|
+
|
186
|
+
if ary.empty?
|
148
187
|
[]
|
149
|
-
elsif ary.first.respond_to?(:[]) &&
|
150
|
-
|
188
|
+
elsif ary.first.respond_to?(:[]) && target_value.nil?
|
189
|
+
begin
|
190
|
+
ary.select { |item| item[property] }
|
191
|
+
rescue TypeError
|
192
|
+
raise_property_error(property)
|
193
|
+
end
|
194
|
+
elsif ary.first.respond_to?(:[])
|
195
|
+
begin
|
196
|
+
ary.select { |item| item[property] == target_value }
|
197
|
+
rescue TypeError
|
198
|
+
raise_property_error(property)
|
199
|
+
end
|
151
200
|
end
|
152
201
|
end
|
153
202
|
|
154
203
|
# Remove duplicate elements from an array
|
155
204
|
# provide optional property with which to determine uniqueness
|
156
205
|
def uniq(input, property = nil)
|
157
|
-
ary = InputIterator.new(input)
|
206
|
+
ary = InputIterator.new(input, context)
|
158
207
|
|
159
208
|
if property.nil?
|
160
209
|
ary.uniq
|
161
210
|
elsif ary.empty? # The next two cases assume a non-empty array.
|
162
211
|
[]
|
163
212
|
elsif ary.first.respond_to?(:[])
|
164
|
-
|
213
|
+
begin
|
214
|
+
ary.uniq { |a| a[property] }
|
215
|
+
rescue TypeError
|
216
|
+
raise_property_error(property)
|
217
|
+
end
|
165
218
|
end
|
166
219
|
end
|
167
220
|
|
168
221
|
# Reverse the elements of an array
|
169
222
|
def reverse(input)
|
170
|
-
ary = InputIterator.new(input)
|
223
|
+
ary = InputIterator.new(input, context)
|
171
224
|
ary.reverse
|
172
225
|
end
|
173
226
|
|
174
227
|
# map/collect on a given property
|
175
228
|
def map(input, property)
|
176
|
-
InputIterator.new(input).map do |e|
|
229
|
+
InputIterator.new(input, context).map do |e|
|
177
230
|
e = e.call if e.is_a?(Proc)
|
178
231
|
|
179
|
-
if property == "to_liquid"
|
232
|
+
if property == "to_liquid"
|
180
233
|
e
|
181
234
|
elsif e.respond_to?(:[])
|
182
235
|
r = e[property]
|
183
236
|
r.is_a?(Proc) ? r.call : r
|
184
237
|
end
|
185
238
|
end
|
239
|
+
rescue TypeError
|
240
|
+
raise_property_error(property)
|
186
241
|
end
|
187
242
|
|
188
243
|
# Remove nils within an array
|
189
244
|
# provide optional property with which to check for nil
|
190
245
|
def compact(input, property = nil)
|
191
|
-
ary = InputIterator.new(input)
|
246
|
+
ary = InputIterator.new(input, context)
|
192
247
|
|
193
248
|
if property.nil?
|
194
249
|
ary.compact
|
195
250
|
elsif ary.empty? # The next two cases assume a non-empty array.
|
196
251
|
[]
|
197
252
|
elsif ary.first.respond_to?(:[])
|
198
|
-
|
253
|
+
begin
|
254
|
+
ary.reject { |a| a[property].nil? }
|
255
|
+
rescue TypeError
|
256
|
+
raise_property_error(property)
|
257
|
+
end
|
199
258
|
end
|
200
259
|
end
|
201
260
|
|
202
261
|
# Replace occurrences of a string with another
|
203
|
-
def replace(input, string, replacement = ''
|
262
|
+
def replace(input, string, replacement = '')
|
204
263
|
input.to_s.gsub(string.to_s, replacement.to_s)
|
205
264
|
end
|
206
265
|
|
207
266
|
# Replace the first occurrences of a string with another
|
208
|
-
def replace_first(input, string, replacement = ''
|
267
|
+
def replace_first(input, string, replacement = '')
|
209
268
|
input.to_s.sub(string.to_s, replacement.to_s)
|
210
269
|
end
|
211
270
|
|
212
271
|
# remove a substring
|
213
272
|
def remove(input, string)
|
214
|
-
input.to_s.gsub(string.to_s, ''
|
273
|
+
input.to_s.gsub(string.to_s, '')
|
215
274
|
end
|
216
275
|
|
217
276
|
# remove the first occurrences of a substring
|
218
277
|
def remove_first(input, string)
|
219
|
-
input.to_s.sub(string.to_s, ''
|
278
|
+
input.to_s.sub(string.to_s, '')
|
220
279
|
end
|
221
280
|
|
222
281
|
# add one string to another
|
@@ -226,9 +285,9 @@ module Liquid
|
|
226
285
|
|
227
286
|
def concat(input, array)
|
228
287
|
unless array.respond_to?(:to_ary)
|
229
|
-
raise ArgumentError
|
288
|
+
raise ArgumentError, "concat filter requires an array argument"
|
230
289
|
end
|
231
|
-
InputIterator.new(input).concat(array)
|
290
|
+
InputIterator.new(input, context).concat(array)
|
232
291
|
end
|
233
292
|
|
234
293
|
# prepend a string to another
|
@@ -238,7 +297,7 @@ module Liquid
|
|
238
297
|
|
239
298
|
# Add <br /> tags in front of all newlines in input string
|
240
299
|
def newline_to_br(input)
|
241
|
-
input.to_s.gsub(/\n/, "<br />\n"
|
300
|
+
input.to_s.gsub(/\r?\n/, "<br />\n")
|
242
301
|
end
|
243
302
|
|
244
303
|
# Reformat a date using Ruby's core Time#strftime( string ) -> string
|
@@ -275,7 +334,7 @@ module Liquid
|
|
275
334
|
def date(input, format)
|
276
335
|
return input if format.to_s.empty?
|
277
336
|
|
278
|
-
return input unless date = Utils.to_date(input)
|
337
|
+
return input unless (date = Utils.to_date(input))
|
279
338
|
|
280
339
|
date.strftime(format.to_s)
|
281
340
|
end
|
@@ -353,26 +412,73 @@ module Liquid
|
|
353
412
|
raise Liquid::FloatDomainError, e.message
|
354
413
|
end
|
355
414
|
|
356
|
-
def
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
415
|
+
def at_least(input, n)
|
416
|
+
min_value = Utils.to_number(n)
|
417
|
+
|
418
|
+
result = Utils.to_number(input)
|
419
|
+
result = min_value if min_value > result
|
420
|
+
result.is_a?(BigDecimal) ? result.to_f : result
|
421
|
+
end
|
422
|
+
|
423
|
+
def at_most(input, n)
|
424
|
+
max_value = Utils.to_number(n)
|
425
|
+
|
426
|
+
result = Utils.to_number(input)
|
427
|
+
result = max_value if max_value < result
|
428
|
+
result.is_a?(BigDecimal) ? result.to_f : result
|
429
|
+
end
|
430
|
+
|
431
|
+
# Set a default value when the input is nil, false or empty
|
432
|
+
#
|
433
|
+
# Example:
|
434
|
+
# {{ product.title | default: "No Title" }}
|
435
|
+
#
|
436
|
+
# Use `allow_false` when an input should only be tested against nil or empty and not false.
|
437
|
+
#
|
438
|
+
# Example:
|
439
|
+
# {{ product.title | default: "No Title", allow_false: true }}
|
440
|
+
#
|
441
|
+
def default(input, default_value = '', options = {})
|
442
|
+
options = {} unless options.is_a?(Hash)
|
443
|
+
false_check = options['allow_false'] ? input.nil? : !input
|
444
|
+
false_check || (input.respond_to?(:empty?) && input.empty?) ? default_value : input
|
362
445
|
end
|
363
446
|
|
364
447
|
private
|
365
448
|
|
449
|
+
attr_reader :context
|
450
|
+
|
451
|
+
def raise_property_error(property)
|
452
|
+
raise Liquid::ArgumentError, "cannot select the property '#{property}'"
|
453
|
+
end
|
454
|
+
|
366
455
|
def apply_operation(input, operand, operation)
|
367
456
|
result = Utils.to_number(input).send(operation, Utils.to_number(operand))
|
368
457
|
result.is_a?(BigDecimal) ? result.to_f : result
|
369
458
|
end
|
370
459
|
|
460
|
+
def nil_safe_compare(a, b)
|
461
|
+
if !a.nil? && !b.nil?
|
462
|
+
a <=> b
|
463
|
+
else
|
464
|
+
a.nil? ? 1 : -1
|
465
|
+
end
|
466
|
+
end
|
467
|
+
|
468
|
+
def nil_safe_casecmp(a, b)
|
469
|
+
if !a.nil? && !b.nil?
|
470
|
+
a.to_s.casecmp(b.to_s)
|
471
|
+
else
|
472
|
+
a.nil? ? 1 : -1
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
371
476
|
class InputIterator
|
372
477
|
include Enumerable
|
373
478
|
|
374
|
-
def initialize(input)
|
375
|
-
@
|
479
|
+
def initialize(input, context)
|
480
|
+
@context = context
|
481
|
+
@input = if input.is_a?(Array)
|
376
482
|
input.flatten
|
377
483
|
elsif input.is_a?(Hash)
|
378
484
|
[input]
|
@@ -384,7 +490,7 @@ module Liquid
|
|
384
490
|
end
|
385
491
|
|
386
492
|
def join(glue)
|
387
|
-
to_a.join(glue)
|
493
|
+
to_a.join(glue.to_s)
|
388
494
|
end
|
389
495
|
|
390
496
|
def concat(args)
|
@@ -410,6 +516,7 @@ module Liquid
|
|
410
516
|
|
411
517
|
def each
|
412
518
|
@input.each do |e|
|
519
|
+
e.context = @context if e.respond_to?(:context=)
|
413
520
|
yield(e.respond_to?(:to_liquid) ? e.to_liquid : e)
|
414
521
|
end
|
415
522
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Liquid
|
4
|
+
class StaticRegisters
|
5
|
+
attr_reader :static
|
6
|
+
|
7
|
+
def initialize(registers = {})
|
8
|
+
@static = registers.is_a?(StaticRegisters) ? registers.static : registers
|
9
|
+
@registers = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def []=(key, value)
|
13
|
+
@registers[key] = value
|
14
|
+
end
|
15
|
+
|
16
|
+
def [](key)
|
17
|
+
if @registers.key?(key)
|
18
|
+
@registers[key]
|
19
|
+
else
|
20
|
+
@static[key]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete(key)
|
25
|
+
@registers.delete(key)
|
26
|
+
end
|
27
|
+
|
28
|
+
UNDEFINED = Object.new
|
29
|
+
|
30
|
+
def fetch(key, default = UNDEFINED, &block)
|
31
|
+
if @registers.key?(key)
|
32
|
+
@registers.fetch(key)
|
33
|
+
elsif default != UNDEFINED
|
34
|
+
@static.fetch(key, default, &block)
|
35
|
+
else
|
36
|
+
@static.fetch(key, &block)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def key?(key)
|
41
|
+
@registers.key?(key) || @static.key?(key)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|