liquid 3.0.6 → 5.4.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 +5 -5
- data/History.md +243 -58
- data/README.md +43 -4
- data/lib/liquid/block.rb +57 -123
- data/lib/liquid/block_body.rb +217 -85
- data/lib/liquid/condition.rb +92 -45
- data/lib/liquid/context.rb +154 -89
- data/lib/liquid/document.rb +57 -9
- data/lib/liquid/drop.rb +20 -17
- data/lib/liquid/errors.rb +27 -29
- data/lib/liquid/expression.rb +32 -20
- data/lib/liquid/extensions.rb +21 -7
- data/lib/liquid/file_system.rb +17 -15
- data/lib/liquid/forloop_drop.rb +92 -0
- data/lib/liquid/i18n.rb +10 -8
- data/lib/liquid/interrupts.rb +4 -3
- data/lib/liquid/lexer.rb +37 -26
- data/lib/liquid/locales/en.yml +13 -6
- data/lib/liquid/parse_context.rb +54 -0
- data/lib/liquid/parse_tree_visitor.rb +42 -0
- data/lib/liquid/parser.rb +30 -18
- data/lib/liquid/parser_switching.rb +20 -6
- data/lib/liquid/partial_cache.rb +24 -0
- data/lib/liquid/profiler/hooks.rb +26 -14
- data/lib/liquid/profiler.rb +72 -92
- data/lib/liquid/range_lookup.rb +28 -3
- data/lib/liquid/registers.rb +51 -0
- data/lib/liquid/resource_limits.rb +62 -0
- data/lib/liquid/standardfilters.rb +715 -132
- data/lib/liquid/strainer_factory.rb +41 -0
- data/lib/liquid/strainer_template.rb +62 -0
- data/lib/liquid/tablerowloop_drop.rb +121 -0
- data/lib/liquid/tag/disableable.rb +22 -0
- data/lib/liquid/tag/disabler.rb +21 -0
- data/lib/liquid/tag.rb +35 -12
- data/lib/liquid/tags/assign.rb +57 -18
- data/lib/liquid/tags/break.rb +15 -5
- data/lib/liquid/tags/capture.rb +24 -18
- data/lib/liquid/tags/case.rb +79 -30
- data/lib/liquid/tags/comment.rb +19 -4
- data/lib/liquid/tags/continue.rb +16 -12
- data/lib/liquid/tags/cycle.rb +47 -27
- data/lib/liquid/tags/decrement.rb +23 -24
- data/lib/liquid/tags/echo.rb +41 -0
- data/lib/liquid/tags/for.rb +155 -124
- data/lib/liquid/tags/if.rb +97 -63
- data/lib/liquid/tags/ifchanged.rb +11 -12
- data/lib/liquid/tags/include.rb +82 -73
- data/lib/liquid/tags/increment.rb +23 -17
- data/lib/liquid/tags/inline_comment.rb +43 -0
- data/lib/liquid/tags/raw.rb +50 -8
- data/lib/liquid/tags/render.rb +109 -0
- data/lib/liquid/tags/table_row.rb +57 -41
- data/lib/liquid/tags/unless.rb +38 -20
- data/lib/liquid/template.rb +71 -103
- data/lib/liquid/template_factory.rb +9 -0
- data/lib/liquid/tokenizer.rb +39 -0
- data/lib/liquid/usage.rb +8 -0
- data/lib/liquid/utils.rb +63 -9
- data/lib/liquid/variable.rb +74 -56
- data/lib/liquid/variable_lookup.rb +31 -15
- data/lib/liquid/version.rb +3 -1
- data/lib/liquid.rb +27 -12
- metadata +30 -106
- data/lib/liquid/module_ex.rb +0 -62
- data/lib/liquid/strainer.rb +0 -59
- data/lib/liquid/token.rb +0 -18
- data/test/fixtures/en_locale.yml +0 -9
- data/test/integration/assign_test.rb +0 -48
- data/test/integration/blank_test.rb +0 -106
- data/test/integration/capture_test.rb +0 -50
- data/test/integration/context_test.rb +0 -32
- data/test/integration/drop_test.rb +0 -271
- data/test/integration/error_handling_test.rb +0 -207
- data/test/integration/filter_test.rb +0 -138
- data/test/integration/hash_ordering_test.rb +0 -23
- data/test/integration/output_test.rb +0 -124
- data/test/integration/parsing_quirks_test.rb +0 -116
- data/test/integration/render_profiling_test.rb +0 -154
- data/test/integration/security_test.rb +0 -64
- data/test/integration/standard_filter_test.rb +0 -396
- data/test/integration/tags/break_tag_test.rb +0 -16
- data/test/integration/tags/continue_tag_test.rb +0 -16
- data/test/integration/tags/for_tag_test.rb +0 -375
- data/test/integration/tags/if_else_tag_test.rb +0 -190
- data/test/integration/tags/include_tag_test.rb +0 -234
- data/test/integration/tags/increment_tag_test.rb +0 -24
- data/test/integration/tags/raw_tag_test.rb +0 -25
- data/test/integration/tags/standard_tag_test.rb +0 -297
- data/test/integration/tags/statements_test.rb +0 -113
- data/test/integration/tags/table_row_test.rb +0 -63
- data/test/integration/tags/unless_else_tag_test.rb +0 -26
- data/test/integration/template_test.rb +0 -182
- data/test/integration/variable_test.rb +0 -82
- data/test/test_helper.rb +0 -89
- data/test/unit/block_unit_test.rb +0 -55
- data/test/unit/condition_unit_test.rb +0 -149
- data/test/unit/context_unit_test.rb +0 -492
- data/test/unit/file_system_unit_test.rb +0 -35
- data/test/unit/i18n_unit_test.rb +0 -37
- data/test/unit/lexer_unit_test.rb +0 -48
- data/test/unit/module_ex_unit_test.rb +0 -87
- data/test/unit/parser_unit_test.rb +0 -82
- data/test/unit/regexp_unit_test.rb +0 -44
- data/test/unit/strainer_unit_test.rb +0 -69
- data/test/unit/tag_unit_test.rb +0 -16
- data/test/unit/tags/case_tag_unit_test.rb +0 -10
- data/test/unit/tags/for_tag_unit_test.rb +0 -13
- data/test/unit/tags/if_tag_unit_test.rb +0 -8
- data/test/unit/template_unit_test.rb +0 -69
- data/test/unit/tokenizer_unit_test.rb +0 -38
- data/test/unit/variable_unit_test.rb +0 -145
- /data/{MIT-LICENSE → LICENSE} +0 -0
@@ -1,54 +1,190 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cgi'
|
4
|
+
require 'base64'
|
2
5
|
require 'bigdecimal'
|
3
6
|
|
4
7
|
module Liquid
|
5
|
-
|
6
8
|
module StandardFilters
|
9
|
+
MAX_INT = (1 << 31) - 1
|
7
10
|
HTML_ESCAPE = {
|
8
|
-
'&'
|
9
|
-
'>'
|
10
|
-
'<'
|
11
|
-
'"'
|
12
|
-
"'"
|
13
|
-
}
|
11
|
+
'&' => '&',
|
12
|
+
'>' => '>',
|
13
|
+
'<' => '<',
|
14
|
+
'"' => '"',
|
15
|
+
"'" => ''',
|
16
|
+
}.freeze
|
14
17
|
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
|
15
|
-
|
16
|
-
|
18
|
+
STRIP_HTML_BLOCKS = Regexp.union(
|
19
|
+
%r{<script.*?</script>}m,
|
20
|
+
/<!--.*?-->/m,
|
21
|
+
%r{<style.*?</style>}m
|
22
|
+
)
|
23
|
+
STRIP_HTML_TAGS = /<.*?>/m
|
24
|
+
|
25
|
+
# @liquid_public_docs
|
26
|
+
# @liquid_type filter
|
27
|
+
# @liquid_category array
|
28
|
+
# @liquid_summary
|
29
|
+
# Returns the size of a string or array.
|
30
|
+
# @liquid_description
|
31
|
+
# The size of a string is the number of characters that the string includes. The size of an array is the number of items
|
32
|
+
# in the array.
|
33
|
+
# @liquid_syntax variable | size
|
34
|
+
# @liquid_return [number]
|
17
35
|
def size(input)
|
18
36
|
input.respond_to?(:size) ? input.size : 0
|
19
37
|
end
|
20
38
|
|
21
|
-
#
|
39
|
+
# @liquid_public_docs
|
40
|
+
# @liquid_type filter
|
41
|
+
# @liquid_category string
|
42
|
+
# @liquid_summary
|
43
|
+
# Converts a string to all lowercase characters.
|
44
|
+
# @liquid_syntax string | downcase
|
45
|
+
# @liquid_return [string]
|
22
46
|
def downcase(input)
|
23
47
|
input.to_s.downcase
|
24
48
|
end
|
25
49
|
|
26
|
-
#
|
50
|
+
# @liquid_public_docs
|
51
|
+
# @liquid_type filter
|
52
|
+
# @liquid_category string
|
53
|
+
# @liquid_summary
|
54
|
+
# Converts a string to all uppercase characters.
|
55
|
+
# @liquid_syntax string | upcase
|
56
|
+
# @liquid_return [string]
|
27
57
|
def upcase(input)
|
28
58
|
input.to_s.upcase
|
29
59
|
end
|
30
60
|
|
31
|
-
#
|
61
|
+
# @liquid_public_docs
|
62
|
+
# @liquid_type filter
|
63
|
+
# @liquid_category string
|
64
|
+
# @liquid_summary
|
65
|
+
# Capitalizes the first word in a string.
|
66
|
+
# @liquid_syntax string | capitalize
|
67
|
+
# @liquid_return [string]
|
32
68
|
def capitalize(input)
|
33
69
|
input.to_s.capitalize
|
34
70
|
end
|
35
71
|
|
72
|
+
# @liquid_public_docs
|
73
|
+
# @liquid_type filter
|
74
|
+
# @liquid_category string
|
75
|
+
# @liquid_summary
|
76
|
+
# Escapes a string.
|
77
|
+
# @liquid_syntax string | escape
|
78
|
+
# @liquid_return [string]
|
36
79
|
def escape(input)
|
37
|
-
CGI.escapeHTML(input)
|
80
|
+
CGI.escapeHTML(input.to_s) unless input.nil?
|
38
81
|
end
|
39
82
|
alias_method :h, :escape
|
40
83
|
|
84
|
+
# @liquid_public_docs
|
85
|
+
# @liquid_type filter
|
86
|
+
# @liquid_category string
|
87
|
+
# @liquid_summary
|
88
|
+
# Escapes a string without changing characters that have already been escaped.
|
89
|
+
# @liquid_syntax string | escape_once
|
90
|
+
# @liquid_return [string]
|
41
91
|
def escape_once(input)
|
42
92
|
input.to_s.gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
|
43
93
|
end
|
44
94
|
|
95
|
+
# @liquid_public_docs
|
96
|
+
# @liquid_type filter
|
97
|
+
# @liquid_category string
|
98
|
+
# @liquid_summary
|
99
|
+
# Converts any URL-unsafe characters in a string to the
|
100
|
+
# [percent-encoded](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding) equivalent.
|
101
|
+
# @liquid_description
|
102
|
+
# > Note:
|
103
|
+
# > Spaces are converted to a `+` character, instead of a percent-encoded character.
|
104
|
+
# @liquid_syntax string | url_encode
|
105
|
+
# @liquid_return [string]
|
45
106
|
def url_encode(input)
|
46
|
-
CGI.escape(input)
|
107
|
+
CGI.escape(input.to_s) unless input.nil?
|
47
108
|
end
|
48
109
|
|
49
|
-
|
50
|
-
|
51
|
-
|
110
|
+
# @liquid_public_docs
|
111
|
+
# @liquid_type filter
|
112
|
+
# @liquid_category string
|
113
|
+
# @liquid_summary
|
114
|
+
# Decodes any [percent-encoded](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding) characters
|
115
|
+
# in a string.
|
116
|
+
# @liquid_syntax string | url_decode
|
117
|
+
# @liquid_return [string]
|
118
|
+
def url_decode(input)
|
119
|
+
return if input.nil?
|
120
|
+
|
121
|
+
result = CGI.unescape(input.to_s)
|
122
|
+
raise Liquid::ArgumentError, "invalid byte sequence in #{result.encoding}" unless result.valid_encoding?
|
123
|
+
|
124
|
+
result
|
125
|
+
end
|
126
|
+
|
127
|
+
# @liquid_public_docs
|
128
|
+
# @liquid_type filter
|
129
|
+
# @liquid_category string
|
130
|
+
# @liquid_summary
|
131
|
+
# Encodes a string to [Base64 format](https://developer.mozilla.org/en-US/docs/Glossary/Base64).
|
132
|
+
# @liquid_syntax string | base64_encode
|
133
|
+
# @liquid_return [string]
|
134
|
+
def base64_encode(input)
|
135
|
+
Base64.strict_encode64(input.to_s)
|
136
|
+
end
|
137
|
+
|
138
|
+
# @liquid_public_docs
|
139
|
+
# @liquid_type filter
|
140
|
+
# @liquid_category string
|
141
|
+
# @liquid_summary
|
142
|
+
# Decodes a string in [Base64 format](https://developer.mozilla.org/en-US/docs/Glossary/Base64).
|
143
|
+
# @liquid_syntax string | base64_decode
|
144
|
+
# @liquid_return [string]
|
145
|
+
def base64_decode(input)
|
146
|
+
Base64.strict_decode64(input.to_s)
|
147
|
+
rescue ::ArgumentError
|
148
|
+
raise Liquid::ArgumentError, "invalid base64 provided to base64_decode"
|
149
|
+
end
|
150
|
+
|
151
|
+
# @liquid_public_docs
|
152
|
+
# @liquid_type filter
|
153
|
+
# @liquid_category string
|
154
|
+
# @liquid_summary
|
155
|
+
# Encodes a string to URL-safe [Base64 format](https://developer.mozilla.org/en-US/docs/Glossary/Base64).
|
156
|
+
# @liquid_syntax string | base64_url_safe_encode
|
157
|
+
# @liquid_return [string]
|
158
|
+
def base64_url_safe_encode(input)
|
159
|
+
Base64.urlsafe_encode64(input.to_s)
|
160
|
+
end
|
161
|
+
|
162
|
+
# @liquid_public_docs
|
163
|
+
# @liquid_type filter
|
164
|
+
# @liquid_category string
|
165
|
+
# @liquid_summary
|
166
|
+
# Decodes a string in URL-safe [Base64 format](https://developer.mozilla.org/en-US/docs/Glossary/Base64).
|
167
|
+
# @liquid_syntax string | base64_url_safe_decode
|
168
|
+
# @liquid_return [string]
|
169
|
+
def base64_url_safe_decode(input)
|
170
|
+
Base64.urlsafe_decode64(input.to_s)
|
171
|
+
rescue ::ArgumentError
|
172
|
+
raise Liquid::ArgumentError, "invalid base64 provided to base64_url_safe_decode"
|
173
|
+
end
|
174
|
+
|
175
|
+
# @liquid_public_docs
|
176
|
+
# @liquid_type filter
|
177
|
+
# @liquid_category string
|
178
|
+
# @liquid_summary
|
179
|
+
# Returns a substring or series of array items, starting at a given 0-based index.
|
180
|
+
# @liquid_description
|
181
|
+
# By default, the substring has a length of one character, and the array series has one array item. However, you can
|
182
|
+
# provide a second parameter to specify the number of characters or array items.
|
183
|
+
# @liquid_syntax string | slice
|
184
|
+
# @liquid_return [string]
|
185
|
+
def slice(input, offset, length = nil)
|
186
|
+
offset = Utils.to_integer(offset)
|
187
|
+
length = length ? Utils.to_integer(length) : 1
|
52
188
|
|
53
189
|
if input.is_a?(Array)
|
54
190
|
input.slice(offset, length) || []
|
@@ -57,134 +193,442 @@ module Liquid
|
|
57
193
|
end
|
58
194
|
end
|
59
195
|
|
60
|
-
#
|
61
|
-
|
62
|
-
|
63
|
-
|
196
|
+
# @liquid_public_docs
|
197
|
+
# @liquid_type filter
|
198
|
+
# @liquid_category string
|
199
|
+
# @liquid_summary
|
200
|
+
# Truncates a string down to a given number of characters.
|
201
|
+
# @liquid_description
|
202
|
+
# If the specified number of characters is less than the length of the string, then an ellipsis (`...`) is appended to
|
203
|
+
# the truncated string. The ellipsis is included in the character count of the truncated string.
|
204
|
+
# @liquid_syntax string | truncate: number
|
205
|
+
# @liquid_return [string]
|
206
|
+
def truncate(input, length = 50, truncate_string = "...")
|
207
|
+
return if input.nil?
|
208
|
+
input_str = input.to_s
|
209
|
+
length = Utils.to_integer(length)
|
210
|
+
|
211
|
+
truncate_string_str = truncate_string.to_s
|
212
|
+
|
213
|
+
l = length - truncate_string_str.length
|
64
214
|
l = 0 if l < 0
|
65
|
-
input.length > length.to_i ? input[0...l] + truncate_string : input
|
66
|
-
end
|
67
215
|
|
68
|
-
|
69
|
-
if input.nil? then return end
|
70
|
-
wordlist = input.to_s.split
|
71
|
-
l = words.to_i - 1
|
72
|
-
l = 0 if l < 0
|
73
|
-
wordlist.length > l ? wordlist[0..l].join(" ".freeze) + truncate_string : input
|
216
|
+
input_str.length > length ? input_str[0...l].concat(truncate_string_str) : input_str
|
74
217
|
end
|
75
218
|
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
219
|
+
# @liquid_public_docs
|
220
|
+
# @liquid_type filter
|
221
|
+
# @liquid_category string
|
222
|
+
# @liquid_summary
|
223
|
+
# Truncates a string down to a given number of words.
|
224
|
+
# @liquid_description
|
225
|
+
# If the specified number of words is less than the number of words in the string, then an ellipsis (`...`) is appended to
|
226
|
+
# the truncated string.
|
80
227
|
#
|
228
|
+
# > Caution:
|
229
|
+
# > HTML tags are treated as words, so you should strip any HTML from truncated content. If you don't strip HTML, then
|
230
|
+
# > closing HTML tags can be removed, which can result in unexpected behavior.
|
231
|
+
# @liquid_syntax string | truncatewords: number
|
232
|
+
# @liquid_return [string]
|
233
|
+
def truncatewords(input, words = 15, truncate_string = "...")
|
234
|
+
return if input.nil?
|
235
|
+
input = input.to_s
|
236
|
+
words = Utils.to_integer(words)
|
237
|
+
words = 1 if words <= 0
|
238
|
+
|
239
|
+
wordlist = begin
|
240
|
+
input.split(" ", words + 1)
|
241
|
+
rescue RangeError
|
242
|
+
raise if words + 1 < MAX_INT
|
243
|
+
# e.g. integer #{words} too big to convert to `int'
|
244
|
+
raise Liquid::ArgumentError, "integer #{words} too big for truncatewords"
|
245
|
+
end
|
246
|
+
return input if wordlist.length <= words
|
247
|
+
|
248
|
+
wordlist.pop
|
249
|
+
wordlist.join(" ").concat(truncate_string.to_s)
|
250
|
+
end
|
251
|
+
|
252
|
+
# @liquid_public_docs
|
253
|
+
# @liquid_type filter
|
254
|
+
# @liquid_category string
|
255
|
+
# @liquid_summary
|
256
|
+
# Splits a string into an array of substrings based on a given separator.
|
257
|
+
# @liquid_syntax string | split: string
|
258
|
+
# @liquid_return [array[string]]
|
81
259
|
def split(input, pattern)
|
82
|
-
input.to_s.split(pattern)
|
260
|
+
input.to_s.split(pattern.to_s)
|
83
261
|
end
|
84
262
|
|
263
|
+
# @liquid_public_docs
|
264
|
+
# @liquid_type filter
|
265
|
+
# @liquid_category string
|
266
|
+
# @liquid_summary
|
267
|
+
# Strips all whitespace from the left and right of a string.
|
268
|
+
# @liquid_syntax string | strip
|
269
|
+
# @liquid_return [string]
|
85
270
|
def strip(input)
|
86
271
|
input.to_s.strip
|
87
272
|
end
|
88
273
|
|
274
|
+
# @liquid_public_docs
|
275
|
+
# @liquid_type filter
|
276
|
+
# @liquid_category string
|
277
|
+
# @liquid_summary
|
278
|
+
# Strips all whitespace from the left of a string.
|
279
|
+
# @liquid_syntax string | lstrip
|
280
|
+
# @liquid_return [string]
|
89
281
|
def lstrip(input)
|
90
282
|
input.to_s.lstrip
|
91
283
|
end
|
92
284
|
|
285
|
+
# @liquid_public_docs
|
286
|
+
# @liquid_type filter
|
287
|
+
# @liquid_category string
|
288
|
+
# @liquid_summary
|
289
|
+
# Strips all whitespace from the right of a string.
|
290
|
+
# @liquid_syntax string | rstrip
|
291
|
+
# @liquid_return [string]
|
93
292
|
def rstrip(input)
|
94
293
|
input.to_s.rstrip
|
95
294
|
end
|
96
295
|
|
296
|
+
# @liquid_public_docs
|
297
|
+
# @liquid_type filter
|
298
|
+
# @liquid_category string
|
299
|
+
# @liquid_summary
|
300
|
+
# Strips all HTML tags from a string.
|
301
|
+
# @liquid_syntax string | strip_html
|
302
|
+
# @liquid_return [string]
|
97
303
|
def strip_html(input)
|
98
|
-
empty
|
99
|
-
input.to_s.gsub(
|
304
|
+
empty = ''
|
305
|
+
result = input.to_s.gsub(STRIP_HTML_BLOCKS, empty)
|
306
|
+
result.gsub!(STRIP_HTML_TAGS, empty)
|
307
|
+
result
|
100
308
|
end
|
101
309
|
|
102
|
-
#
|
310
|
+
# @liquid_public_docs
|
311
|
+
# @liquid_type filter
|
312
|
+
# @liquid_category string
|
313
|
+
# @liquid_summary
|
314
|
+
# Strips all newline characters (line breaks) from a string.
|
315
|
+
# @liquid_syntax string | strip_newlines
|
316
|
+
# @liquid_return [string]
|
103
317
|
def strip_newlines(input)
|
104
|
-
input.to_s.gsub(/\r?\n/, ''
|
105
|
-
end
|
318
|
+
input.to_s.gsub(/\r?\n/, '')
|
319
|
+
end
|
320
|
+
|
321
|
+
# @liquid_public_docs
|
322
|
+
# @liquid_type filter
|
323
|
+
# @liquid_category array
|
324
|
+
# @liquid_summary
|
325
|
+
# Combines all of the items in an array into a single string, separated by a space.
|
326
|
+
# @liquid_syntax array | join
|
327
|
+
# @liquid_return [string]
|
328
|
+
def join(input, glue = ' ')
|
329
|
+
InputIterator.new(input, context).join(glue)
|
330
|
+
end
|
331
|
+
|
332
|
+
# @liquid_public_docs
|
333
|
+
# @liquid_type filter
|
334
|
+
# @liquid_category array
|
335
|
+
# @liquid_summary
|
336
|
+
# Sorts the items in an array in case-sensitive alphabetical, or numerical, order.
|
337
|
+
# @liquid_syntax array | sort
|
338
|
+
# @liquid_return [array[untyped]]
|
339
|
+
def sort(input, property = nil)
|
340
|
+
ary = InputIterator.new(input, context)
|
341
|
+
|
342
|
+
return [] if ary.empty?
|
106
343
|
|
107
|
-
|
108
|
-
|
109
|
-
|
344
|
+
if property.nil?
|
345
|
+
ary.sort do |a, b|
|
346
|
+
nil_safe_compare(a, b)
|
347
|
+
end
|
348
|
+
elsif ary.all? { |el| el.respond_to?(:[]) }
|
349
|
+
begin
|
350
|
+
ary.sort { |a, b| nil_safe_compare(a[property], b[property]) }
|
351
|
+
rescue TypeError
|
352
|
+
raise_property_error(property)
|
353
|
+
end
|
354
|
+
end
|
110
355
|
end
|
111
356
|
|
112
|
-
#
|
113
|
-
#
|
114
|
-
|
115
|
-
|
357
|
+
# @liquid_public_docs
|
358
|
+
# @liquid_type filter
|
359
|
+
# @liquid_category array
|
360
|
+
# @liquid_summary
|
361
|
+
# Sorts the items in an array in case-insensitive alphabetical order.
|
362
|
+
# @liquid_description
|
363
|
+
# > Caution:
|
364
|
+
# > You shouldn't use the `sort_natural` filter to sort numerical values. When comparing items an array, each item is converted to a
|
365
|
+
# > string, so sorting on numerical values can lead to unexpected results.
|
366
|
+
# @liquid_syntax array | sort_natural
|
367
|
+
# @liquid_return [array[untyped]]
|
368
|
+
def sort_natural(input, property = nil)
|
369
|
+
ary = InputIterator.new(input, context)
|
370
|
+
|
371
|
+
return [] if ary.empty?
|
372
|
+
|
116
373
|
if property.nil?
|
117
|
-
ary.sort
|
118
|
-
|
119
|
-
|
120
|
-
elsif ary.
|
121
|
-
|
374
|
+
ary.sort do |a, b|
|
375
|
+
nil_safe_casecmp(a, b)
|
376
|
+
end
|
377
|
+
elsif ary.all? { |el| el.respond_to?(:[]) }
|
378
|
+
begin
|
379
|
+
ary.sort { |a, b| nil_safe_casecmp(a[property], b[property]) }
|
380
|
+
rescue TypeError
|
381
|
+
raise_property_error(property)
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
# @liquid_public_docs
|
387
|
+
# @liquid_type filter
|
388
|
+
# @liquid_category array
|
389
|
+
# @liquid_summary
|
390
|
+
# Filters an array to include only items with a specific property value.
|
391
|
+
# @liquid_description
|
392
|
+
# This requires you to provide both the property name and the associated value.
|
393
|
+
# @liquid_syntax array | where: string, string
|
394
|
+
# @liquid_return [array[untyped]]
|
395
|
+
def where(input, property, target_value = nil)
|
396
|
+
ary = InputIterator.new(input, context)
|
397
|
+
|
398
|
+
if ary.empty?
|
399
|
+
[]
|
400
|
+
elsif target_value.nil?
|
401
|
+
ary.select do |item|
|
402
|
+
item[property]
|
403
|
+
rescue TypeError
|
404
|
+
raise_property_error(property)
|
405
|
+
rescue NoMethodError
|
406
|
+
return nil unless item.respond_to?(:[])
|
407
|
+
raise
|
408
|
+
end
|
409
|
+
else
|
410
|
+
ary.select do |item|
|
411
|
+
item[property] == target_value
|
412
|
+
rescue TypeError
|
413
|
+
raise_property_error(property)
|
414
|
+
rescue NoMethodError
|
415
|
+
return nil unless item.respond_to?(:[])
|
416
|
+
raise
|
417
|
+
end
|
122
418
|
end
|
123
419
|
end
|
124
420
|
|
125
|
-
#
|
126
|
-
#
|
421
|
+
# @liquid_public_docs
|
422
|
+
# @liquid_type filter
|
423
|
+
# @liquid_category array
|
424
|
+
# @liquid_summary
|
425
|
+
# Removes any duplicate items in an array.
|
426
|
+
# @liquid_syntax array | uniq
|
427
|
+
# @liquid_return [array[untyped]]
|
127
428
|
def uniq(input, property = nil)
|
128
|
-
ary = InputIterator.new(input)
|
429
|
+
ary = InputIterator.new(input, context)
|
430
|
+
|
129
431
|
if property.nil?
|
130
|
-
|
131
|
-
elsif
|
132
|
-
|
432
|
+
ary.uniq
|
433
|
+
elsif ary.empty? # The next two cases assume a non-empty array.
|
434
|
+
[]
|
435
|
+
else
|
436
|
+
ary.uniq do |item|
|
437
|
+
item[property]
|
438
|
+
rescue TypeError
|
439
|
+
raise_property_error(property)
|
440
|
+
rescue NoMethodError
|
441
|
+
return nil unless item.respond_to?(:[])
|
442
|
+
raise
|
443
|
+
end
|
133
444
|
end
|
134
445
|
end
|
135
446
|
|
136
|
-
#
|
447
|
+
# @liquid_public_docs
|
448
|
+
# @liquid_type filter
|
449
|
+
# @liquid_category array
|
450
|
+
# @liquid_summary
|
451
|
+
# Reverses the order of the items in an array.
|
452
|
+
# @liquid_syntax array | reverse
|
453
|
+
# @liquid_return [array[untyped]]
|
137
454
|
def reverse(input)
|
138
|
-
ary = InputIterator.new(input)
|
455
|
+
ary = InputIterator.new(input, context)
|
139
456
|
ary.reverse
|
140
457
|
end
|
141
458
|
|
142
|
-
#
|
459
|
+
# @liquid_public_docs
|
460
|
+
# @liquid_type filter
|
461
|
+
# @liquid_category array
|
462
|
+
# @liquid_summary
|
463
|
+
# Creates an array of values from a specific property of the items in an array.
|
464
|
+
# @liquid_syntax array | map: string
|
465
|
+
# @liquid_return [array[untyped]]
|
143
466
|
def map(input, property)
|
144
|
-
InputIterator.new(input).map do |e|
|
467
|
+
InputIterator.new(input, context).map do |e|
|
145
468
|
e = e.call if e.is_a?(Proc)
|
146
469
|
|
147
|
-
if property == "to_liquid"
|
470
|
+
if property == "to_liquid"
|
148
471
|
e
|
149
472
|
elsif e.respond_to?(:[])
|
150
|
-
e[property]
|
473
|
+
r = e[property]
|
474
|
+
r.is_a?(Proc) ? r.call : r
|
151
475
|
end
|
152
476
|
end
|
477
|
+
rescue TypeError
|
478
|
+
raise_property_error(property)
|
153
479
|
end
|
154
480
|
|
155
|
-
#
|
156
|
-
|
157
|
-
|
158
|
-
|
481
|
+
# @liquid_public_docs
|
482
|
+
# @liquid_type filter
|
483
|
+
# @liquid_category array
|
484
|
+
# @liquid_summary
|
485
|
+
# Removes any `nil` items from an array.
|
486
|
+
# @liquid_syntax array | compact
|
487
|
+
# @liquid_return [array[untyped]]
|
488
|
+
def compact(input, property = nil)
|
489
|
+
ary = InputIterator.new(input, context)
|
159
490
|
|
160
|
-
|
161
|
-
|
162
|
-
|
491
|
+
if property.nil?
|
492
|
+
ary.compact
|
493
|
+
elsif ary.empty? # The next two cases assume a non-empty array.
|
494
|
+
[]
|
495
|
+
else
|
496
|
+
ary.reject do |item|
|
497
|
+
item[property].nil?
|
498
|
+
rescue TypeError
|
499
|
+
raise_property_error(property)
|
500
|
+
rescue NoMethodError
|
501
|
+
return nil unless item.respond_to?(:[])
|
502
|
+
raise
|
503
|
+
end
|
504
|
+
end
|
163
505
|
end
|
164
506
|
|
165
|
-
#
|
507
|
+
# @liquid_public_docs
|
508
|
+
# @liquid_type filter
|
509
|
+
# @liquid_category string
|
510
|
+
# @liquid_summary
|
511
|
+
# Replaces any instance of a substring inside a string with a given string.
|
512
|
+
# @liquid_syntax string | replace: string, string
|
513
|
+
# @liquid_return [string]
|
514
|
+
def replace(input, string, replacement = '')
|
515
|
+
input.to_s.gsub(string.to_s, replacement.to_s)
|
516
|
+
end
|
517
|
+
|
518
|
+
# @liquid_public_docs
|
519
|
+
# @liquid_type filter
|
520
|
+
# @liquid_category string
|
521
|
+
# @liquid_summary
|
522
|
+
# Replaces the first instance of a substring inside a string with a given string.
|
523
|
+
# @liquid_syntax string | replace_first: string, string
|
524
|
+
# @liquid_return [string]
|
525
|
+
def replace_first(input, string, replacement = '')
|
526
|
+
input.to_s.sub(string.to_s, replacement.to_s)
|
527
|
+
end
|
528
|
+
|
529
|
+
# @liquid_public_docs
|
530
|
+
# @liquid_type filter
|
531
|
+
# @liquid_category string
|
532
|
+
# @liquid_summary
|
533
|
+
# Replaces the last instance of a substring inside a string with a given string.
|
534
|
+
# @liquid_syntax string | replace_last: string, string
|
535
|
+
# @liquid_return [string]
|
536
|
+
def replace_last(input, string, replacement)
|
537
|
+
input = input.to_s
|
538
|
+
string = string.to_s
|
539
|
+
replacement = replacement.to_s
|
540
|
+
|
541
|
+
start_index = input.rindex(string)
|
542
|
+
|
543
|
+
return input unless start_index
|
544
|
+
|
545
|
+
output = input.dup
|
546
|
+
output[start_index, string.length] = replacement
|
547
|
+
output
|
548
|
+
end
|
549
|
+
|
550
|
+
# @liquid_public_docs
|
551
|
+
# @liquid_type filter
|
552
|
+
# @liquid_category string
|
553
|
+
# @liquid_summary
|
554
|
+
# Removes any instance of a substring inside a string.
|
555
|
+
# @liquid_syntax string | remove: string
|
556
|
+
# @liquid_return [string]
|
166
557
|
def remove(input, string)
|
167
|
-
input
|
558
|
+
replace(input, string, '')
|
168
559
|
end
|
169
560
|
|
170
|
-
#
|
561
|
+
# @liquid_public_docs
|
562
|
+
# @liquid_type filter
|
563
|
+
# @liquid_category string
|
564
|
+
# @liquid_summary
|
565
|
+
# Removes the first instance of a substring inside a string.
|
566
|
+
# @liquid_syntax string | remove_first: string
|
567
|
+
# @liquid_return [string]
|
171
568
|
def remove_first(input, string)
|
172
|
-
input
|
173
|
-
end
|
174
|
-
|
175
|
-
#
|
569
|
+
replace_first(input, string, '')
|
570
|
+
end
|
571
|
+
|
572
|
+
# @liquid_public_docs
|
573
|
+
# @liquid_type filter
|
574
|
+
# @liquid_category string
|
575
|
+
# @liquid_summary
|
576
|
+
# Removes the last instance of a substring inside a string.
|
577
|
+
# @liquid_syntax string | remove_last: string
|
578
|
+
# @liquid_return [string]
|
579
|
+
def remove_last(input, string)
|
580
|
+
replace_last(input, string, '')
|
581
|
+
end
|
582
|
+
|
583
|
+
# @liquid_public_docs
|
584
|
+
# @liquid_type filter
|
585
|
+
# @liquid_category string
|
586
|
+
# @liquid_summary
|
587
|
+
# Adds a given string to the end of a string.
|
588
|
+
# @liquid_syntax string | append: string
|
589
|
+
# @liquid_return [string]
|
176
590
|
def append(input, string)
|
177
591
|
input.to_s + string.to_s
|
178
592
|
end
|
179
593
|
|
180
|
-
#
|
594
|
+
# @liquid_public_docs
|
595
|
+
# @liquid_type filter
|
596
|
+
# @liquid_category array
|
597
|
+
# @liquid_summary
|
598
|
+
# Concatenates (combines) two arrays.
|
599
|
+
# @liquid_description
|
600
|
+
# > Note:
|
601
|
+
# > The `concat` filter won't filter out duplicates. If you want to remove duplicates, then you need to use the
|
602
|
+
# > [`uniq` filter](/api/liquid/filters#uniq).
|
603
|
+
# @liquid_syntax array | concat: array
|
604
|
+
# @liquid_return [array[untyped]]
|
605
|
+
def concat(input, array)
|
606
|
+
unless array.respond_to?(:to_ary)
|
607
|
+
raise ArgumentError, "concat filter requires an array argument"
|
608
|
+
end
|
609
|
+
InputIterator.new(input, context).concat(array)
|
610
|
+
end
|
611
|
+
|
612
|
+
# @liquid_public_docs
|
613
|
+
# @liquid_type filter
|
614
|
+
# @liquid_category string
|
615
|
+
# @liquid_summary
|
616
|
+
# Adds a given string to the beginning of a string.
|
617
|
+
# @liquid_syntax string | prepend: string
|
618
|
+
# @liquid_return [string]
|
181
619
|
def prepend(input, string)
|
182
620
|
string.to_s + input.to_s
|
183
621
|
end
|
184
622
|
|
185
|
-
#
|
623
|
+
# @liquid_public_docs
|
624
|
+
# @liquid_type filter
|
625
|
+
# @liquid_category string
|
626
|
+
# @liquid_summary
|
627
|
+
# Converts newlines (`\n`) in a string to HTML line breaks (`<br>`).
|
628
|
+
# @liquid_syntax string | newline_to_br
|
629
|
+
# @liquid_return [string]
|
186
630
|
def newline_to_br(input)
|
187
|
-
input.to_s.gsub(/\n/, "<br />\n"
|
631
|
+
input.to_s.gsub(/\r?\n/, "<br />\n")
|
188
632
|
end
|
189
633
|
|
190
634
|
# Reformat a date using Ruby's core Time#strftime( string ) -> string
|
@@ -221,115 +665,235 @@ module Liquid
|
|
221
665
|
def date(input, format)
|
222
666
|
return input if format.to_s.empty?
|
223
667
|
|
224
|
-
return input unless date = to_date(input)
|
668
|
+
return input unless (date = Utils.to_date(input))
|
225
669
|
|
226
670
|
date.strftime(format.to_s)
|
227
671
|
end
|
228
672
|
|
229
|
-
#
|
230
|
-
#
|
231
|
-
#
|
232
|
-
#
|
233
|
-
#
|
673
|
+
# @liquid_public_docs
|
674
|
+
# @liquid_type filter
|
675
|
+
# @liquid_category array
|
676
|
+
# @liquid_summary
|
677
|
+
# Returns the first item in an array.
|
678
|
+
# @liquid_syntax array | first
|
679
|
+
# @liquid_return [untyped]
|
234
680
|
def first(array)
|
235
681
|
array.first if array.respond_to?(:first)
|
236
682
|
end
|
237
683
|
|
238
|
-
#
|
239
|
-
#
|
240
|
-
#
|
241
|
-
#
|
242
|
-
#
|
684
|
+
# @liquid_public_docs
|
685
|
+
# @liquid_type filter
|
686
|
+
# @liquid_category array
|
687
|
+
# @liquid_summary
|
688
|
+
# Returns the last item in an array.
|
689
|
+
# @liquid_syntax array | last
|
690
|
+
# @liquid_return [untyped]
|
243
691
|
def last(array)
|
244
692
|
array.last if array.respond_to?(:last)
|
245
693
|
end
|
246
694
|
|
247
|
-
#
|
695
|
+
# @liquid_public_docs
|
696
|
+
# @liquid_type filter
|
697
|
+
# @liquid_category math
|
698
|
+
# @liquid_summary
|
699
|
+
# Returns the absolute value of a number.
|
700
|
+
# @liquid_syntax number | abs
|
701
|
+
# @liquid_return [number]
|
702
|
+
def abs(input)
|
703
|
+
result = Utils.to_number(input).abs
|
704
|
+
result.is_a?(BigDecimal) ? result.to_f : result
|
705
|
+
end
|
706
|
+
|
707
|
+
# @liquid_public_docs
|
708
|
+
# @liquid_type filter
|
709
|
+
# @liquid_category math
|
710
|
+
# @liquid_summary
|
711
|
+
# Adds two numbers.
|
712
|
+
# @liquid_syntax number | plus: number
|
713
|
+
# @liquid_return [number]
|
248
714
|
def plus(input, operand)
|
249
715
|
apply_operation(input, operand, :+)
|
250
716
|
end
|
251
717
|
|
252
|
-
#
|
718
|
+
# @liquid_public_docs
|
719
|
+
# @liquid_type filter
|
720
|
+
# @liquid_category math
|
721
|
+
# @liquid_summary
|
722
|
+
# Subtracts a given number from another number.
|
723
|
+
# @liquid_syntax number | minus: number
|
724
|
+
# @liquid_return [number]
|
253
725
|
def minus(input, operand)
|
254
726
|
apply_operation(input, operand, :-)
|
255
727
|
end
|
256
728
|
|
257
|
-
#
|
729
|
+
# @liquid_public_docs
|
730
|
+
# @liquid_type filter
|
731
|
+
# @liquid_category math
|
732
|
+
# @liquid_summary
|
733
|
+
# Multiplies a number by a given number.
|
734
|
+
# @liquid_syntax number | times: number
|
735
|
+
# @liquid_return [number]
|
258
736
|
def times(input, operand)
|
259
737
|
apply_operation(input, operand, :*)
|
260
738
|
end
|
261
739
|
|
262
|
-
#
|
740
|
+
# @liquid_public_docs
|
741
|
+
# @liquid_type filter
|
742
|
+
# @liquid_category math
|
743
|
+
# @liquid_summary
|
744
|
+
# Divides a number by a given number.
|
745
|
+
# @liquid_syntax number | divided_by: number
|
746
|
+
# @liquid_return [number]
|
263
747
|
def divided_by(input, operand)
|
264
748
|
apply_operation(input, operand, :/)
|
749
|
+
rescue ::ZeroDivisionError => e
|
750
|
+
raise Liquid::ZeroDivisionError, e.message
|
265
751
|
end
|
266
752
|
|
753
|
+
# @liquid_public_docs
|
754
|
+
# @liquid_type filter
|
755
|
+
# @liquid_category math
|
756
|
+
# @liquid_summary
|
757
|
+
# Returns the remainder of dividing a number by a given number.
|
758
|
+
# @liquid_syntax number | modulo: number
|
759
|
+
# @liquid_return [number]
|
267
760
|
def modulo(input, operand)
|
268
761
|
apply_operation(input, operand, :%)
|
762
|
+
rescue ::ZeroDivisionError => e
|
763
|
+
raise Liquid::ZeroDivisionError, e.message
|
269
764
|
end
|
270
765
|
|
766
|
+
# @liquid_public_docs
|
767
|
+
# @liquid_type filter
|
768
|
+
# @liquid_category math
|
769
|
+
# @liquid_summary
|
770
|
+
# Rounds a number to the nearest integer.
|
771
|
+
# @liquid_syntax number | round
|
772
|
+
# @liquid_return [number]
|
271
773
|
def round(input, n = 0)
|
272
|
-
result = to_number(input).round(to_number(n))
|
774
|
+
result = Utils.to_number(input).round(Utils.to_number(n))
|
273
775
|
result = result.to_f if result.is_a?(BigDecimal)
|
274
776
|
result = result.to_i if n == 0
|
275
777
|
result
|
778
|
+
rescue ::FloatDomainError => e
|
779
|
+
raise Liquid::FloatDomainError, e.message
|
276
780
|
end
|
277
781
|
|
782
|
+
# @liquid_public_docs
|
783
|
+
# @liquid_type filter
|
784
|
+
# @liquid_category math
|
785
|
+
# @liquid_summary
|
786
|
+
# Rounds a number up to the nearest integer.
|
787
|
+
# @liquid_syntax number | ceil
|
788
|
+
# @liquid_return [number]
|
278
789
|
def ceil(input)
|
279
|
-
to_number(input).ceil.to_i
|
790
|
+
Utils.to_number(input).ceil.to_i
|
791
|
+
rescue ::FloatDomainError => e
|
792
|
+
raise Liquid::FloatDomainError, e.message
|
793
|
+
end
|
794
|
+
|
795
|
+
# @liquid_public_docs
|
796
|
+
# @liquid_type filter
|
797
|
+
# @liquid_category math
|
798
|
+
# @liquid_summary
|
799
|
+
# Rounds a number down to the nearest integer.
|
800
|
+
# @liquid_syntax number | floor
|
801
|
+
# @liquid_return [number]
|
802
|
+
def floor(input)
|
803
|
+
Utils.to_number(input).floor.to_i
|
804
|
+
rescue ::FloatDomainError => e
|
805
|
+
raise Liquid::FloatDomainError, e.message
|
806
|
+
end
|
807
|
+
|
808
|
+
# @liquid_public_docs
|
809
|
+
# @liquid_type filter
|
810
|
+
# @liquid_category math
|
811
|
+
# @liquid_summary
|
812
|
+
# Limits a number to a minimum value.
|
813
|
+
# @liquid_syntax number | at_least
|
814
|
+
# @liquid_return [number]
|
815
|
+
def at_least(input, n)
|
816
|
+
min_value = Utils.to_number(n)
|
817
|
+
|
818
|
+
result = Utils.to_number(input)
|
819
|
+
result = min_value if min_value > result
|
820
|
+
result.is_a?(BigDecimal) ? result.to_f : result
|
280
821
|
end
|
281
822
|
|
282
|
-
|
283
|
-
|
823
|
+
# @liquid_public_docs
|
824
|
+
# @liquid_type filter
|
825
|
+
# @liquid_category math
|
826
|
+
# @liquid_summary
|
827
|
+
# Limits a number to a maximum value.
|
828
|
+
# @liquid_syntax number | at_most
|
829
|
+
# @liquid_return [number]
|
830
|
+
def at_most(input, n)
|
831
|
+
max_value = Utils.to_number(n)
|
832
|
+
|
833
|
+
result = Utils.to_number(input)
|
834
|
+
result = max_value if max_value < result
|
835
|
+
result.is_a?(BigDecimal) ? result.to_f : result
|
284
836
|
end
|
285
837
|
|
286
|
-
|
287
|
-
|
288
|
-
|
838
|
+
# @liquid_public_docs
|
839
|
+
# @liquid_type filter
|
840
|
+
# @liquid_category default
|
841
|
+
# @liquid_summary
|
842
|
+
# Sets a default value for any variable whose value is one of the following:
|
843
|
+
#
|
844
|
+
# - [`empty`](/api/liquid/basics#empty)
|
845
|
+
# - [`false`](/api/liquid/basics#truthy-and-falsy)
|
846
|
+
# - [`nil`](/api/liquid/basics#nil)
|
847
|
+
# @liquid_syntax variable | default: variable
|
848
|
+
# @liquid_return [untyped]
|
849
|
+
# @liquid_optional_param allow_false [boolean] Whether to use false values instead of the default.
|
850
|
+
def default(input, default_value = '', options = {})
|
851
|
+
options = {} unless options.is_a?(Hash)
|
852
|
+
false_check = options['allow_false'] ? input.nil? : !Liquid::Utils.to_liquid_value(input)
|
853
|
+
false_check || (input.respond_to?(:empty?) && input.empty?) ? default_value : input
|
289
854
|
end
|
290
855
|
|
291
856
|
private
|
292
857
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
0
|
303
|
-
end
|
858
|
+
attr_reader :context
|
859
|
+
|
860
|
+
def raise_property_error(property)
|
861
|
+
raise Liquid::ArgumentError, "cannot select the property '#{property}'"
|
862
|
+
end
|
863
|
+
|
864
|
+
def apply_operation(input, operand, operation)
|
865
|
+
result = Utils.to_number(input).send(operation, Utils.to_number(operand))
|
866
|
+
result.is_a?(BigDecimal) ? result.to_f : result
|
304
867
|
end
|
305
868
|
|
306
|
-
def
|
307
|
-
|
869
|
+
def nil_safe_compare(a, b)
|
870
|
+
result = a <=> b
|
308
871
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
Time.parse(obj)
|
872
|
+
if result
|
873
|
+
result
|
874
|
+
elsif a.nil?
|
875
|
+
1
|
876
|
+
elsif b.nil?
|
877
|
+
-1
|
316
878
|
else
|
317
|
-
|
879
|
+
raise Liquid::ArgumentError, "cannot sort values of incompatible types"
|
318
880
|
end
|
319
|
-
rescue ::ArgumentError
|
320
|
-
nil
|
321
881
|
end
|
322
882
|
|
323
|
-
def
|
324
|
-
|
325
|
-
|
883
|
+
def nil_safe_casecmp(a, b)
|
884
|
+
if !a.nil? && !b.nil?
|
885
|
+
a.to_s.casecmp(b.to_s)
|
886
|
+
else
|
887
|
+
a.nil? ? 1 : -1
|
888
|
+
end
|
326
889
|
end
|
327
890
|
|
328
891
|
class InputIterator
|
329
892
|
include Enumerable
|
330
893
|
|
331
|
-
def initialize(input)
|
332
|
-
@
|
894
|
+
def initialize(input, context)
|
895
|
+
@context = context
|
896
|
+
@input = if input.is_a?(Array)
|
333
897
|
input.flatten
|
334
898
|
elsif input.is_a?(Hash)
|
335
899
|
[input]
|
@@ -341,16 +905,35 @@ module Liquid
|
|
341
905
|
end
|
342
906
|
|
343
907
|
def join(glue)
|
344
|
-
to_a.join(glue)
|
908
|
+
to_a.join(glue.to_s)
|
909
|
+
end
|
910
|
+
|
911
|
+
def concat(args)
|
912
|
+
to_a.concat(args)
|
345
913
|
end
|
346
914
|
|
347
915
|
def reverse
|
348
916
|
reverse_each.to_a
|
349
917
|
end
|
350
918
|
|
919
|
+
def uniq(&block)
|
920
|
+
to_a.uniq(&block)
|
921
|
+
end
|
922
|
+
|
923
|
+
def compact
|
924
|
+
to_a.compact
|
925
|
+
end
|
926
|
+
|
927
|
+
def empty?
|
928
|
+
@input.each { return false }
|
929
|
+
true
|
930
|
+
end
|
931
|
+
|
351
932
|
def each
|
352
933
|
@input.each do |e|
|
353
|
-
|
934
|
+
e = e.respond_to?(:to_liquid) ? e.to_liquid : e
|
935
|
+
e.context = @context if e.respond_to?(:context=)
|
936
|
+
yield(e)
|
354
937
|
end
|
355
938
|
end
|
356
939
|
end
|