liquid 4.0.1 → 4.0.2
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
- data/History.md +48 -0
- data/lib/liquid.rb +1 -0
- data/lib/liquid/condition.rb +11 -2
- data/lib/liquid/expression.rb +1 -1
- data/lib/liquid/i18n.rb +1 -1
- data/lib/liquid/lexer.rb +1 -1
- data/lib/liquid/parse_tree_visitor.rb +42 -0
- data/lib/liquid/standardfilters.rb +85 -35
- data/lib/liquid/tags/assign.rb +8 -0
- data/lib/liquid/tags/case.rb +8 -0
- data/lib/liquid/tags/cycle.rb +8 -0
- data/lib/liquid/tags/for.rb +7 -2
- data/lib/liquid/tags/if.rb +13 -5
- data/lib/liquid/tags/include.rb +11 -0
- data/lib/liquid/tags/table_row.rb +8 -0
- data/lib/liquid/truffle.rb +5 -0
- data/lib/liquid/variable.rb +6 -0
- data/lib/liquid/variable_lookup.rb +7 -1
- data/lib/liquid/version.rb +2 -1
- data/test/integration/error_handling_test.rb +3 -3
- data/test/integration/parse_tree_visitor_test.rb +247 -0
- data/test/integration/parsing_quirks_test.rb +1 -1
- data/test/integration/standard_filter_test.rb +153 -3
- data/test/test_helper.rb +0 -0
- data/test/truffle/truffle_test.rb +9 -0
- data/test/unit/condition_unit_test.rb +2 -2
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e3124f91e43cab43cf6782b093c0387d9189bd951b911ab1ade84024e5b84bf3
|
4
|
+
data.tar.gz: 40c04d46b3a1a51a775832cabf161fc870bde43b72d2857a8a8cf736e1909a43
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71deb80c6d970684e424fb8e4ca0a817399dc0b6564a7308093158a94ace0e24cac5d8e08a8b015327937b8dd45be25532dd8d9e02de0c3677f08297a08638dd
|
7
|
+
data.tar.gz: 79490a2f0db69914e01c69fdcf135cc3541609cfca29017154d3c33325c57f682c3d90bbfa0bca1a7f3d82e4cbe4af5259a77cf42861c142921491e21949bddf
|
data/History.md
CHANGED
@@ -1,5 +1,53 @@
|
|
1
1
|
# Liquid Change Log
|
2
2
|
|
3
|
+
## 4.0.2 / 2019-03-08
|
4
|
+
|
5
|
+
### Changed
|
6
|
+
* Add `where` filter (#1026) [Samuel Doiron]
|
7
|
+
* Add `ParseTreeVisitor` to iterate the Liquid AST (#1025) [Stephen Paul Weber]
|
8
|
+
* Improve `strip_html` performance (#1032) [printercu]
|
9
|
+
|
10
|
+
### Fixed
|
11
|
+
* Add error checking for invalid combinations of inputs to sort, sort_natural, where, uniq, map, compact filters (#1059) [Garland Zhang]
|
12
|
+
* Validate the character encoding in url_decode (#1070) [Clayton Smith]
|
13
|
+
|
14
|
+
## 4.0.1 / 2018-10-09
|
15
|
+
|
16
|
+
### Changed
|
17
|
+
* Add benchmark group in Gemfile (#855) [Jerry Liu]
|
18
|
+
* Allow benchmarks to benchmark render by itself (#851) [Jerry Liu]
|
19
|
+
* Avoid calling `line_number` on String node when rescuing a render error. (#860) [Dylan Thacker-Smith]
|
20
|
+
* Avoid duck typing to detect whether to call render on a node. [Dylan Thacker-Smith]
|
21
|
+
* Clarify spelling of `reversed` on `for` block tag (#843) [Mark Crossfield]
|
22
|
+
* Replace recursion with loop to avoid potential stack overflow from malicious input (#891, #892) [Dylan Thacker-Smith]
|
23
|
+
* Limit block tag nesting to 100 (#894) [Dylan Thacker-Smith]
|
24
|
+
* Replace `assert_equal nil` with `assert_nil` (#895) [Dylan Thacker-Smith]
|
25
|
+
* Remove Spy Gem (#896) [Dylan Thacker-Smith]
|
26
|
+
* Add `collection_name` and `variable_name` reader to `For` block (#909)
|
27
|
+
* Symbols render as strings (#920) [Justin Li]
|
28
|
+
* Remove default value from Hash objects (#932) [Maxime Bedard]
|
29
|
+
* Remove one level of nesting (#944) [Dylan Thacker-Smith]
|
30
|
+
* Update Rubocop version (#952) [Justin Li]
|
31
|
+
* Add `at_least` and `at_most` filters (#954, #958) [Nithin Bekal]
|
32
|
+
* Add a regression test for a liquid-c trim mode bug (#972) [Dylan Thacker-Smith]
|
33
|
+
* Use https rather than git protocol to fetch liquid-c [Dylan Thacker-Smith]
|
34
|
+
* Add tests against Ruby 2.4 (#963) and 2.5 (#981)
|
35
|
+
* Replace RegExp literals with constants (#988) [Ashwin Maroli]
|
36
|
+
* Replace unnecessary `#each_with_index` with `#each` (#992) [Ashwin Maroli]
|
37
|
+
* Improve the unexpected end delimiter message for block tags. (#1003) [Dylan Thacker-Smith]
|
38
|
+
* Refactor and optimize rendering (#1005) [Christopher Aue]
|
39
|
+
* Add installation instruction (#1006) [Ben Gift]
|
40
|
+
* Remove Circle CI (#1010)
|
41
|
+
* Rename deprecated `BigDecimal.new` to `BigDecimal` (#1024) [Koichi ITO]
|
42
|
+
* Rename deprecated Rubocop name (#1027) [Justin Li]
|
43
|
+
|
44
|
+
### Fixed
|
45
|
+
* Handle `join` filter on non String joiners (#857) [Richard Monette]
|
46
|
+
* Fix duplicate inclusion condition logic error of `Liquid::Strainer.add_filter` method (#861)
|
47
|
+
* Fix `escape`, `url_encode`, `url_decode` not handling non-string values (#898) [Thierry Joyal]
|
48
|
+
* Fix raise when variable is defined but nil when using `strict_variables` [Pascal Betz]
|
49
|
+
* Fix `sort` and `sort_natural` to handle arrays with nils (#930) [Eric Chan]
|
50
|
+
|
3
51
|
## 4.0.0 / 2016-12-14 / branch "4-0-stable"
|
4
52
|
|
5
53
|
### Changed
|
data/lib/liquid.rb
CHANGED
data/lib/liquid/condition.rb
CHANGED
@@ -29,7 +29,7 @@ module Liquid
|
|
29
29
|
@@operators
|
30
30
|
end
|
31
31
|
|
32
|
-
attr_reader :attachment
|
32
|
+
attr_reader :attachment, :child_condition
|
33
33
|
attr_accessor :left, :operator, :right
|
34
34
|
|
35
35
|
def initialize(left = nil, operator = nil, right = nil)
|
@@ -83,7 +83,7 @@ module Liquid
|
|
83
83
|
|
84
84
|
protected
|
85
85
|
|
86
|
-
attr_reader :child_relation
|
86
|
+
attr_reader :child_relation
|
87
87
|
|
88
88
|
private
|
89
89
|
|
@@ -128,6 +128,15 @@ module Liquid
|
|
128
128
|
end
|
129
129
|
end
|
130
130
|
end
|
131
|
+
|
132
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
133
|
+
def children
|
134
|
+
[
|
135
|
+
@node.left, @node.right,
|
136
|
+
@node.child_condition, @node.attachment
|
137
|
+
].compact
|
138
|
+
end
|
139
|
+
end
|
131
140
|
end
|
132
141
|
|
133
142
|
class ElseCondition < Condition
|
data/lib/liquid/expression.rb
CHANGED
@@ -19,7 +19,7 @@ module Liquid
|
|
19
19
|
'false'.freeze => false,
|
20
20
|
'blank'.freeze => MethodLiteral.new(:blank?, '').freeze,
|
21
21
|
'empty'.freeze => MethodLiteral.new(:empty?, '').freeze
|
22
|
-
}
|
22
|
+
}.freeze
|
23
23
|
|
24
24
|
SINGLE_QUOTED_STRING = /\A'(.*)'\z/m
|
25
25
|
DOUBLE_QUOTED_STRING = /\A"(.*)"\z/m
|
data/lib/liquid/i18n.rb
CHANGED
data/lib/liquid/lexer.rb
CHANGED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Liquid
|
4
|
+
class ParseTreeVisitor
|
5
|
+
def self.for(node, callbacks = Hash.new(proc {}))
|
6
|
+
if defined?(node.class::ParseTreeVisitor)
|
7
|
+
node.class::ParseTreeVisitor
|
8
|
+
else
|
9
|
+
self
|
10
|
+
end.new(node, callbacks)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(node, callbacks)
|
14
|
+
@node = node
|
15
|
+
@callbacks = callbacks
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_callback_for(*classes, &block)
|
19
|
+
callback = block
|
20
|
+
callback = ->(node, _) { yield node } if block.arity.abs == 1
|
21
|
+
callback = ->(_, _) { yield } if block.arity.zero?
|
22
|
+
classes.each { |klass| @callbacks[klass] = callback }
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def visit(context = nil)
|
27
|
+
children.map do |node|
|
28
|
+
item, new_context = @callbacks[node.class].call(node, context)
|
29
|
+
[
|
30
|
+
item,
|
31
|
+
ParseTreeVisitor.for(node, @callbacks).visit(new_context || context)
|
32
|
+
]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def children
|
39
|
+
@node.respond_to?(:nodelist) ? Array(@node.nodelist) : []
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -9,8 +9,14 @@ module Liquid
|
|
9
9
|
'<'.freeze => '<'.freeze,
|
10
10
|
'"'.freeze => '"'.freeze,
|
11
11
|
"'".freeze => '''.freeze
|
12
|
-
}
|
12
|
+
}.freeze
|
13
13
|
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
|
14
|
+
STRIP_HTML_BLOCKS = Regexp.union(
|
15
|
+
/<script.*?<\/script>/m,
|
16
|
+
/<!--.*?-->/m,
|
17
|
+
/<style.*?<\/style>/m
|
18
|
+
)
|
19
|
+
STRIP_HTML_TAGS = /<.*?>/m
|
14
20
|
|
15
21
|
# Return the size of an array or of an string
|
16
22
|
def size(input)
|
@@ -46,7 +52,12 @@ module Liquid
|
|
46
52
|
end
|
47
53
|
|
48
54
|
def url_decode(input)
|
49
|
-
|
55
|
+
return if input.nil?
|
56
|
+
|
57
|
+
result = CGI.unescape(input.to_s)
|
58
|
+
raise Liquid::ArgumentError, "invalid byte sequence in #{result.encoding}" unless result.valid_encoding?
|
59
|
+
|
60
|
+
result
|
50
61
|
end
|
51
62
|
|
52
63
|
def slice(input, offset, length = nil)
|
@@ -103,7 +114,9 @@ module Liquid
|
|
103
114
|
|
104
115
|
def strip_html(input)
|
105
116
|
empty = ''.freeze
|
106
|
-
input.to_s.gsub(
|
117
|
+
result = input.to_s.gsub(STRIP_HTML_BLOCKS, empty)
|
118
|
+
result.gsub!(STRIP_HTML_TAGS, empty)
|
119
|
+
result
|
107
120
|
end
|
108
121
|
|
109
122
|
# Remove all newlines from the string
|
@@ -120,25 +133,18 @@ module Liquid
|
|
120
133
|
# provide optional property with which to sort an array of hashes or drops
|
121
134
|
def sort(input, property = nil)
|
122
135
|
ary = InputIterator.new(input)
|
136
|
+
|
137
|
+
return [] if ary.empty?
|
138
|
+
|
123
139
|
if property.nil?
|
124
140
|
ary.sort do |a, b|
|
125
|
-
|
126
|
-
a <=> b
|
127
|
-
else
|
128
|
-
a.nil? ? 1 : -1
|
129
|
-
end
|
141
|
+
nil_safe_compare(a, b)
|
130
142
|
end
|
131
|
-
elsif ary.empty? # The next two cases assume a non-empty array.
|
132
|
-
[]
|
133
143
|
elsif ary.all? { |el| el.respond_to?(:[]) }
|
134
|
-
|
135
|
-
a
|
136
|
-
|
137
|
-
|
138
|
-
a <=> b
|
139
|
-
else
|
140
|
-
a.nil? ? 1 : -1
|
141
|
-
end
|
144
|
+
begin
|
145
|
+
ary.sort { |a, b| nil_safe_compare(a[property], b[property]) }
|
146
|
+
rescue TypeError
|
147
|
+
raise_property_error(property)
|
142
148
|
end
|
143
149
|
end
|
144
150
|
end
|
@@ -148,25 +154,39 @@ module Liquid
|
|
148
154
|
def sort_natural(input, property = nil)
|
149
155
|
ary = InputIterator.new(input)
|
150
156
|
|
157
|
+
return [] if ary.empty?
|
158
|
+
|
151
159
|
if property.nil?
|
152
160
|
ary.sort do |a, b|
|
153
|
-
|
154
|
-
a.to_s.casecmp(b.to_s)
|
155
|
-
else
|
156
|
-
a.nil? ? 1 : -1
|
157
|
-
end
|
161
|
+
nil_safe_casecmp(a, b)
|
158
162
|
end
|
159
|
-
elsif ary.empty? # The next two cases assume a non-empty array.
|
160
|
-
[]
|
161
163
|
elsif ary.all? { |el| el.respond_to?(:[]) }
|
162
|
-
|
163
|
-
a
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
164
|
+
begin
|
165
|
+
ary.sort { |a, b| nil_safe_casecmp(a[property], b[property]) }
|
166
|
+
rescue TypeError
|
167
|
+
raise_property_error(property)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Filter the elements of an array to those with a certain property value.
|
173
|
+
# By default the target is any truthy value.
|
174
|
+
def where(input, property, target_value = nil)
|
175
|
+
ary = InputIterator.new(input)
|
176
|
+
|
177
|
+
if ary.empty?
|
178
|
+
[]
|
179
|
+
elsif ary.first.respond_to?(:[]) && target_value.nil?
|
180
|
+
begin
|
181
|
+
ary.select { |item| item[property] }
|
182
|
+
rescue TypeError
|
183
|
+
raise_property_error(property)
|
184
|
+
end
|
185
|
+
elsif ary.first.respond_to?(:[])
|
186
|
+
begin
|
187
|
+
ary.select { |item| item[property] == target_value }
|
188
|
+
rescue TypeError
|
189
|
+
raise_property_error(property)
|
170
190
|
end
|
171
191
|
end
|
172
192
|
end
|
@@ -181,7 +201,11 @@ module Liquid
|
|
181
201
|
elsif ary.empty? # The next two cases assume a non-empty array.
|
182
202
|
[]
|
183
203
|
elsif ary.first.respond_to?(:[])
|
184
|
-
|
204
|
+
begin
|
205
|
+
ary.uniq { |a| a[property] }
|
206
|
+
rescue TypeError
|
207
|
+
raise_property_error(property)
|
208
|
+
end
|
185
209
|
end
|
186
210
|
end
|
187
211
|
|
@@ -203,6 +227,8 @@ module Liquid
|
|
203
227
|
r.is_a?(Proc) ? r.call : r
|
204
228
|
end
|
205
229
|
end
|
230
|
+
rescue TypeError
|
231
|
+
raise_property_error(property)
|
206
232
|
end
|
207
233
|
|
208
234
|
# Remove nils within an array
|
@@ -215,7 +241,11 @@ module Liquid
|
|
215
241
|
elsif ary.empty? # The next two cases assume a non-empty array.
|
216
242
|
[]
|
217
243
|
elsif ary.first.respond_to?(:[])
|
218
|
-
|
244
|
+
begin
|
245
|
+
ary.reject { |a| a[property].nil? }
|
246
|
+
rescue TypeError
|
247
|
+
raise_property_error(property)
|
248
|
+
end
|
219
249
|
end
|
220
250
|
end
|
221
251
|
|
@@ -399,11 +429,31 @@ module Liquid
|
|
399
429
|
|
400
430
|
private
|
401
431
|
|
432
|
+
def raise_property_error(property)
|
433
|
+
raise Liquid::ArgumentError.new("cannot select the property '#{property}'")
|
434
|
+
end
|
435
|
+
|
402
436
|
def apply_operation(input, operand, operation)
|
403
437
|
result = Utils.to_number(input).send(operation, Utils.to_number(operand))
|
404
438
|
result.is_a?(BigDecimal) ? result.to_f : result
|
405
439
|
end
|
406
440
|
|
441
|
+
def nil_safe_compare(a, b)
|
442
|
+
if !a.nil? && !b.nil?
|
443
|
+
a <=> b
|
444
|
+
else
|
445
|
+
a.nil? ? 1 : -1
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
def nil_safe_casecmp(a, b)
|
450
|
+
if !a.nil? && !b.nil?
|
451
|
+
a.to_s.casecmp(b.to_s)
|
452
|
+
else
|
453
|
+
a.nil? ? 1 : -1
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
407
457
|
class InputIterator
|
408
458
|
include Enumerable
|
409
459
|
|
data/lib/liquid/tags/assign.rb
CHANGED
@@ -10,6 +10,8 @@ module Liquid
|
|
10
10
|
class Assign < Tag
|
11
11
|
Syntax = /(#{VariableSignature}+)\s*=\s*(.*)\s*/om
|
12
12
|
|
13
|
+
attr_reader :to, :from
|
14
|
+
|
13
15
|
def initialize(tag_name, markup, options)
|
14
16
|
super
|
15
17
|
if markup =~ Syntax
|
@@ -45,6 +47,12 @@ module Liquid
|
|
45
47
|
1
|
46
48
|
end
|
47
49
|
end
|
50
|
+
|
51
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
52
|
+
def children
|
53
|
+
[@node.from]
|
54
|
+
end
|
55
|
+
end
|
48
56
|
end
|
49
57
|
|
50
58
|
Template.register_tag('assign'.freeze, Assign)
|
data/lib/liquid/tags/case.rb
CHANGED
@@ -3,6 +3,8 @@ module Liquid
|
|
3
3
|
Syntax = /(#{QuotedFragment})/o
|
4
4
|
WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/om
|
5
5
|
|
6
|
+
attr_reader :blocks, :left
|
7
|
+
|
6
8
|
def initialize(tag_name, markup, options)
|
7
9
|
super
|
8
10
|
@blocks = []
|
@@ -80,6 +82,12 @@ module Liquid
|
|
80
82
|
block.attach(BlockBody.new)
|
81
83
|
@blocks << block
|
82
84
|
end
|
85
|
+
|
86
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
87
|
+
def children
|
88
|
+
[@node.left] + @node.blocks
|
89
|
+
end
|
90
|
+
end
|
83
91
|
end
|
84
92
|
|
85
93
|
Template.register_tag('case'.freeze, Case)
|
data/lib/liquid/tags/cycle.rb
CHANGED
@@ -15,6 +15,8 @@ module Liquid
|
|
15
15
|
SimpleSyntax = /\A#{QuotedFragment}+/o
|
16
16
|
NamedSyntax = /\A(#{QuotedFragment})\s*\:\s*(.*)/om
|
17
17
|
|
18
|
+
attr_reader :variables
|
19
|
+
|
18
20
|
def initialize(tag_name, markup, options)
|
19
21
|
super
|
20
22
|
case markup
|
@@ -51,6 +53,12 @@ module Liquid
|
|
51
53
|
$1 ? Expression.parse($1) : nil
|
52
54
|
end.compact
|
53
55
|
end
|
56
|
+
|
57
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
58
|
+
def children
|
59
|
+
Array(@node.variables)
|
60
|
+
end
|
61
|
+
end
|
54
62
|
end
|
55
63
|
|
56
64
|
Template.register_tag('cycle', Cycle)
|
data/lib/liquid/tags/for.rb
CHANGED
@@ -46,8 +46,7 @@ module Liquid
|
|
46
46
|
class For < Block
|
47
47
|
Syntax = /\A(#{VariableSegment}+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
|
48
48
|
|
49
|
-
attr_reader :collection_name
|
50
|
-
attr_reader :variable_name
|
49
|
+
attr_reader :collection_name, :variable_name, :limit, :from
|
51
50
|
|
52
51
|
def initialize(tag_name, markup, options)
|
53
52
|
super
|
@@ -192,6 +191,12 @@ module Liquid
|
|
192
191
|
def render_else(context)
|
193
192
|
@else_block ? @else_block.render(context) : ''.freeze
|
194
193
|
end
|
194
|
+
|
195
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
196
|
+
def children
|
197
|
+
(super + [@node.limit, @node.from, @node.collection_name]).compact
|
198
|
+
end
|
199
|
+
end
|
195
200
|
end
|
196
201
|
|
197
202
|
Template.register_tag('for'.freeze, For)
|
data/lib/liquid/tags/if.rb
CHANGED
@@ -12,7 +12,9 @@ module Liquid
|
|
12
12
|
class If < Block
|
13
13
|
Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o
|
14
14
|
ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o
|
15
|
-
BOOLEAN_OPERATORS = %w(and or)
|
15
|
+
BOOLEAN_OPERATORS = %w(and or).freeze
|
16
|
+
|
17
|
+
attr_reader :blocks
|
16
18
|
|
17
19
|
def initialize(tag_name, markup, options)
|
18
20
|
super
|
@@ -20,15 +22,15 @@ module Liquid
|
|
20
22
|
push_block('if'.freeze, markup)
|
21
23
|
end
|
22
24
|
|
25
|
+
def nodelist
|
26
|
+
@blocks.map(&:attachment)
|
27
|
+
end
|
28
|
+
|
23
29
|
def parse(tokens)
|
24
30
|
while parse_body(@blocks.last.attachment, tokens)
|
25
31
|
end
|
26
32
|
end
|
27
33
|
|
28
|
-
def nodelist
|
29
|
-
@blocks.map(&:attachment)
|
30
|
-
end
|
31
|
-
|
32
34
|
def unknown_tag(tag, markup, tokens)
|
33
35
|
if ['elsif'.freeze, 'else'.freeze].include?(tag)
|
34
36
|
push_block(tag, markup)
|
@@ -108,6 +110,12 @@ module Liquid
|
|
108
110
|
Condition.new(a)
|
109
111
|
end
|
110
112
|
end
|
113
|
+
|
114
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
115
|
+
def children
|
116
|
+
@node.blocks
|
117
|
+
end
|
118
|
+
end
|
111
119
|
end
|
112
120
|
|
113
121
|
Template.register_tag('if'.freeze, If)
|
data/lib/liquid/tags/include.rb
CHANGED
@@ -16,6 +16,8 @@ module Liquid
|
|
16
16
|
class Include < Tag
|
17
17
|
Syntax = /(#{QuotedFragment}+)(\s+(?:with|for)\s+(#{QuotedFragment}+))?/o
|
18
18
|
|
19
|
+
attr_reader :template_name_expr, :variable_name_expr, :attributes
|
20
|
+
|
19
21
|
def initialize(tag_name, markup, options)
|
20
22
|
super
|
21
23
|
|
@@ -107,6 +109,15 @@ module Liquid
|
|
107
109
|
|
108
110
|
file_system.read_template_file(context.evaluate(@template_name_expr))
|
109
111
|
end
|
112
|
+
|
113
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
114
|
+
def children
|
115
|
+
[
|
116
|
+
@node.template_name_expr,
|
117
|
+
@node.variable_name_expr
|
118
|
+
] + @node.attributes.values
|
119
|
+
end
|
120
|
+
end
|
110
121
|
end
|
111
122
|
|
112
123
|
Template.register_tag('include'.freeze, Include)
|
@@ -2,6 +2,8 @@ module Liquid
|
|
2
2
|
class TableRow < Block
|
3
3
|
Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)/o
|
4
4
|
|
5
|
+
attr_reader :variable_name, :collection_name, :attributes
|
6
|
+
|
5
7
|
def initialize(tag_name, markup, options)
|
6
8
|
super
|
7
9
|
if markup =~ Syntax
|
@@ -48,6 +50,12 @@ module Liquid
|
|
48
50
|
result << "</tr>\n"
|
49
51
|
result
|
50
52
|
end
|
53
|
+
|
54
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
55
|
+
def children
|
56
|
+
super + @node.attributes.values + [@node.collection_name]
|
57
|
+
end
|
58
|
+
end
|
51
59
|
end
|
52
60
|
|
53
61
|
Template.register_tag('tablerow'.freeze, TableRow)
|
data/lib/liquid/variable.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Liquid
|
2
2
|
class VariableLookup
|
3
3
|
SQUARE_BRACKETED = /\A\[(.*)\]\z/m
|
4
|
-
COMMAND_METHODS = ['size'.freeze, 'first'.freeze, 'last'.freeze]
|
4
|
+
COMMAND_METHODS = ['size'.freeze, 'first'.freeze, 'last'.freeze].freeze
|
5
5
|
|
6
6
|
attr_reader :name, :lookups
|
7
7
|
|
@@ -78,5 +78,11 @@ module Liquid
|
|
78
78
|
def state
|
79
79
|
[@name, @lookups, @command_flags]
|
80
80
|
end
|
81
|
+
|
82
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
83
|
+
def children
|
84
|
+
@node.lookups
|
85
|
+
end
|
86
|
+
end
|
81
87
|
end
|
82
88
|
end
|
data/lib/liquid/version.rb
CHANGED
@@ -123,7 +123,7 @@ class ErrorHandlingTest < Minitest::Test
|
|
123
123
|
',
|
124
124
|
error_mode: :warn,
|
125
125
|
line_numbers: true
|
126
|
-
|
126
|
+
)
|
127
127
|
|
128
128
|
assert_equal ['Liquid syntax error (line 4): Unexpected character = in "1 =! 2"'],
|
129
129
|
template.warnings.map(&:message)
|
@@ -140,7 +140,7 @@ class ErrorHandlingTest < Minitest::Test
|
|
140
140
|
',
|
141
141
|
error_mode: :strict,
|
142
142
|
line_numbers: true
|
143
|
-
|
143
|
+
)
|
144
144
|
end
|
145
145
|
|
146
146
|
assert_equal 'Liquid syntax error (line 4): Unexpected character = in "1 =! 2"', err.message
|
@@ -158,7 +158,7 @@ class ErrorHandlingTest < Minitest::Test
|
|
158
158
|
bla
|
159
159
|
',
|
160
160
|
line_numbers: true
|
161
|
-
|
161
|
+
)
|
162
162
|
end
|
163
163
|
|
164
164
|
assert_equal "Liquid syntax error (line 5): Unknown tag 'foo'", err.message
|
@@ -0,0 +1,247 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class ParseTreeVisitorTest < Minitest::Test
|
6
|
+
include Liquid
|
7
|
+
|
8
|
+
def test_variable
|
9
|
+
assert_equal(
|
10
|
+
["test"],
|
11
|
+
visit(%({{ test }}))
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_varible_with_filter
|
16
|
+
assert_equal(
|
17
|
+
["test", "infilter"],
|
18
|
+
visit(%({{ test | split: infilter }}))
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_dynamic_variable
|
23
|
+
assert_equal(
|
24
|
+
["test", "inlookup"],
|
25
|
+
visit(%({{ test[inlookup] }}))
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_if_condition
|
30
|
+
assert_equal(
|
31
|
+
["test"],
|
32
|
+
visit(%({% if test %}{% endif %}))
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_complex_if_condition
|
37
|
+
assert_equal(
|
38
|
+
["test"],
|
39
|
+
visit(%({% if 1 == 1 and 2 == test %}{% endif %}))
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_if_body
|
44
|
+
assert_equal(
|
45
|
+
["test"],
|
46
|
+
visit(%({% if 1 == 1 %}{{ test }}{% endif %}))
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_unless_condition
|
51
|
+
assert_equal(
|
52
|
+
["test"],
|
53
|
+
visit(%({% unless test %}{% endunless %}))
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_complex_unless_condition
|
58
|
+
assert_equal(
|
59
|
+
["test"],
|
60
|
+
visit(%({% unless 1 == 1 and 2 == test %}{% endunless %}))
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_unless_body
|
65
|
+
assert_equal(
|
66
|
+
["test"],
|
67
|
+
visit(%({% unless 1 == 1 %}{{ test }}{% endunless %}))
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_elsif_condition
|
72
|
+
assert_equal(
|
73
|
+
["test"],
|
74
|
+
visit(%({% if 1 == 1 %}{% elsif test %}{% endif %}))
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_complex_elsif_condition
|
79
|
+
assert_equal(
|
80
|
+
["test"],
|
81
|
+
visit(%({% if 1 == 1 %}{% elsif 1 == 1 and 2 == test %}{% endif %}))
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_elsif_body
|
86
|
+
assert_equal(
|
87
|
+
["test"],
|
88
|
+
visit(%({% if 1 == 1 %}{% elsif 2 == 2 %}{{ test }}{% endif %}))
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_else_body
|
93
|
+
assert_equal(
|
94
|
+
["test"],
|
95
|
+
visit(%({% if 1 == 1 %}{% else %}{{ test }}{% endif %}))
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_case_left
|
100
|
+
assert_equal(
|
101
|
+
["test"],
|
102
|
+
visit(%({% case test %}{% endcase %}))
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_case_condition
|
107
|
+
assert_equal(
|
108
|
+
["test"],
|
109
|
+
visit(%({% case 1 %}{% when test %}{% endcase %}))
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_case_when_body
|
114
|
+
assert_equal(
|
115
|
+
["test"],
|
116
|
+
visit(%({% case 1 %}{% when 2 %}{{ test }}{% endcase %}))
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_case_else_body
|
121
|
+
assert_equal(
|
122
|
+
["test"],
|
123
|
+
visit(%({% case 1 %}{% else %}{{ test }}{% endcase %}))
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_for_in
|
128
|
+
assert_equal(
|
129
|
+
["test"],
|
130
|
+
visit(%({% for x in test %}{% endfor %}))
|
131
|
+
)
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_for_limit
|
135
|
+
assert_equal(
|
136
|
+
["test"],
|
137
|
+
visit(%({% for x in (1..5) limit: test %}{% endfor %}))
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_for_offset
|
142
|
+
assert_equal(
|
143
|
+
["test"],
|
144
|
+
visit(%({% for x in (1..5) offset: test %}{% endfor %}))
|
145
|
+
)
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_for_body
|
149
|
+
assert_equal(
|
150
|
+
["test"],
|
151
|
+
visit(%({% for x in (1..5) %}{{ test }}{% endfor %}))
|
152
|
+
)
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_tablerow_in
|
156
|
+
assert_equal(
|
157
|
+
["test"],
|
158
|
+
visit(%({% tablerow x in test %}{% endtablerow %}))
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_tablerow_limit
|
163
|
+
assert_equal(
|
164
|
+
["test"],
|
165
|
+
visit(%({% tablerow x in (1..5) limit: test %}{% endtablerow %}))
|
166
|
+
)
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_tablerow_offset
|
170
|
+
assert_equal(
|
171
|
+
["test"],
|
172
|
+
visit(%({% tablerow x in (1..5) offset: test %}{% endtablerow %}))
|
173
|
+
)
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_tablerow_body
|
177
|
+
assert_equal(
|
178
|
+
["test"],
|
179
|
+
visit(%({% tablerow x in (1..5) %}{{ test }}{% endtablerow %}))
|
180
|
+
)
|
181
|
+
end
|
182
|
+
|
183
|
+
def test_cycle
|
184
|
+
assert_equal(
|
185
|
+
["test"],
|
186
|
+
visit(%({% cycle test %}))
|
187
|
+
)
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_assign
|
191
|
+
assert_equal(
|
192
|
+
["test"],
|
193
|
+
visit(%({% assign x = test %}))
|
194
|
+
)
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_capture
|
198
|
+
assert_equal(
|
199
|
+
["test"],
|
200
|
+
visit(%({% capture x %}{{ test }}{% endcapture %}))
|
201
|
+
)
|
202
|
+
end
|
203
|
+
|
204
|
+
def test_include
|
205
|
+
assert_equal(
|
206
|
+
["test"],
|
207
|
+
visit(%({% include test %}))
|
208
|
+
)
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_include_with
|
212
|
+
assert_equal(
|
213
|
+
["test"],
|
214
|
+
visit(%({% include "hai" with test %}))
|
215
|
+
)
|
216
|
+
end
|
217
|
+
|
218
|
+
def test_include_for
|
219
|
+
assert_equal(
|
220
|
+
["test"],
|
221
|
+
visit(%({% include "hai" for test %}))
|
222
|
+
)
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_preserve_tree_structure
|
226
|
+
assert_equal(
|
227
|
+
[[nil, [
|
228
|
+
[nil, [[nil, [["other", []]]]]],
|
229
|
+
["test", []],
|
230
|
+
["xs", []]
|
231
|
+
]]],
|
232
|
+
traversal(%({% for x in xs offset: test %}{{ other }}{% endfor %})).visit
|
233
|
+
)
|
234
|
+
end
|
235
|
+
|
236
|
+
private
|
237
|
+
|
238
|
+
def traversal(template)
|
239
|
+
ParseTreeVisitor
|
240
|
+
.for(Template.parse(template).root)
|
241
|
+
.add_callback_for(VariableLookup, &:name)
|
242
|
+
end
|
243
|
+
|
244
|
+
def visit(template)
|
245
|
+
traversal(template).visit.flatten.compact
|
246
|
+
end
|
247
|
+
end
|
@@ -99,7 +99,7 @@ class ParsingQuirksTest < Minitest::Test
|
|
99
99
|
# After the messed up quotes a filter without parameters (reverse) should work
|
100
100
|
# but one with parameters (remove) shouldn't be detected.
|
101
101
|
assert_template_result('here', "{{ 'hi there' | split:\"t\"\" | reverse | first}}")
|
102
|
-
assert_template_result('hi ',
|
102
|
+
assert_template_result('hi ', "{{ 'hi there' | split:\"t\"\" | remove:\"i\" | first}}")
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
@@ -158,6 +158,10 @@ class StandardFiltersTest < Minitest::Test
|
|
158
158
|
assert_equal '1', @filters.url_decode(1)
|
159
159
|
assert_equal '2001-02-03', @filters.url_decode(Date.new(2001, 2, 3))
|
160
160
|
assert_nil @filters.url_decode(nil)
|
161
|
+
exception = assert_raises Liquid::ArgumentError do
|
162
|
+
@filters.url_decode('%ff')
|
163
|
+
end
|
164
|
+
assert_equal 'Liquid error: invalid byte sequence in UTF-8', exception.message
|
161
165
|
end
|
162
166
|
|
163
167
|
def test_truncatewords
|
@@ -177,6 +181,9 @@ class StandardFiltersTest < Minitest::Test
|
|
177
181
|
assert_equal 'test', @filters.strip_html("<div\nclass='multiline'>test</div>")
|
178
182
|
assert_equal 'test', @filters.strip_html("<!-- foo bar \n test -->test")
|
179
183
|
assert_equal '', @filters.strip_html(nil)
|
184
|
+
|
185
|
+
# Quirk of the existing implementation
|
186
|
+
assert_equal 'foo;', @filters.strip_html("<<<script </script>script>foo;</script>")
|
180
187
|
end
|
181
188
|
|
182
189
|
def test_join
|
@@ -268,10 +275,34 @@ class StandardFiltersTest < Minitest::Test
|
|
268
275
|
assert_equal [], @filters.sort([], "a")
|
269
276
|
end
|
270
277
|
|
278
|
+
def test_sort_invalid_property
|
279
|
+
foo = [
|
280
|
+
[1],
|
281
|
+
[2],
|
282
|
+
[3]
|
283
|
+
]
|
284
|
+
|
285
|
+
assert_raises Liquid::ArgumentError do
|
286
|
+
@filters.sort(foo, "bar")
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
271
290
|
def test_sort_natural_empty_array
|
272
291
|
assert_equal [], @filters.sort_natural([], "a")
|
273
292
|
end
|
274
293
|
|
294
|
+
def test_sort_natural_invalid_property
|
295
|
+
foo = [
|
296
|
+
[1],
|
297
|
+
[2],
|
298
|
+
[3]
|
299
|
+
]
|
300
|
+
|
301
|
+
assert_raises Liquid::ArgumentError do
|
302
|
+
@filters.sort_natural(foo, "bar")
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
275
306
|
def test_legacy_sort_hash
|
276
307
|
assert_equal [{ a: 1, b: 2 }], @filters.sort({ a: 1, b: 2 })
|
277
308
|
end
|
@@ -295,10 +326,34 @@ class StandardFiltersTest < Minitest::Test
|
|
295
326
|
assert_equal [], @filters.uniq([], "a")
|
296
327
|
end
|
297
328
|
|
329
|
+
def test_uniq_invalid_property
|
330
|
+
foo = [
|
331
|
+
[1],
|
332
|
+
[2],
|
333
|
+
[3]
|
334
|
+
]
|
335
|
+
|
336
|
+
assert_raises Liquid::ArgumentError do
|
337
|
+
@filters.uniq(foo, "bar")
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
298
341
|
def test_compact_empty_array
|
299
342
|
assert_equal [], @filters.compact([], "a")
|
300
343
|
end
|
301
344
|
|
345
|
+
def test_compact_invalid_property
|
346
|
+
foo = [
|
347
|
+
[1],
|
348
|
+
[2],
|
349
|
+
[3]
|
350
|
+
]
|
351
|
+
|
352
|
+
assert_raises Liquid::ArgumentError do
|
353
|
+
@filters.compact(foo, "bar")
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
302
357
|
def test_reverse
|
303
358
|
assert_equal [4, 3, 2, 1], @filters.reverse([1, 2, 3, 4])
|
304
359
|
end
|
@@ -364,6 +419,29 @@ class StandardFiltersTest < Minitest::Test
|
|
364
419
|
assert_template_result "123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new
|
365
420
|
end
|
366
421
|
|
422
|
+
def test_map_returns_empty_on_2d_input_array
|
423
|
+
foo = [
|
424
|
+
[1],
|
425
|
+
[2],
|
426
|
+
[3]
|
427
|
+
]
|
428
|
+
|
429
|
+
assert_raises Liquid::ArgumentError do
|
430
|
+
@filters.map(foo, "bar")
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
def test_map_returns_empty_with_no_property
|
435
|
+
foo = [
|
436
|
+
[1],
|
437
|
+
[2],
|
438
|
+
[3]
|
439
|
+
]
|
440
|
+
assert_raises Liquid::ArgumentError do
|
441
|
+
@filters.map(foo, nil)
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
367
445
|
def test_sort_works_on_enumerables
|
368
446
|
assert_template_result "213", '{{ foo | sort: "bar" | map: "foo" }}', "foo" => TestEnumerable.new
|
369
447
|
end
|
@@ -394,9 +472,9 @@ class StandardFiltersTest < Minitest::Test
|
|
394
472
|
assert_equal '07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y")
|
395
473
|
|
396
474
|
assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y")
|
397
|
-
assert_equal
|
398
|
-
assert_equal
|
399
|
-
assert_equal
|
475
|
+
assert_equal Date.today.year.to_s, @filters.date('now', '%Y')
|
476
|
+
assert_equal Date.today.year.to_s, @filters.date('today', '%Y')
|
477
|
+
assert_equal Date.today.year.to_s, @filters.date('Today', '%Y')
|
400
478
|
|
401
479
|
assert_nil @filters.date(nil, "%B")
|
402
480
|
|
@@ -614,6 +692,78 @@ class StandardFiltersTest < Minitest::Test
|
|
614
692
|
assert_template_result('abc', "{{ 'abc' | date: '%D' }}")
|
615
693
|
end
|
616
694
|
|
695
|
+
def test_where
|
696
|
+
input = [
|
697
|
+
{ "handle" => "alpha", "ok" => true },
|
698
|
+
{ "handle" => "beta", "ok" => false },
|
699
|
+
{ "handle" => "gamma", "ok" => false },
|
700
|
+
{ "handle" => "delta", "ok" => true }
|
701
|
+
]
|
702
|
+
|
703
|
+
expectation = [
|
704
|
+
{ "handle" => "alpha", "ok" => true },
|
705
|
+
{ "handle" => "delta", "ok" => true }
|
706
|
+
]
|
707
|
+
|
708
|
+
assert_equal expectation, @filters.where(input, "ok", true)
|
709
|
+
assert_equal expectation, @filters.where(input, "ok")
|
710
|
+
end
|
711
|
+
|
712
|
+
def test_where_no_key_set
|
713
|
+
input = [
|
714
|
+
{ "handle" => "alpha", "ok" => true },
|
715
|
+
{ "handle" => "beta" },
|
716
|
+
{ "handle" => "gamma" },
|
717
|
+
{ "handle" => "delta", "ok" => true }
|
718
|
+
]
|
719
|
+
|
720
|
+
expectation = [
|
721
|
+
{ "handle" => "alpha", "ok" => true },
|
722
|
+
{ "handle" => "delta", "ok" => true }
|
723
|
+
]
|
724
|
+
|
725
|
+
assert_equal expectation, @filters.where(input, "ok", true)
|
726
|
+
assert_equal expectation, @filters.where(input, "ok")
|
727
|
+
end
|
728
|
+
|
729
|
+
def test_where_non_array_map_input
|
730
|
+
assert_equal [{ "a" => "ok" }], @filters.where({ "a" => "ok" }, "a", "ok")
|
731
|
+
assert_equal [], @filters.where({ "a" => "not ok" }, "a", "ok")
|
732
|
+
end
|
733
|
+
|
734
|
+
def test_where_indexable_but_non_map_value
|
735
|
+
assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok", true) }
|
736
|
+
assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok") }
|
737
|
+
end
|
738
|
+
|
739
|
+
def test_where_non_boolean_value
|
740
|
+
input = [
|
741
|
+
{ "message" => "Bonjour!", "language" => "French" },
|
742
|
+
{ "message" => "Hello!", "language" => "English" },
|
743
|
+
{ "message" => "Hallo!", "language" => "German" }
|
744
|
+
]
|
745
|
+
|
746
|
+
assert_equal [{ "message" => "Bonjour!", "language" => "French" }], @filters.where(input, "language", "French")
|
747
|
+
assert_equal [{ "message" => "Hallo!", "language" => "German" }], @filters.where(input, "language", "German")
|
748
|
+
assert_equal [{ "message" => "Hello!", "language" => "English" }], @filters.where(input, "language", "English")
|
749
|
+
end
|
750
|
+
|
751
|
+
def test_where_array_of_only_unindexable_values
|
752
|
+
assert_nil @filters.where([nil], "ok", true)
|
753
|
+
assert_nil @filters.where([nil], "ok")
|
754
|
+
end
|
755
|
+
|
756
|
+
def test_where_no_target_value
|
757
|
+
input = [
|
758
|
+
{ "foo" => false },
|
759
|
+
{ "foo" => true },
|
760
|
+
{ "foo" => "for sure" },
|
761
|
+
{ "bar" => true }
|
762
|
+
]
|
763
|
+
|
764
|
+
assert_equal [{ "foo" => true }, { "foo" => "for sure" }], @filters.where(input, "foo")
|
765
|
+
end
|
766
|
+
|
617
767
|
private
|
618
768
|
|
619
769
|
def with_timezone(tz)
|
data/test/test_helper.rb
CHANGED
File without changes
|
@@ -24,9 +24,9 @@ class ConditionUnitTest < Minitest::Test
|
|
24
24
|
assert_evaluates_true 1, '<=', 1
|
25
25
|
# negative numbers
|
26
26
|
assert_evaluates_true 1, '>', -1
|
27
|
-
assert_evaluates_true
|
27
|
+
assert_evaluates_true -1, '<', 1
|
28
28
|
assert_evaluates_true 1.0, '>', -1.0
|
29
|
-
assert_evaluates_true
|
29
|
+
assert_evaluates_true -1.0, '<', 1.0
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_default_operators_evalute_false
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: liquid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Lütke
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -67,6 +67,7 @@ files:
|
|
67
67
|
- lib/liquid/lexer.rb
|
68
68
|
- lib/liquid/locales/en.yml
|
69
69
|
- lib/liquid/parse_context.rb
|
70
|
+
- lib/liquid/parse_tree_visitor.rb
|
70
71
|
- lib/liquid/parser.rb
|
71
72
|
- lib/liquid/parser_switching.rb
|
72
73
|
- lib/liquid/profiler.rb
|
@@ -95,6 +96,7 @@ files:
|
|
95
96
|
- lib/liquid/tags/unless.rb
|
96
97
|
- lib/liquid/template.rb
|
97
98
|
- lib/liquid/tokenizer.rb
|
99
|
+
- lib/liquid/truffle.rb
|
98
100
|
- lib/liquid/utils.rb
|
99
101
|
- lib/liquid/variable.rb
|
100
102
|
- lib/liquid/variable_lookup.rb
|
@@ -111,6 +113,7 @@ files:
|
|
111
113
|
- test/integration/filter_test.rb
|
112
114
|
- test/integration/hash_ordering_test.rb
|
113
115
|
- test/integration/output_test.rb
|
116
|
+
- test/integration/parse_tree_visitor_test.rb
|
114
117
|
- test/integration/parsing_quirks_test.rb
|
115
118
|
- test/integration/render_profiling_test.rb
|
116
119
|
- test/integration/security_test.rb
|
@@ -130,6 +133,7 @@ files:
|
|
130
133
|
- test/integration/trim_mode_test.rb
|
131
134
|
- test/integration/variable_test.rb
|
132
135
|
- test/test_helper.rb
|
136
|
+
- test/truffle/truffle_test.rb
|
133
137
|
- test/unit/block_unit_test.rb
|
134
138
|
- test/unit/condition_unit_test.rb
|
135
139
|
- test/unit/context_unit_test.rb
|
@@ -165,8 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
165
169
|
- !ruby/object:Gem::Version
|
166
170
|
version: 1.3.7
|
167
171
|
requirements: []
|
168
|
-
|
169
|
-
rubygems_version: 2.7.6
|
172
|
+
rubygems_version: 3.0.2
|
170
173
|
signing_key:
|
171
174
|
specification_version: 4
|
172
175
|
summary: A secure, non-evaling end user template engine with aesthetic markup.
|
@@ -191,6 +194,7 @@ test_files:
|
|
191
194
|
- test/integration/hash_ordering_test.rb
|
192
195
|
- test/integration/variable_test.rb
|
193
196
|
- test/integration/blank_test.rb
|
197
|
+
- test/integration/parse_tree_visitor_test.rb
|
194
198
|
- test/integration/assign_test.rb
|
195
199
|
- test/integration/trim_mode_test.rb
|
196
200
|
- test/integration/context_test.rb
|
@@ -216,5 +220,6 @@ test_files:
|
|
216
220
|
- test/integration/render_profiling_test.rb
|
217
221
|
- test/integration/parsing_quirks_test.rb
|
218
222
|
- test/integration/filter_test.rb
|
223
|
+
- test/truffle/truffle_test.rb
|
219
224
|
- test/fixtures/en_locale.yml
|
220
225
|
- test/test_helper.rb
|