liquid2 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +22 -2
- data/LICENSE_SHOPIFY.txt +8 -0
- data/README.md +420 -13
- data/lib/liquid2/context.rb +29 -18
- data/lib/liquid2/environment.rb +58 -6
- data/lib/liquid2/errors.rb +4 -2
- data/lib/liquid2/expressions/arguments.rb +20 -0
- data/lib/liquid2/expressions/arithmetic.rb +123 -0
- data/lib/liquid2/expressions/boolean.rb +2 -1
- data/lib/liquid2/expressions/filtered.rb +19 -25
- data/lib/liquid2/expressions/lambda.rb +2 -0
- data/lib/liquid2/expressions/loop.rb +7 -5
- data/lib/liquid2/expressions/path.rb +19 -2
- data/lib/liquid2/expressions/relational.rb +1 -1
- data/lib/liquid2/filter.rb +1 -2
- data/lib/liquid2/filters/array.rb +0 -1
- data/lib/liquid2/filters/sort.rb +5 -4
- data/lib/liquid2/loader.rb +1 -0
- data/lib/liquid2/nodes/tags/doc.rb +2 -0
- data/lib/liquid2/nodes/tags/extends.rb +270 -1
- data/lib/liquid2/nodes/tags/include.rb +7 -7
- data/lib/liquid2/nodes/tags/macro.rb +145 -1
- data/lib/liquid2/nodes/tags/raw.rb +2 -1
- data/lib/liquid2/nodes/tags/render.rb +8 -10
- data/lib/liquid2/nodes/tags/with.rb +42 -1
- data/lib/liquid2/parser.rb +170 -22
- data/lib/liquid2/scanner.rb +27 -44
- data/lib/liquid2/static_analysis.rb +1 -1
- data/lib/liquid2/template.rb +52 -5
- data/lib/liquid2/undefined.rb +32 -20
- data/lib/liquid2/version.rb +1 -1
- data/lib/liquid2.rb +2 -0
- data/sig/liquid2.rbs +331 -40
- data.tar.gz.sig +0 -0
- metadata +2 -2
- metadata.gz.sig +0 -0
- data/.vscode/settings.json +0 -32
data/lib/liquid2/environment.rb
CHANGED
@@ -21,16 +21,19 @@ require_relative "nodes/tags/cycle"
|
|
21
21
|
require_relative "nodes/tags/decrement"
|
22
22
|
require_relative "nodes/tags/doc"
|
23
23
|
require_relative "nodes/tags/echo"
|
24
|
+
require_relative "nodes/tags/extends"
|
24
25
|
require_relative "nodes/tags/for"
|
25
26
|
require_relative "nodes/tags/if"
|
26
27
|
require_relative "nodes/tags/include"
|
27
28
|
require_relative "nodes/tags/increment"
|
28
29
|
require_relative "nodes/tags/inline_comment"
|
29
30
|
require_relative "nodes/tags/liquid"
|
31
|
+
require_relative "nodes/tags/macro"
|
30
32
|
require_relative "nodes/tags/raw"
|
31
33
|
require_relative "nodes/tags/render"
|
32
34
|
require_relative "nodes/tags/tablerow"
|
33
35
|
require_relative "nodes/tags/unless"
|
36
|
+
require_relative "nodes/tags/with"
|
34
37
|
|
35
38
|
module Liquid2
|
36
39
|
# Template parsing and rendering configuration.
|
@@ -42,9 +45,30 @@ module Liquid2
|
|
42
45
|
class Environment
|
43
46
|
attr_reader :tags, :local_namespace_limit, :context_depth_limit, :loop_iteration_limit,
|
44
47
|
:output_stream_limit, :filters, :suppress_blank_control_flow_blocks,
|
45
|
-
:shorthand_indexes
|
48
|
+
:shorthand_indexes, :falsy_undefined, :arithmetic_operators
|
46
49
|
|
50
|
+
# @param context_depth_limit [Integer] The maximum number of times a render context can
|
51
|
+
# be extended or copied before a `Liquid2::LiquidResourceLimitError`` is raised.
|
52
|
+
# @param globals [Hash[String, untyped]?] Variables that are available to all templates
|
53
|
+
# rendered from this environment.
|
54
|
+
# @param loader [Liquid2::Loader] An instance of `Liquid2::Loader`. A template loader
|
55
|
+
# is responsible for finding and reading templates for `{% include %}` and
|
56
|
+
# `{% render %}` tags, or when calling `Liquid2::Environment.get_template(name)`.
|
57
|
+
# @param local_namespace_limit [Integer?] The maximum allowed "size" of the template
|
58
|
+
# local namespace (variables from `assign` and `capture` tags) before a
|
59
|
+
# `Liquid2::LiquidResourceLimitError`` is raised.
|
60
|
+
# @param loop_iteration_limit [Integer?] The maximum number of loop iterations allowed
|
61
|
+
# before a `LiquidResourceLimitError` is raised.
|
62
|
+
# @param output_stream_limit [Integer?] The maximum number of bytes that can be written
|
63
|
+
# to a template's output buffer before a `LiquidResourceLimitError` is raised.
|
64
|
+
# @param shorthand_indexes [bool] When `true`, allow shorthand dotted array indexes as
|
65
|
+
# well as bracketed indexes in variable paths. Defaults to `false`.
|
66
|
+
# @param suppress_blank_control_flow_blocks [bool] When `true`, suppress blank control
|
67
|
+
# flow block output, so as not to include unnecessary whitespace. Defaults to `true`.
|
68
|
+
# @param undefined [singleton(Liquid2::Undefined)] A singleton returning an instance of
|
69
|
+
# `Liquid2::Undefined`, which is used to represent template variables that don't exist.
|
47
70
|
def initialize(
|
71
|
+
arithmetic_operators: false,
|
48
72
|
context_depth_limit: 30,
|
49
73
|
globals: nil,
|
50
74
|
loader: nil,
|
@@ -53,7 +77,8 @@ module Liquid2
|
|
53
77
|
output_stream_limit: nil,
|
54
78
|
shorthand_indexes: false,
|
55
79
|
suppress_blank_control_flow_blocks: true,
|
56
|
-
undefined: Undefined
|
80
|
+
undefined: Undefined,
|
81
|
+
falsy_undefined: true
|
57
82
|
)
|
58
83
|
# A mapping of tag names to objects responding to `parse(token, parser)`.
|
59
84
|
@tags = {}
|
@@ -63,6 +88,10 @@ module Liquid2
|
|
63
88
|
# keyword argument.
|
64
89
|
@filters = {}
|
65
90
|
|
91
|
+
# When `true`, arithmetic operators `+`, `-`, `*`, `/`, `%` and `**` are enabled.
|
92
|
+
# Defaults to `false`.
|
93
|
+
@arithmetic_operators = arithmetic_operators
|
94
|
+
|
66
95
|
# The maximum number of times a render context can be extended or copied before
|
67
96
|
# a Liquid2::LiquidResourceLimitError is raised.
|
68
97
|
@context_depth_limit = context_depth_limit
|
@@ -99,10 +128,14 @@ module Liquid2
|
|
99
128
|
# unnecessary whitespace. Defaults to `true`.
|
100
129
|
@suppress_blank_control_flow_blocks = suppress_blank_control_flow_blocks
|
101
130
|
|
102
|
-
#
|
103
|
-
# don't exist.
|
131
|
+
# A singleton returning an instance of `Liquid2::Undefined`, which is used to
|
132
|
+
# represent template variables that don't exist.
|
104
133
|
@undefined = undefined
|
105
134
|
|
135
|
+
# When `true` (the default), undefined variables are considered falsy and do not
|
136
|
+
# raise an error when tested for truthiness.
|
137
|
+
@falsy_undefined = falsy_undefined
|
138
|
+
|
106
139
|
# Override `setup_tags_and_filters` in environment subclasses to configure custom
|
107
140
|
# tags and/or filters.
|
108
141
|
setup_tags_and_filters
|
@@ -118,8 +151,8 @@ module Liquid2
|
|
118
151
|
name: name, path: path, up_to_date: up_to_date,
|
119
152
|
globals: make_globals(globals), overlay: overlay)
|
120
153
|
rescue LiquidError => e
|
121
|
-
e.source = source
|
122
|
-
e.template_name = name unless name.empty?
|
154
|
+
e.source = source unless e.source
|
155
|
+
e.template_name = name unless e.template_name || name.empty?
|
123
156
|
raise
|
124
157
|
end
|
125
158
|
|
@@ -155,6 +188,20 @@ module Liquid2
|
|
155
188
|
@filters.delete(name)
|
156
189
|
end
|
157
190
|
|
191
|
+
# Add or replace a tag.
|
192
|
+
# @param name [String] The tag's name, as used by template authors.
|
193
|
+
# @param tag [responds to parse: ([Symbol, String?, Integer], Parser) -> Tag]
|
194
|
+
def register_tag(name, tag)
|
195
|
+
@tags[name] = tag
|
196
|
+
end
|
197
|
+
|
198
|
+
# Remove a tag from the tag register.
|
199
|
+
# @param name [String] The name of the tag.
|
200
|
+
# @return [_Tag | nil]
|
201
|
+
def delete_tag(name)
|
202
|
+
@tags.delete(name)
|
203
|
+
end
|
204
|
+
|
158
205
|
def setup_tags_and_filters
|
159
206
|
@tags["#"] = InlineComment
|
160
207
|
@tags["assign"] = AssignTag
|
@@ -167,15 +214,20 @@ module Liquid2
|
|
167
214
|
@tags["decrement"] = DecrementTag
|
168
215
|
@tags["doc"] = DocTag
|
169
216
|
@tags["echo"] = EchoTag
|
217
|
+
@tags["extends"] = ExtendsTag
|
218
|
+
@tags["block"] = BlockTag
|
170
219
|
@tags["for"] = ForTag
|
171
220
|
@tags["if"] = IfTag
|
172
221
|
@tags["include"] = IncludeTag
|
173
222
|
@tags["increment"] = IncrementTag
|
174
223
|
@tags["liquid"] = LiquidTag
|
224
|
+
@tags["macro"] = MacroTag
|
225
|
+
@tags["call"] = CallTag
|
175
226
|
@tags["raw"] = RawTag
|
176
227
|
@tags["render"] = RenderTag
|
177
228
|
@tags["tablerow"] = TableRowTag
|
178
229
|
@tags["unless"] = UnlessTag
|
230
|
+
@tags["with"] = WithTag
|
179
231
|
|
180
232
|
register_filter("abs", Liquid2::Filters.method(:abs))
|
181
233
|
register_filter("append", Liquid2::Filters.method(:append))
|
data/lib/liquid2/errors.rb
CHANGED
@@ -7,10 +7,10 @@ module Liquid2
|
|
7
7
|
|
8
8
|
FULL_MESSAGE = ((RUBY_VERSION.split(".")&.map(&:to_i) <=> [3, 2, 0]) || -1) < 1
|
9
9
|
|
10
|
-
def initialize(message, token = nil)
|
10
|
+
def initialize(message, token = nil, template_name: nil)
|
11
11
|
super(message)
|
12
12
|
@token = token
|
13
|
-
@template_name =
|
13
|
+
@template_name = template_name
|
14
14
|
@source = nil
|
15
15
|
end
|
16
16
|
|
@@ -76,4 +76,6 @@ module Liquid2
|
|
76
76
|
class LiquidResourceLimitError < LiquidError; end
|
77
77
|
class UndefinedError < LiquidError; end
|
78
78
|
class DisabledTagError < LiquidError; end
|
79
|
+
class TemplateInheritanceError < LiquidError; end
|
80
|
+
class RequiredBlockError < TemplateInheritanceError; end
|
79
81
|
end
|
@@ -22,4 +22,24 @@ module Liquid2
|
|
22
22
|
|
23
23
|
def children = [@value]
|
24
24
|
end
|
25
|
+
|
26
|
+
# A macro parameter with a name and optional default value.
|
27
|
+
class Parameter < Expression
|
28
|
+
attr_reader :value, :name, :sym
|
29
|
+
|
30
|
+
# @param name [String]
|
31
|
+
# @param value [Expression?]
|
32
|
+
def initialize(token, name, value)
|
33
|
+
super(token)
|
34
|
+
@name = name
|
35
|
+
@sym = name.to_sym
|
36
|
+
@value = value
|
37
|
+
end
|
38
|
+
|
39
|
+
def evaluate(context)
|
40
|
+
[@name, context.evaluate(@value)]
|
41
|
+
end
|
42
|
+
|
43
|
+
def children = [@value]
|
44
|
+
end
|
25
45
|
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "blank"
|
4
|
+
require_relative "../expression"
|
5
|
+
|
6
|
+
module Liquid2 # :nodoc:
|
7
|
+
# Base class for all arithmetic expressions.
|
8
|
+
class ArithmeticExpression < Expression
|
9
|
+
# @param left [Expression]
|
10
|
+
# @param right [Expression]
|
11
|
+
def initialize(token, left, right)
|
12
|
+
super(token)
|
13
|
+
@left = left
|
14
|
+
@right = right
|
15
|
+
end
|
16
|
+
|
17
|
+
def children = [@left, @right]
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def inner_evaluate(context)
|
22
|
+
left = context.evaluate(@left)
|
23
|
+
right = context.evaluate(@right)
|
24
|
+
left = left.to_liquid(context) if left.respond_to?(:to_liquid)
|
25
|
+
right = right.to_liquid(context) if right.respond_to?(:to_liquid)
|
26
|
+
[Liquid2::Filters.to_decimal(left), Liquid2::Filters.to_decimal(right)]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Infix addition
|
31
|
+
class Plus < ArithmeticExpression
|
32
|
+
def evaluate(context)
|
33
|
+
left, right = inner_evaluate(context)
|
34
|
+
left + right
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Infix subtraction
|
39
|
+
class Minus < ArithmeticExpression
|
40
|
+
def evaluate(context)
|
41
|
+
left, right = inner_evaluate(context)
|
42
|
+
left - right
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Infix multiplication
|
47
|
+
class Times < ArithmeticExpression
|
48
|
+
def evaluate(context)
|
49
|
+
left, right = inner_evaluate(context)
|
50
|
+
left * right
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Infix division
|
55
|
+
class Divide < ArithmeticExpression
|
56
|
+
def evaluate(context)
|
57
|
+
left, right = inner_evaluate(context)
|
58
|
+
left / right
|
59
|
+
rescue ZeroDivisionError => e
|
60
|
+
raise LiquidTypeError.new(e.message, nil)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Infix modulo
|
65
|
+
class Modulo < ArithmeticExpression
|
66
|
+
def evaluate(context)
|
67
|
+
left, right = inner_evaluate(context)
|
68
|
+
left % right
|
69
|
+
rescue ZeroDivisionError => e
|
70
|
+
raise LiquidTypeError.new(e.message, nil)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Infix exponentiation
|
75
|
+
class Pow < ArithmeticExpression
|
76
|
+
def evaluate(context)
|
77
|
+
left, right = inner_evaluate(context)
|
78
|
+
left**right
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Prefix negation
|
83
|
+
class Negative < Expression
|
84
|
+
# @param right [Expression]
|
85
|
+
def initialize(token, right)
|
86
|
+
super(token)
|
87
|
+
@right = right
|
88
|
+
end
|
89
|
+
|
90
|
+
def evaluate(context)
|
91
|
+
right = context.evaluate(@right)
|
92
|
+
value = Liquid2::Filters.to_decimal(right,
|
93
|
+
default: nil) || context.env.undefined(
|
94
|
+
"-(#{Liquid2.to_output_string(right)})",
|
95
|
+
node: self
|
96
|
+
)
|
97
|
+
value.send(:-@)
|
98
|
+
end
|
99
|
+
|
100
|
+
def children = [@right]
|
101
|
+
end
|
102
|
+
|
103
|
+
# Prefix positive
|
104
|
+
class Positive < Expression
|
105
|
+
# @param right [Expression]
|
106
|
+
def initialize(token, right)
|
107
|
+
super(token)
|
108
|
+
@right = right
|
109
|
+
end
|
110
|
+
|
111
|
+
def evaluate(context)
|
112
|
+
right = context.evaluate(@right)
|
113
|
+
value = Liquid2::Filters.to_decimal(right,
|
114
|
+
default: nil) || context.env.undefined(
|
115
|
+
"+(#{Liquid2.to_output_string(right)})",
|
116
|
+
node: self
|
117
|
+
)
|
118
|
+
value.send(:+@)
|
119
|
+
end
|
120
|
+
|
121
|
+
def children = [@right]
|
122
|
+
end
|
123
|
+
end
|
@@ -12,7 +12,8 @@ module Liquid2
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def evaluate(context)
|
15
|
-
|
15
|
+
value = context.evaluate(@expr)
|
16
|
+
Liquid2.truthy?(context, value.respond_to?(:to_liquid) ? value.to_liquid(context) : value)
|
16
17
|
end
|
17
18
|
|
18
19
|
def children = [@expr]
|
@@ -15,8 +15,10 @@ module Liquid2
|
|
15
15
|
|
16
16
|
def evaluate(context)
|
17
17
|
left = context.evaluate(@left)
|
18
|
+
return left if @filters.nil?
|
19
|
+
|
18
20
|
index = 0
|
19
|
-
while (filter = @filters[index])
|
21
|
+
while (filter = (@filters || raise)[index])
|
20
22
|
left = filter.evaluate(left, context)
|
21
23
|
index += 1
|
22
24
|
end
|
@@ -81,7 +83,7 @@ module Liquid2
|
|
81
83
|
attr_reader :name, :args
|
82
84
|
|
83
85
|
# @param name [String]
|
84
|
-
# @param args [Array[Expression]]
|
86
|
+
# @param args [Array[Expression]?]
|
85
87
|
def initialize(token, name, args)
|
86
88
|
super(token)
|
87
89
|
@name = name
|
@@ -92,36 +94,18 @@ module Liquid2
|
|
92
94
|
filter, with_context = context.env.filters[@name]
|
93
95
|
raise LiquidFilterNotFoundError.new("unknown filter #{@name.inspect}", @token) unless filter
|
94
96
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
if keyword_args.empty?
|
99
|
-
filter.call(left, *positional_args) # steep:ignore
|
100
|
-
else
|
101
|
-
filter.call(left, *positional_args, **keyword_args) # steep:ignore
|
102
|
-
end
|
103
|
-
rescue ArgumentError, TypeError => e
|
104
|
-
raise LiquidArgumentError.new(e.message, @token)
|
105
|
-
end
|
106
|
-
|
107
|
-
def children = @args
|
97
|
+
return filter.call(left) if @args.nil? && !with_context # steep:ignore
|
98
|
+
return filter.call(left, context: context) if @args.nil? && with_context # steep:ignore
|
108
99
|
|
109
|
-
private
|
110
|
-
|
111
|
-
# @param context [RenderContext]
|
112
|
-
# @return [positional arguments, keyword arguments] An array with two elements.
|
113
|
-
# The first is an array of evaluates positional arguments. The second is a hash
|
114
|
-
# of keyword names to evaluated keyword values.
|
115
|
-
def evaluate_args(context)
|
116
100
|
positional_args = [] # @type var positional_args: Array[untyped]
|
117
101
|
keyword_args = {} # @type var keyword_args: Hash[Symbol, untyped]
|
118
102
|
|
119
103
|
index = 0
|
120
104
|
loop do
|
121
105
|
# `@args[index]` could be `false` or `nil`
|
122
|
-
break if index >= @args.length
|
106
|
+
break if index >= @args.length # steep:ignore
|
123
107
|
|
124
|
-
arg = @args[index]
|
108
|
+
arg = @args[index] # steep:ignore
|
125
109
|
index += 1
|
126
110
|
if arg.respond_to?(:sym)
|
127
111
|
keyword_args[arg.sym] = context.evaluate(arg.value)
|
@@ -130,7 +114,17 @@ module Liquid2
|
|
130
114
|
end
|
131
115
|
end
|
132
116
|
|
133
|
-
[
|
117
|
+
keyword_args[:context] = context if with_context
|
118
|
+
|
119
|
+
if keyword_args.empty?
|
120
|
+
filter.call(left, *positional_args) # steep:ignore
|
121
|
+
else
|
122
|
+
filter.call(left, *positional_args, **keyword_args) # steep:ignore
|
123
|
+
end
|
124
|
+
rescue ArgumentError, TypeError => e
|
125
|
+
raise LiquidArgumentError.new(e.message, @token)
|
134
126
|
end
|
127
|
+
|
128
|
+
def children = @args || []
|
135
129
|
end
|
136
130
|
end
|
@@ -33,11 +33,13 @@ module Liquid2
|
|
33
33
|
elsif obj.is_a?(String)
|
34
34
|
# TODO: optionally enable/disable string iteration
|
35
35
|
obj.each_char.to_a
|
36
|
-
elsif obj.respond_to?(:
|
37
|
-
#
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
elsif obj.respond_to?(:slice)
|
37
|
+
# Special lazy drop slicing
|
38
|
+
return obj.slice(context.evaluate(@offset),
|
39
|
+
context.evaluate(@limit),
|
40
|
+
@reversed) || EMPTY_ENUM
|
41
|
+
elsif obj.is_a?(Enumerable) # rubocop:disable Lint/DuplicateBranch
|
42
|
+
obj.to_a
|
41
43
|
else
|
42
44
|
EMPTY_ENUM
|
43
45
|
end
|
@@ -8,6 +8,8 @@ module Liquid2
|
|
8
8
|
class Path < Expression
|
9
9
|
attr_reader :segments, :head
|
10
10
|
|
11
|
+
RE_PROPERTY = /\A[\u0080-\uFFFFa-zA-Z_][\u0080-\uFFFFa-zA-Z0-9_-]*\Z/
|
12
|
+
|
11
13
|
# @param segments [Array[String | Integer | Path]]
|
12
14
|
def initialize(token, segments)
|
13
15
|
super(token)
|
@@ -19,8 +21,9 @@ module Liquid2
|
|
19
21
|
context.fetch(@head, @segments, node: self)
|
20
22
|
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
+
def to_s
|
25
|
+
segment_to_s(@head, head: true) + @segments.map { |segment| segment_to_s(segment) }.join
|
26
|
+
end
|
24
27
|
|
25
28
|
def children
|
26
29
|
if @head.is_a?(Path)
|
@@ -29,5 +32,19 @@ module Liquid2
|
|
29
32
|
@segments.filter { |segment| segment.is_a?(Path) }
|
30
33
|
end
|
31
34
|
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def segment_to_s(segment, head: false)
|
39
|
+
if segment.is_a?(String)
|
40
|
+
if segment.match?(RE_PROPERTY)
|
41
|
+
"#{head ? "" : "."}#{segment}"
|
42
|
+
else
|
43
|
+
"[#{segment.inspect}]"
|
44
|
+
end
|
45
|
+
else
|
46
|
+
"[#{segment}]"
|
47
|
+
end
|
48
|
+
end
|
32
49
|
end
|
33
50
|
end
|
@@ -4,7 +4,7 @@ require_relative "blank"
|
|
4
4
|
require_relative "../expression"
|
5
5
|
|
6
6
|
module Liquid2 # :nodoc:
|
7
|
-
# Base for comparison expressions.
|
7
|
+
# Base class for all comparison expressions.
|
8
8
|
class ComparisonExpression < Expression
|
9
9
|
# @param left [Expression]
|
10
10
|
# @param right [Expression]
|
data/lib/liquid2/filter.rb
CHANGED
@@ -63,8 +63,7 @@ module Liquid2
|
|
63
63
|
end
|
64
64
|
|
65
65
|
# Cast _obj_ to a date and time. Return `nil` if casting fails.
|
66
|
-
#
|
67
|
-
# TODO: This was copied from Shopify/liquid. Include their license and copyright.
|
66
|
+
# NOTE: This was copied from Shopify/liquid.
|
68
67
|
def self.to_date(obj)
|
69
68
|
return obj if obj.respond_to?(:strftime)
|
70
69
|
|
data/lib/liquid2/filters/sort.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
module Liquid2
|
4
4
|
# Liquid filters and helper methods.
|
5
5
|
module Filters
|
6
|
+
INFINITY_ARRAY = [Float::INFINITY].freeze # : [Float]
|
7
|
+
|
6
8
|
def self.sort(left, key = nil, context:)
|
7
9
|
left = Liquid2::Filters.to_enumerable(left)
|
8
10
|
|
@@ -82,12 +84,11 @@ module Liquid2
|
|
82
84
|
end
|
83
85
|
|
84
86
|
def self.ints(obj)
|
85
|
-
|
86
|
-
when Integer, Float, BigDecimal
|
87
|
+
if obj.is_a?(Integer) || obj.is_a?(Float) || obj.is_a?(BigDecimal)
|
87
88
|
[obj]
|
88
89
|
else
|
89
|
-
numeric = obj.to_s.scan(
|
90
|
-
return
|
90
|
+
numeric = obj.to_s.scan(/(?<=\.)0+|-?\d+/)
|
91
|
+
return INFINITY_ARRAY if numeric.empty?
|
91
92
|
|
92
93
|
numeric.map(&:to_i)
|
93
94
|
end
|
data/lib/liquid2/loader.rb
CHANGED
@@ -31,6 +31,7 @@ module Liquid2
|
|
31
31
|
def load(env, name, globals: nil, context: nil, **kwargs)
|
32
32
|
data = get_source(env, name, context: context, **kwargs)
|
33
33
|
path = Pathname.new(data.name)
|
34
|
+
# FIXME: name and path
|
34
35
|
env.parse(data.source,
|
35
36
|
name: path.basename.to_s,
|
36
37
|
path: data.name,
|