liquid 4.0.0 → 5.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|