Skip to content

Commit ef47709

Browse files
committed
Fix MethodLiteral for updated blank & empty
1 parent a4e82eb commit ef47709

File tree

4 files changed

+53
-20
lines changed

4 files changed

+53
-20
lines changed

lib/liquid/binary_expression.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def contains(left, right)
7272
end
7373

7474
def apply_method_literal(node, other)
75-
other.send(node.method_name) if other.respond_to?(node.method_name)
75+
node.apply(other)
7676
end
7777

7878
def equal_variables(left, right)

lib/liquid/expression.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ class Expression
99
'' => nil,
1010
'true' => true,
1111
'false' => false,
12-
'blank' => MethodLiteral.new(:blank?, '').freeze,
13-
'empty' => MethodLiteral.new(:empty?, '').freeze,
12+
'blank' => MethodLiteral::BLANK,
13+
'empty' => MethodLiteral::EMPTY,
1414
}.freeze
1515

1616
DOT = ".".ord

lib/liquid/method_literal.rb

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,46 @@ module Liquid
44
class MethodLiteral
55
attr_reader :method_name, :to_s
66

7-
def initialize(method_name, to_s)
7+
def initialize(method_name, to_s, &evaluator)
88
@method_name = method_name
99
@to_s = to_s
10+
@evaluator = evaluator
11+
end
12+
13+
def apply(value)
14+
if value.respond_to?(@method_name)
15+
value.send(@method_name)
16+
elsif @evaluator
17+
@evaluator.call(value)
18+
end
1019
end
1120

1221
def to_liquid
1322
to_s
1423
end
24+
25+
BLANK = MethodLiteral.new(:blank?, '') do |value|
26+
case value
27+
when NilClass, FalseClass
28+
true
29+
when TrueClass, Numeric
30+
false
31+
when String
32+
value.empty? || value.match?(/\A\s*\z/)
33+
when Array, Hash
34+
value.empty?
35+
else
36+
value.respond_to?(:empty?) ? value.empty? : false
37+
end
38+
end.freeze
39+
40+
EMPTY = MethodLiteral.new(:empty?, '') do |value|
41+
case value
42+
when String, Array, Hash
43+
value.empty?
44+
else
45+
value.respond_to?(:empty?) ? value.empty? : nil
46+
end
47+
end.freeze
1548
end
1649
end

test/unit/condition_unit_test.rb

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ def test_blank_with_whitespace_string
197197
# Template authors expect " " to be blank since it has no visible content.
198198
# This matches ActiveSupport's String#blank? which returns true for whitespace-only strings.
199199
@context['whitespace'] = ' '
200-
blank_literal = Condition.class_variable_get(:@@method_literals)['blank']
200+
blank_literal = Expression::LITERALS['blank']
201201

202202
assert_evaluates_true(VariableLookup.parse('whitespace'), '==', blank_literal)
203203
end
@@ -206,7 +206,7 @@ def test_blank_with_empty_string
206206
# An empty string has no content, so it should be considered blank.
207207
# This is the most basic case of a blank string.
208208
@context['empty_string'] = ''
209-
blank_literal = Condition.class_variable_get(:@@method_literals)['blank']
209+
blank_literal = Expression::LITERALS['blank']
210210

211211
assert_evaluates_true(VariableLookup.parse('empty_string'), '==', blank_literal)
212212
end
@@ -215,7 +215,7 @@ def test_blank_with_empty_array
215215
# Empty arrays have no elements, so they are blank.
216216
# Useful for checking if a collection has items: {% if products == blank %}
217217
@context['empty_array'] = []
218-
blank_literal = Condition.class_variable_get(:@@method_literals)['blank']
218+
blank_literal = Expression::LITERALS['blank']
219219

220220
assert_evaluates_true(VariableLookup.parse('empty_array'), '==', blank_literal)
221221
end
@@ -224,7 +224,7 @@ def test_blank_with_empty_hash
224224
# Empty hashes have no key-value pairs, so they are blank.
225225
# Useful for checking if settings/options exist: {% if settings == blank %}
226226
@context['empty_hash'] = {}
227-
blank_literal = Condition.class_variable_get(:@@method_literals)['blank']
227+
blank_literal = Expression::LITERALS['blank']
228228

229229
assert_evaluates_true(VariableLookup.parse('empty_hash'), '==', blank_literal)
230230
end
@@ -233,7 +233,7 @@ def test_blank_with_nil
233233
# nil represents "nothing" and is the canonical blank value.
234234
# Unassigned variables resolve to nil, so this enables: {% if missing_var == blank %}
235235
@context['nil_value'] = nil
236-
blank_literal = Condition.class_variable_get(:@@method_literals)['blank']
236+
blank_literal = Expression::LITERALS['blank']
237237

238238
assert_evaluates_true(VariableLookup.parse('nil_value'), '==', blank_literal)
239239
end
@@ -242,7 +242,7 @@ def test_blank_with_false
242242
# false is considered blank to match ActiveSupport semantics.
243243
# This allows {% if some_flag == blank %} to work when flag is false.
244244
@context['false_value'] = false
245-
blank_literal = Condition.class_variable_get(:@@method_literals)['blank']
245+
blank_literal = Expression::LITERALS['blank']
246246

247247
assert_evaluates_true(VariableLookup.parse('false_value'), '==', blank_literal)
248248
end
@@ -251,7 +251,7 @@ def test_not_blank_with_true
251251
# true is a definite value, not blank.
252252
# Ensures {% if flag == blank %} works correctly for boolean flags.
253253
@context['true_value'] = true
254-
blank_literal = Condition.class_variable_get(:@@method_literals)['blank']
254+
blank_literal = Expression::LITERALS['blank']
255255

256256
assert_evaluates_false(VariableLookup.parse('true_value'), '==', blank_literal)
257257
end
@@ -260,7 +260,7 @@ def test_not_blank_with_number
260260
# Numbers (including zero) are never blank - they represent actual values.
261261
# 0 is a valid quantity, not the absence of a value.
262262
@context['number'] = 42
263-
blank_literal = Condition.class_variable_get(:@@method_literals)['blank']
263+
blank_literal = Expression::LITERALS['blank']
264264

265265
assert_evaluates_false(VariableLookup.parse('number'), '==', blank_literal)
266266
end
@@ -269,7 +269,7 @@ def test_not_blank_with_string_content
269269
# A string with actual content is not blank.
270270
# This is the expected behavior for most template string comparisons.
271271
@context['string'] = 'hello'
272-
blank_literal = Condition.class_variable_get(:@@method_literals)['blank']
272+
blank_literal = Expression::LITERALS['blank']
273273

274274
assert_evaluates_false(VariableLookup.parse('string'), '==', blank_literal)
275275
end
@@ -278,7 +278,7 @@ def test_not_blank_with_non_empty_array
278278
# An array with elements has content, so it's not blank.
279279
# Enables patterns like {% unless products == blank %}Show products{% endunless %}
280280
@context['array'] = [1, 2, 3]
281-
blank_literal = Condition.class_variable_get(:@@method_literals)['blank']
281+
blank_literal = Expression::LITERALS['blank']
282282

283283
assert_evaluates_false(VariableLookup.parse('array'), '==', blank_literal)
284284
end
@@ -287,7 +287,7 @@ def test_not_blank_with_non_empty_hash
287287
# A hash with key-value pairs has content, so it's not blank.
288288
# Useful for checking if configuration exists: {% if config != blank %}
289289
@context['hash'] = { 'a' => 1 }
290-
blank_literal = Condition.class_variable_get(:@@method_literals)['blank']
290+
blank_literal = Expression::LITERALS['blank']
291291

292292
assert_evaluates_false(VariableLookup.parse('hash'), '==', blank_literal)
293293
end
@@ -303,7 +303,7 @@ def test_empty_with_empty_string
303303
# An empty string ("") has length 0, so it's empty.
304304
# Different from blank - empty is a stricter check.
305305
@context['empty_string'] = ''
306-
empty_literal = Condition.class_variable_get(:@@method_literals)['empty']
306+
empty_literal = Expression::LITERALS['empty']
307307

308308
assert_evaluates_true(VariableLookup.parse('empty_string'), '==', empty_literal)
309309
end
@@ -313,7 +313,7 @@ def test_empty_with_whitespace_string_not_empty
313313
# This is the key difference between empty and blank:
314314
# " ".empty? => false, but " ".blank? => true
315315
@context['whitespace'] = ' '
316-
empty_literal = Condition.class_variable_get(:@@method_literals)['empty']
316+
empty_literal = Expression::LITERALS['empty']
317317

318318
assert_evaluates_false(VariableLookup.parse('whitespace'), '==', empty_literal)
319319
end
@@ -322,7 +322,7 @@ def test_empty_with_empty_array
322322
# An array with no elements is empty.
323323
# [].empty? => true
324324
@context['empty_array'] = []
325-
empty_literal = Condition.class_variable_get(:@@method_literals)['empty']
325+
empty_literal = Expression::LITERALS['empty']
326326

327327
assert_evaluates_true(VariableLookup.parse('empty_array'), '==', empty_literal)
328328
end
@@ -331,7 +331,7 @@ def test_empty_with_empty_hash
331331
# A hash with no key-value pairs is empty.
332332
# {}.empty? => true
333333
@context['empty_hash'] = {}
334-
empty_literal = Condition.class_variable_get(:@@method_literals)['empty']
334+
empty_literal = Expression::LITERALS['empty']
335335

336336
assert_evaluates_true(VariableLookup.parse('empty_hash'), '==', empty_literal)
337337
end
@@ -341,7 +341,7 @@ def test_nil_is_not_empty
341341
# nil is not a collection, so it cannot be empty.
342342
# This differs from blank: nil IS blank, but nil is NOT empty.
343343
@context['nil_value'] = nil
344-
empty_literal = Condition.class_variable_get(:@@method_literals)['empty']
344+
empty_literal = Expression::LITERALS['empty']
345345

346346
assert_evaluates_false(VariableLookup.parse('nil_value'), '==', empty_literal)
347347
end

0 commit comments

Comments
 (0)