liquid 2.6.3 → 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 +272 -26
- data/README.md +67 -3
- data/lib/liquid/block.rb +62 -94
- data/lib/liquid/block_body.rb +255 -0
- data/lib/liquid/condition.rb +96 -38
- data/lib/liquid/context.rb +172 -154
- data/lib/liquid/document.rb +57 -9
- data/lib/liquid/drop.rb +33 -14
- data/lib/liquid/errors.rb +56 -10
- data/lib/liquid/expression.rb +45 -0
- data/lib/liquid/extensions.rb +21 -7
- data/lib/liquid/file_system.rb +27 -14
- data/lib/liquid/forloop_drop.rb +92 -0
- data/lib/liquid/i18n.rb +41 -0
- data/lib/liquid/interrupts.rb +3 -2
- data/lib/liquid/lexer.rb +62 -0
- data/lib/liquid/locales/en.yml +29 -0
- data/lib/liquid/parse_context.rb +54 -0
- data/lib/liquid/parse_tree_visitor.rb +42 -0
- data/lib/liquid/parser.rb +102 -0
- data/lib/liquid/parser_switching.rb +45 -0
- data/lib/liquid/partial_cache.rb +24 -0
- data/lib/liquid/profiler/hooks.rb +35 -0
- data/lib/liquid/profiler.rb +139 -0
- data/lib/liquid/range_lookup.rb +47 -0
- data/lib/liquid/registers.rb +51 -0
- data/lib/liquid/resource_limits.rb +62 -0
- data/lib/liquid/standardfilters.rb +789 -118
- 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 +49 -10
- data/lib/liquid/tags/assign.rb +61 -19
- data/lib/liquid/tags/break.rb +14 -4
- data/lib/liquid/tags/capture.rb +29 -21
- data/lib/liquid/tags/case.rb +80 -31
- data/lib/liquid/tags/comment.rb +24 -2
- data/lib/liquid/tags/continue.rb +14 -13
- data/lib/liquid/tags/cycle.rb +50 -32
- data/lib/liquid/tags/decrement.rb +24 -26
- data/lib/liquid/tags/echo.rb +41 -0
- data/lib/liquid/tags/for.rb +164 -100
- data/lib/liquid/tags/if.rb +105 -44
- data/lib/liquid/tags/ifchanged.rb +10 -11
- data/lib/liquid/tags/include.rb +85 -65
- data/lib/liquid/tags/increment.rb +24 -22
- data/lib/liquid/tags/inline_comment.rb +43 -0
- data/lib/liquid/tags/raw.rb +50 -11
- data/lib/liquid/tags/render.rb +109 -0
- data/lib/liquid/tags/table_row.rb +88 -0
- data/lib/liquid/tags/unless.rb +37 -21
- data/lib/liquid/template.rb +124 -46
- 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 +68 -5
- data/lib/liquid/variable.rb +128 -32
- data/lib/liquid/variable_lookup.rb +96 -0
- data/lib/liquid/version.rb +3 -1
- data/lib/liquid.rb +36 -13
- metadata +69 -77
- data/lib/extras/liquid_view.rb +0 -51
- data/lib/liquid/htmltags.rb +0 -73
- data/lib/liquid/module_ex.rb +0 -62
- data/lib/liquid/strainer.rb +0 -53
- data/test/liquid/assign_test.rb +0 -21
- data/test/liquid/block_test.rb +0 -58
- data/test/liquid/capture_test.rb +0 -40
- data/test/liquid/condition_test.rb +0 -127
- data/test/liquid/context_test.rb +0 -478
- data/test/liquid/drop_test.rb +0 -180
- data/test/liquid/error_handling_test.rb +0 -81
- data/test/liquid/file_system_test.rb +0 -29
- data/test/liquid/filter_test.rb +0 -125
- data/test/liquid/hash_ordering_test.rb +0 -25
- data/test/liquid/module_ex_test.rb +0 -87
- data/test/liquid/output_test.rb +0 -116
- data/test/liquid/parsing_quirks_test.rb +0 -52
- data/test/liquid/regexp_test.rb +0 -44
- data/test/liquid/security_test.rb +0 -64
- data/test/liquid/standard_filter_test.rb +0 -263
- data/test/liquid/strainer_test.rb +0 -52
- data/test/liquid/tags/break_tag_test.rb +0 -16
- data/test/liquid/tags/continue_tag_test.rb +0 -16
- data/test/liquid/tags/for_tag_test.rb +0 -297
- data/test/liquid/tags/html_tag_test.rb +0 -63
- data/test/liquid/tags/if_else_tag_test.rb +0 -166
- data/test/liquid/tags/include_tag_test.rb +0 -166
- data/test/liquid/tags/increment_tag_test.rb +0 -24
- data/test/liquid/tags/raw_tag_test.rb +0 -24
- data/test/liquid/tags/standard_tag_test.rb +0 -295
- data/test/liquid/tags/statements_test.rb +0 -134
- data/test/liquid/tags/unless_else_tag_test.rb +0 -26
- data/test/liquid/template_test.rb +0 -146
- data/test/liquid/variable_test.rb +0 -186
- data/test/test_helper.rb +0 -29
- /data/{MIT-LICENSE → LICENSE} +0 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Liquid
|
4
|
+
# @liquid_public_docs
|
5
|
+
# @liquid_type tag
|
6
|
+
# @liquid_category iteration
|
7
|
+
# @liquid_name tablerow
|
8
|
+
# @liquid_summary
|
9
|
+
# Generates HTML table rows for every item in an array.
|
10
|
+
# @liquid_description
|
11
|
+
# The `tablerow` tag must be wrapped in HTML `<table>` and `</table>` tags.
|
12
|
+
#
|
13
|
+
# > Tip:
|
14
|
+
# > Every `tablerow` loop has an associated [`tablerowloop` object](/api/liquid/objects#tablerowloop) with information about the loop.
|
15
|
+
# @liquid_syntax
|
16
|
+
# {% tablerow variable in array %}
|
17
|
+
# expression
|
18
|
+
# {% endtablerow %}
|
19
|
+
# @liquid_syntax_keyword variable The current item in the array.
|
20
|
+
# @liquid_syntax_keyword array The array to iterate over.
|
21
|
+
# @liquid_syntax_keyword expression The expression to render.
|
22
|
+
# @liquid_optional_param cols [number] The number of columns that the table should have.
|
23
|
+
# @liquid_optional_param limit [number] The number of iterations to perform.
|
24
|
+
# @liquid_optional_param offset [number] The 1-based index to start iterating at.
|
25
|
+
# @liquid_optional_param range [untyped] A custom numeric range to iterate over.
|
26
|
+
class TableRow < Block
|
27
|
+
Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)/o
|
28
|
+
|
29
|
+
attr_reader :variable_name, :collection_name, :attributes
|
30
|
+
|
31
|
+
def initialize(tag_name, markup, options)
|
32
|
+
super
|
33
|
+
if markup =~ Syntax
|
34
|
+
@variable_name = Regexp.last_match(1)
|
35
|
+
@collection_name = parse_expression(Regexp.last_match(2))
|
36
|
+
@attributes = {}
|
37
|
+
markup.scan(TagAttributes) do |key, value|
|
38
|
+
@attributes[key] = parse_expression(value)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
raise SyntaxError, options[:locale].t("errors.syntax.table_row")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def render_to_output_buffer(context, output)
|
46
|
+
(collection = context.evaluate(@collection_name)) || (return '')
|
47
|
+
|
48
|
+
from = @attributes.key?('offset') ? context.evaluate(@attributes['offset']).to_i : 0
|
49
|
+
to = @attributes.key?('limit') ? from + context.evaluate(@attributes['limit']).to_i : nil
|
50
|
+
|
51
|
+
collection = Utils.slice_collection(collection, from, to)
|
52
|
+
length = collection.length
|
53
|
+
|
54
|
+
cols = context.evaluate(@attributes['cols']).to_i
|
55
|
+
|
56
|
+
output << "<tr class=\"row1\">\n"
|
57
|
+
context.stack do
|
58
|
+
tablerowloop = Liquid::TablerowloopDrop.new(length, cols)
|
59
|
+
context['tablerowloop'] = tablerowloop
|
60
|
+
|
61
|
+
collection.each do |item|
|
62
|
+
context[@variable_name] = item
|
63
|
+
|
64
|
+
output << "<td class=\"col#{tablerowloop.col}\">"
|
65
|
+
super
|
66
|
+
output << '</td>'
|
67
|
+
|
68
|
+
if tablerowloop.col_last && !tablerowloop.last
|
69
|
+
output << "</tr>\n<tr class=\"row#{tablerowloop.row + 1}\">"
|
70
|
+
end
|
71
|
+
|
72
|
+
tablerowloop.send(:increment!)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
output << "</tr>\n"
|
77
|
+
output
|
78
|
+
end
|
79
|
+
|
80
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
81
|
+
def children
|
82
|
+
super + @node.attributes.values + [@node.collection_name]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
Template.register_tag('tablerow', TableRow)
|
88
|
+
end
|
data/lib/liquid/tags/unless.rb
CHANGED
@@ -1,33 +1,49 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative 'if'
|
4
4
|
|
5
|
-
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
5
|
+
module Liquid
|
6
|
+
# @liquid_public_docs
|
7
|
+
# @liquid_type tag
|
8
|
+
# @liquid_category conditional
|
9
|
+
# @liquid_name unless
|
10
|
+
# @liquid_summary
|
11
|
+
# Renders an expression unless a specific condition is `true`.
|
12
|
+
# @liquid_description
|
13
|
+
# > Tip:
|
14
|
+
# > Similar to the [`if` tag](/api/liquid/tags#if), you can use `elsif` to add more conditions to an `unless` tag.
|
15
|
+
# @liquid_syntax
|
16
|
+
# {% unless condition %}
|
17
|
+
# expression
|
18
|
+
# {% endunless %}
|
19
|
+
# @liquid_syntax_keyword condition The condition to evaluate.
|
20
|
+
# @liquid_syntax_keyword expression The expression to render unless the condition is met.
|
9
21
|
class Unless < If
|
10
|
-
def
|
11
|
-
|
22
|
+
def render_to_output_buffer(context, output)
|
23
|
+
# First condition is interpreted backwards ( if not )
|
24
|
+
first_block = @blocks.first
|
25
|
+
result = Liquid::Utils.to_liquid_value(
|
26
|
+
first_block.evaluate(context)
|
27
|
+
)
|
12
28
|
|
13
|
-
|
14
|
-
first_block
|
15
|
-
|
16
|
-
return render_all(first_block.attachment, context)
|
17
|
-
end
|
29
|
+
unless result
|
30
|
+
return first_block.attachment.render_to_output_buffer(context, output)
|
31
|
+
end
|
18
32
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
33
|
+
# After the first condition unless works just like if
|
34
|
+
@blocks[1..-1].each do |block|
|
35
|
+
result = Liquid::Utils.to_liquid_value(
|
36
|
+
block.evaluate(context)
|
37
|
+
)
|
25
38
|
|
26
|
-
|
39
|
+
if result
|
40
|
+
return block.attachment.render_to_output_buffer(context, output)
|
41
|
+
end
|
27
42
|
end
|
43
|
+
|
44
|
+
output
|
28
45
|
end
|
29
46
|
end
|
30
47
|
|
31
|
-
|
32
48
|
Template.register_tag('unless', Unless)
|
33
49
|
end
|
data/lib/liquid/template.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module Liquid
|
3
4
|
# Templates are central to liquid.
|
4
5
|
# Interpretating templates is a two step process. First you compile the
|
5
6
|
# source code you got. During compile time some extensive error checking is performed.
|
@@ -14,49 +15,100 @@ module Liquid
|
|
14
15
|
# template.render('user_name' => 'bob')
|
15
16
|
#
|
16
17
|
class Template
|
17
|
-
attr_accessor :root
|
18
|
-
|
18
|
+
attr_accessor :root
|
19
|
+
attr_reader :resource_limits, :warnings
|
19
20
|
|
20
|
-
class
|
21
|
-
|
22
|
-
|
21
|
+
class TagRegistry
|
22
|
+
include Enumerable
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@tags = {}
|
26
|
+
@cache = {}
|
27
|
+
end
|
28
|
+
|
29
|
+
def [](tag_name)
|
30
|
+
return nil unless @tags.key?(tag_name)
|
31
|
+
return @cache[tag_name] if Liquid.cache_classes
|
32
|
+
|
33
|
+
lookup_class(@tags[tag_name]).tap { |o| @cache[tag_name] = o }
|
23
34
|
end
|
24
35
|
|
25
|
-
def
|
26
|
-
|
36
|
+
def []=(tag_name, klass)
|
37
|
+
@tags[tag_name] = klass.name
|
38
|
+
@cache[tag_name] = klass
|
27
39
|
end
|
28
40
|
|
29
|
-
def
|
30
|
-
tags
|
41
|
+
def delete(tag_name)
|
42
|
+
@tags.delete(tag_name)
|
43
|
+
@cache.delete(tag_name)
|
44
|
+
end
|
45
|
+
|
46
|
+
def each(&block)
|
47
|
+
@tags.each(&block)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def lookup_class(name)
|
53
|
+
Object.const_get(name)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
attr_reader :profiler
|
58
|
+
|
59
|
+
class << self
|
60
|
+
# Sets how strict the parser should be.
|
61
|
+
# :lax acts like liquid 2.5 and silently ignores malformed tags in most cases.
|
62
|
+
# :warn is the default and will give deprecation warnings when invalid syntax is used.
|
63
|
+
# :strict will enforce correct syntax.
|
64
|
+
attr_accessor :error_mode
|
65
|
+
Template.error_mode = :lax
|
66
|
+
|
67
|
+
attr_accessor :default_exception_renderer
|
68
|
+
Template.default_exception_renderer = lambda do |exception|
|
69
|
+
exception
|
31
70
|
end
|
32
71
|
|
33
|
-
|
34
|
-
|
72
|
+
attr_accessor :file_system
|
73
|
+
Template.file_system = BlankFileSystem.new
|
74
|
+
|
75
|
+
attr_accessor :tags
|
76
|
+
Template.tags = TagRegistry.new
|
77
|
+
private :tags=
|
78
|
+
|
79
|
+
def register_tag(name, klass)
|
80
|
+
tags[name.to_s] = klass
|
35
81
|
end
|
36
82
|
|
37
83
|
# Pass a module with filter methods which should be available
|
38
84
|
# to all liquid views. Good for registering the standard library
|
39
85
|
def register_filter(mod)
|
40
|
-
|
86
|
+
StrainerFactory.add_global_filter(mod)
|
41
87
|
end
|
42
88
|
|
89
|
+
attr_accessor :default_resource_limits
|
90
|
+
Template.default_resource_limits = {}
|
91
|
+
private :default_resource_limits=
|
92
|
+
|
43
93
|
# creates a new <tt>Template</tt> object from liquid source code
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
94
|
+
# To enable profiling, pass in <tt>profile: true</tt> as an option.
|
95
|
+
# See Liquid::Profiler for more information
|
96
|
+
def parse(source, options = {})
|
97
|
+
new.parse(source, options)
|
48
98
|
end
|
49
99
|
end
|
50
100
|
|
51
|
-
# creates a new <tt>Template</tt> from an array of tokens. Use <tt>Template.parse</tt> instead
|
52
101
|
def initialize
|
53
|
-
@
|
102
|
+
@rethrow_errors = false
|
103
|
+
@resource_limits = ResourceLimits.new(Template.default_resource_limits)
|
54
104
|
end
|
55
105
|
|
56
106
|
# Parse source code.
|
57
107
|
# Returns self for easy chaining
|
58
|
-
def parse(source)
|
59
|
-
|
108
|
+
def parse(source, options = {})
|
109
|
+
parse_context = configure_options(options)
|
110
|
+
tokenizer = parse_context.new_tokenizer(source, start_line_number: @line_numbers && 1)
|
111
|
+
@root = Document.parse(tokenizer, parse_context)
|
60
112
|
self
|
61
113
|
end
|
62
114
|
|
@@ -81,6 +133,9 @@ module Liquid
|
|
81
133
|
# if you use the same filters over and over again consider registering them globally
|
82
134
|
# with <tt>Template.register_filter</tt>
|
83
135
|
#
|
136
|
+
# if profiling was enabled in <tt>Template#parse</tt> then the resulting profiling information
|
137
|
+
# will be available via <tt>Template#profiler</tt>
|
138
|
+
#
|
84
139
|
# Following options can be passed:
|
85
140
|
#
|
86
141
|
# * <tt>filters</tt> : array with local filters
|
@@ -92,41 +147,51 @@ module Liquid
|
|
92
147
|
|
93
148
|
context = case args.first
|
94
149
|
when Liquid::Context
|
95
|
-
args.shift
|
150
|
+
c = args.shift
|
151
|
+
|
152
|
+
if @rethrow_errors
|
153
|
+
c.exception_renderer = Liquid::RAISE_EXCEPTION_LAMBDA
|
154
|
+
end
|
155
|
+
|
156
|
+
c
|
96
157
|
when Liquid::Drop
|
97
|
-
drop
|
158
|
+
drop = args.shift
|
98
159
|
drop.context = Context.new([drop, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits)
|
99
160
|
when Hash
|
100
161
|
Context.new([args.shift, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits)
|
101
162
|
when nil
|
102
163
|
Context.new(assigns, instance_assigns, registers, @rethrow_errors, @resource_limits)
|
103
164
|
else
|
104
|
-
raise ArgumentError, "
|
165
|
+
raise ArgumentError, "Expected Hash or Liquid::Context as parameter"
|
105
166
|
end
|
106
167
|
|
168
|
+
output = nil
|
169
|
+
|
107
170
|
case args.last
|
108
171
|
when Hash
|
109
172
|
options = args.pop
|
173
|
+
output = options[:output] if options[:output]
|
174
|
+
static_registers = context.registers.static
|
110
175
|
|
111
|
-
|
112
|
-
|
113
|
-
end
|
114
|
-
|
115
|
-
if options[:filters]
|
116
|
-
context.add_filters(options[:filters])
|
176
|
+
options[:registers]&.each do |key, register|
|
177
|
+
static_registers[key] = register
|
117
178
|
end
|
118
179
|
|
119
|
-
|
120
|
-
|
121
|
-
when Array
|
180
|
+
apply_options_to_context(context, options)
|
181
|
+
when Module, Array
|
122
182
|
context.add_filters(args.pop)
|
123
183
|
end
|
124
184
|
|
185
|
+
# Retrying a render resets resource usage
|
186
|
+
context.resource_limits.reset
|
187
|
+
|
188
|
+
if @profiling && context.profiler.nil?
|
189
|
+
@profiler = context.profiler = Liquid::Profiler.new
|
190
|
+
end
|
191
|
+
|
125
192
|
begin
|
126
193
|
# render the nodelist.
|
127
|
-
|
128
|
-
result = @root.render(context)
|
129
|
-
result.respond_to?(:join) ? result.join : result
|
194
|
+
@root.render_to_output_buffer(context, output || +'')
|
130
195
|
rescue Liquid::MemoryError => e
|
131
196
|
context.handle_error(e)
|
132
197
|
ensure
|
@@ -135,22 +200,35 @@ module Liquid
|
|
135
200
|
end
|
136
201
|
|
137
202
|
def render!(*args)
|
138
|
-
@rethrow_errors = true
|
203
|
+
@rethrow_errors = true
|
204
|
+
render(*args)
|
139
205
|
end
|
140
206
|
|
141
|
-
|
207
|
+
def render_to_output_buffer(context, output)
|
208
|
+
render(context, output: output)
|
209
|
+
end
|
142
210
|
|
143
|
-
|
144
|
-
def tokenize(source)
|
145
|
-
source = source.source if source.respond_to?(:source)
|
146
|
-
return [] if source.to_s.empty?
|
147
|
-
tokens = source.split(TemplateParser)
|
211
|
+
private
|
148
212
|
|
149
|
-
|
150
|
-
|
213
|
+
def configure_options(options)
|
214
|
+
if (profiling = options[:profile])
|
215
|
+
raise "Profiler not loaded, require 'liquid/profiler' first" unless defined?(Liquid::Profiler)
|
216
|
+
end
|
151
217
|
|
152
|
-
|
218
|
+
@options = options
|
219
|
+
@profiling = profiling
|
220
|
+
@line_numbers = options[:line_numbers] || @profiling
|
221
|
+
parse_context = options.is_a?(ParseContext) ? options : ParseContext.new(options)
|
222
|
+
@warnings = parse_context.warnings
|
223
|
+
parse_context
|
153
224
|
end
|
154
225
|
|
226
|
+
def apply_options_to_context(context, options)
|
227
|
+
context.add_filters(options[:filters]) if options[:filters]
|
228
|
+
context.global_filter = options[:global_filter] if options[:global_filter]
|
229
|
+
context.exception_renderer = options[:exception_renderer] if options[:exception_renderer]
|
230
|
+
context.strict_variables = options[:strict_variables] if options[:strict_variables]
|
231
|
+
context.strict_filters = options[:strict_filters] if options[:strict_filters]
|
232
|
+
end
|
155
233
|
end
|
156
234
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Liquid
|
4
|
+
class Tokenizer
|
5
|
+
attr_reader :line_number, :for_liquid_tag
|
6
|
+
|
7
|
+
def initialize(source, line_numbers = false, line_number: nil, for_liquid_tag: false)
|
8
|
+
@source = source.to_s.to_str
|
9
|
+
@line_number = line_number || (line_numbers ? 1 : nil)
|
10
|
+
@for_liquid_tag = for_liquid_tag
|
11
|
+
@tokens = tokenize
|
12
|
+
end
|
13
|
+
|
14
|
+
def shift
|
15
|
+
(token = @tokens.shift) || return
|
16
|
+
|
17
|
+
if @line_number
|
18
|
+
@line_number += @for_liquid_tag ? 1 : token.count("\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
token
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def tokenize
|
27
|
+
return [] if @source.empty?
|
28
|
+
|
29
|
+
return @source.split("\n") if @for_liquid_tag
|
30
|
+
|
31
|
+
tokens = @source.split(TemplateParser)
|
32
|
+
|
33
|
+
# removes the rogue empty element at the beginning of the array
|
34
|
+
tokens.shift if tokens[0]&.empty?
|
35
|
+
|
36
|
+
tokens
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/liquid/usage.rb
ADDED
data/lib/liquid/utils.rb
CHANGED
@@ -1,14 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Liquid
|
2
4
|
module Utils
|
5
|
+
def self.slice_collection(collection, from, to)
|
6
|
+
if (from != 0 || !to.nil?) && collection.respond_to?(:load_slice)
|
7
|
+
collection.load_slice(from, to)
|
8
|
+
else
|
9
|
+
slice_collection_using_each(collection, from, to)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
3
13
|
def self.slice_collection_using_each(collection, from, to)
|
4
14
|
segments = []
|
5
|
-
index
|
15
|
+
index = 0
|
6
16
|
|
7
17
|
# Maintains Ruby 1.8.7 String#each behaviour on 1.9
|
8
|
-
|
18
|
+
if collection.is_a?(String)
|
19
|
+
return collection.empty? ? [] : [collection]
|
20
|
+
end
|
21
|
+
return [] unless collection.respond_to?(:each)
|
9
22
|
|
10
23
|
collection.each do |item|
|
11
|
-
|
12
24
|
if to && to <= index
|
13
25
|
break
|
14
26
|
end
|
@@ -23,8 +35,59 @@ module Liquid
|
|
23
35
|
segments
|
24
36
|
end
|
25
37
|
|
26
|
-
def self.
|
27
|
-
|
38
|
+
def self.to_integer(num)
|
39
|
+
return num if num.is_a?(Integer)
|
40
|
+
num = num.to_s
|
41
|
+
begin
|
42
|
+
Integer(num)
|
43
|
+
rescue ::ArgumentError
|
44
|
+
raise Liquid::ArgumentError, "invalid integer"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.to_number(obj)
|
49
|
+
case obj
|
50
|
+
when Float
|
51
|
+
BigDecimal(obj.to_s)
|
52
|
+
when Numeric
|
53
|
+
obj
|
54
|
+
when String
|
55
|
+
/\A-?\d+\.\d+\z/.match?(obj.strip) ? BigDecimal(obj) : obj.to_i
|
56
|
+
else
|
57
|
+
if obj.respond_to?(:to_number)
|
58
|
+
obj.to_number
|
59
|
+
else
|
60
|
+
0
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.to_date(obj)
|
66
|
+
return obj if obj.respond_to?(:strftime)
|
67
|
+
|
68
|
+
if obj.is_a?(String)
|
69
|
+
return nil if obj.empty?
|
70
|
+
obj = obj.downcase
|
71
|
+
end
|
72
|
+
|
73
|
+
case obj
|
74
|
+
when 'now', 'today'
|
75
|
+
Time.now
|
76
|
+
when /\A\d+\z/, Integer
|
77
|
+
Time.at(obj.to_i)
|
78
|
+
when String
|
79
|
+
Time.parse(obj)
|
80
|
+
end
|
81
|
+
rescue ::ArgumentError
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.to_liquid_value(obj)
|
86
|
+
# Enable "obj" to represent itself as a primitive value like integer, string, or boolean
|
87
|
+
return obj.to_liquid_value if obj.respond_to?(:to_liquid_value)
|
88
|
+
|
89
|
+
# Otherwise return the object itself
|
90
|
+
obj
|
28
91
|
end
|
29
92
|
end
|
30
93
|
end
|