mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-20 11:20:41 -07:00
Refactor Condition so that it takes a parsed expression.
This commit is contained in:
@@ -3,7 +3,7 @@ module Liquid
|
|||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
#
|
#
|
||||||
# c = Condition.new('1', '==', '1')
|
# c = Condition.new(1, '==', 1)
|
||||||
# c.evaluate #=> true
|
# c.evaluate #=> true
|
||||||
#
|
#
|
||||||
class Condition #:nodoc:
|
class Condition #:nodoc:
|
||||||
@@ -28,9 +28,9 @@ module Liquid
|
|||||||
attr_accessor :left, :operator, :right
|
attr_accessor :left, :operator, :right
|
||||||
|
|
||||||
def initialize(left = nil, operator = nil, right = nil)
|
def initialize(left = nil, operator = nil, right = nil)
|
||||||
@left = Expression.parse(left)
|
@left = left
|
||||||
@operator = operator
|
@operator = operator
|
||||||
@right = Expression.parse(right)
|
@right = right
|
||||||
@child_relation = nil
|
@child_relation = nil
|
||||||
@child_condition = nil
|
@child_condition = nil
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ module Liquid
|
|||||||
@blocks = []
|
@blocks = []
|
||||||
|
|
||||||
if markup =~ Syntax
|
if markup =~ Syntax
|
||||||
@left = $1
|
@left = Expression.parse($1)
|
||||||
else
|
else
|
||||||
raise SyntaxError.new(options[:locale].t("errors.syntax.case".freeze))
|
raise SyntaxError.new(options[:locale].t("errors.syntax.case".freeze))
|
||||||
end
|
end
|
||||||
@@ -58,7 +58,7 @@ module Liquid
|
|||||||
|
|
||||||
markup = $2
|
markup = $2
|
||||||
|
|
||||||
block = Condition.new(@left, '=='.freeze, $1)
|
block = Condition.new(@left, '=='.freeze, Expression.parse($1))
|
||||||
block.attach(@nodelist)
|
block.attach(@nodelist)
|
||||||
@blocks.push(block)
|
@blocks.push(block)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -60,14 +60,14 @@ module Liquid
|
|||||||
expressions = markup.scan(ExpressionsAndOperators)
|
expressions = markup.scan(ExpressionsAndOperators)
|
||||||
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop =~ Syntax
|
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop =~ Syntax
|
||||||
|
|
||||||
condition = Condition.new($1, $2, $3)
|
condition = Condition.new(Expression.parse($1), $2, Expression.parse($3))
|
||||||
|
|
||||||
while not expressions.empty?
|
while not expressions.empty?
|
||||||
operator = expressions.pop.to_s.strip
|
operator = expressions.pop.to_s.strip
|
||||||
|
|
||||||
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop.to_s =~ Syntax
|
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop.to_s =~ Syntax
|
||||||
|
|
||||||
new_condition = Condition.new($1, $2, $3)
|
new_condition = Condition.new(Expression.parse($1), $2, Expression.parse($3))
|
||||||
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless BOOLEAN_OPERATORS.include?(operator)
|
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless BOOLEAN_OPERATORS.include?(operator)
|
||||||
new_condition.send(operator, condition)
|
new_condition.send(operator, condition)
|
||||||
condition = new_condition
|
condition = new_condition
|
||||||
@@ -92,9 +92,9 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def parse_comparison(p)
|
def parse_comparison(p)
|
||||||
a = p.expression
|
a = Expression.parse(p.expression)
|
||||||
if op = p.consume?(:comparison)
|
if op = p.consume?(:comparison)
|
||||||
b = p.expression
|
b = Expression.parse(p.expression)
|
||||||
Condition.new(a, op, b)
|
Condition.new(a, op, b)
|
||||||
else
|
else
|
||||||
Condition.new(a)
|
Condition.new(a)
|
||||||
|
|||||||
@@ -4,110 +4,111 @@ class ConditionUnitTest < Minitest::Test
|
|||||||
include Liquid
|
include Liquid
|
||||||
|
|
||||||
def test_basic_condition
|
def test_basic_condition
|
||||||
assert_equal false, Condition.new('1', '==', '2').evaluate
|
assert_equal false, Condition.new(1, '==', 2).evaluate
|
||||||
assert_equal true, Condition.new('1', '==', '1').evaluate
|
assert_equal true, Condition.new(1, '==', 1).evaluate
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_default_operators_evalute_true
|
def test_default_operators_evalute_true
|
||||||
assert_evalutes_true '1', '==', '1'
|
assert_evalutes_true 1, '==', 1
|
||||||
assert_evalutes_true '1', '!=', '2'
|
assert_evalutes_true 1, '!=', 2
|
||||||
assert_evalutes_true '1', '<>', '2'
|
assert_evalutes_true 1, '<>', 2
|
||||||
assert_evalutes_true '1', '<', '2'
|
assert_evalutes_true 1, '<', 2
|
||||||
assert_evalutes_true '2', '>', '1'
|
assert_evalutes_true 2, '>', 1
|
||||||
assert_evalutes_true '1', '>=', '1'
|
assert_evalutes_true 1, '>=', 1
|
||||||
assert_evalutes_true '2', '>=', '1'
|
assert_evalutes_true 2, '>=', 1
|
||||||
assert_evalutes_true '1', '<=', '2'
|
assert_evalutes_true 1, '<=', 2
|
||||||
assert_evalutes_true '1', '<=', '1'
|
assert_evalutes_true 1, '<=', 1
|
||||||
# negative numbers
|
# negative numbers
|
||||||
assert_evalutes_true '1', '>', '-1'
|
assert_evalutes_true 1, '>', -1
|
||||||
assert_evalutes_true '-1', '<', '1'
|
assert_evalutes_true -1, '<', 1
|
||||||
assert_evalutes_true '1.0', '>', '-1.0'
|
assert_evalutes_true 1.0, '>', -1.0
|
||||||
assert_evalutes_true '-1.0', '<', '1.0'
|
assert_evalutes_true -1.0, '<', 1.0
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_default_operators_evalute_false
|
def test_default_operators_evalute_false
|
||||||
assert_evalutes_false '1', '==', '2'
|
assert_evalutes_false 1, '==', 2
|
||||||
assert_evalutes_false '1', '!=', '1'
|
assert_evalutes_false 1, '!=', 1
|
||||||
assert_evalutes_false '1', '<>', '1'
|
assert_evalutes_false 1, '<>', 1
|
||||||
assert_evalutes_false '1', '<', '0'
|
assert_evalutes_false 1, '<', 0
|
||||||
assert_evalutes_false '2', '>', '4'
|
assert_evalutes_false 2, '>', 4
|
||||||
assert_evalutes_false '1', '>=', '3'
|
assert_evalutes_false 1, '>=', 3
|
||||||
assert_evalutes_false '2', '>=', '4'
|
assert_evalutes_false 2, '>=', 4
|
||||||
assert_evalutes_false '1', '<=', '0'
|
assert_evalutes_false 1, '<=', 0
|
||||||
assert_evalutes_false '1', '<=', '0'
|
assert_evalutes_false 1, '<=', 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_contains_works_on_strings
|
def test_contains_works_on_strings
|
||||||
assert_evalutes_true "'bob'", 'contains', "'o'"
|
assert_evalutes_true 'bob', 'contains', 'o'
|
||||||
assert_evalutes_true "'bob'", 'contains', "'b'"
|
assert_evalutes_true 'bob', 'contains', 'b'
|
||||||
assert_evalutes_true "'bob'", 'contains', "'bo'"
|
assert_evalutes_true 'bob', 'contains', 'bo'
|
||||||
assert_evalutes_true "'bob'", 'contains', "'ob'"
|
assert_evalutes_true 'bob', 'contains', 'ob'
|
||||||
assert_evalutes_true "'bob'", 'contains', "'bob'"
|
assert_evalutes_true 'bob', 'contains', 'bob'
|
||||||
|
|
||||||
assert_evalutes_false "'bob'", 'contains', "'bob2'"
|
assert_evalutes_false 'bob', 'contains', 'bob2'
|
||||||
assert_evalutes_false "'bob'", 'contains', "'a'"
|
assert_evalutes_false 'bob', 'contains', 'a'
|
||||||
assert_evalutes_false "'bob'", 'contains', "'---'"
|
assert_evalutes_false 'bob', 'contains', '---'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_invalid_comparation_operator
|
def test_invalid_comparation_operator
|
||||||
assert_evaluates_argument_error "1", '~~', '0'
|
assert_evaluates_argument_error 1, '~~', 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_comparation_of_int_and_str
|
def test_comparation_of_int_and_str
|
||||||
assert_evaluates_argument_error "'1'", '>', '0'
|
assert_evaluates_argument_error '1', '>', 0
|
||||||
assert_evaluates_argument_error "'1'", '<', '0'
|
assert_evaluates_argument_error '1', '<', 0
|
||||||
assert_evaluates_argument_error "'1'", '>=', '0'
|
assert_evaluates_argument_error '1', '>=', 0
|
||||||
assert_evaluates_argument_error "'1'", '<=', '0'
|
assert_evaluates_argument_error '1', '<=', 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_contains_works_on_arrays
|
def test_contains_works_on_arrays
|
||||||
@context = Liquid::Context.new
|
@context = Liquid::Context.new
|
||||||
@context['array'] = [1,2,3,4,5]
|
@context['array'] = [1,2,3,4,5]
|
||||||
|
array_expr = VariableLookup.new("array")
|
||||||
|
|
||||||
assert_evalutes_false "array", 'contains', '0'
|
assert_evalutes_false array_expr, 'contains', 0
|
||||||
assert_evalutes_true "array", 'contains', '1'
|
assert_evalutes_true array_expr, 'contains', 1
|
||||||
assert_evalutes_true "array", 'contains', '2'
|
assert_evalutes_true array_expr, 'contains', 2
|
||||||
assert_evalutes_true "array", 'contains', '3'
|
assert_evalutes_true array_expr, 'contains', 3
|
||||||
assert_evalutes_true "array", 'contains', '4'
|
assert_evalutes_true array_expr, 'contains', 4
|
||||||
assert_evalutes_true "array", 'contains', '5'
|
assert_evalutes_true array_expr, 'contains', 5
|
||||||
assert_evalutes_false "array", 'contains', '6'
|
assert_evalutes_false array_expr, 'contains', 6
|
||||||
assert_evalutes_false "array", 'contains', '"1"'
|
assert_evalutes_false array_expr, 'contains', "1"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_contains_returns_false_for_nil_operands
|
def test_contains_returns_false_for_nil_operands
|
||||||
@context = Liquid::Context.new
|
@context = Liquid::Context.new
|
||||||
assert_evalutes_false "not_assigned", 'contains', '0'
|
assert_evalutes_false VariableLookup.new('not_assigned'), 'contains', '0'
|
||||||
assert_evalutes_false "0", 'contains', 'not_assigned'
|
assert_evalutes_false 0, 'contains', VariableLookup.new('not_assigned')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_contains_return_false_on_wrong_data_type
|
def test_contains_return_false_on_wrong_data_type
|
||||||
assert_evalutes_false "1", 'contains', '0'
|
assert_evalutes_false 1, 'contains', 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_or_condition
|
def test_or_condition
|
||||||
condition = Condition.new('1', '==', '2')
|
condition = Condition.new(1, '==', 2)
|
||||||
|
|
||||||
assert_equal false, condition.evaluate
|
assert_equal false, condition.evaluate
|
||||||
|
|
||||||
condition.or Condition.new('2', '==', '1')
|
condition.or Condition.new(2, '==', 1)
|
||||||
|
|
||||||
assert_equal false, condition.evaluate
|
assert_equal false, condition.evaluate
|
||||||
|
|
||||||
condition.or Condition.new('1', '==', '1')
|
condition.or Condition.new(1, '==', 1)
|
||||||
|
|
||||||
assert_equal true, condition.evaluate
|
assert_equal true, condition.evaluate
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_and_condition
|
def test_and_condition
|
||||||
condition = Condition.new('1', '==', '1')
|
condition = Condition.new(1, '==', 1)
|
||||||
|
|
||||||
assert_equal true, condition.evaluate
|
assert_equal true, condition.evaluate
|
||||||
|
|
||||||
condition.and Condition.new('2', '==', '2')
|
condition.and Condition.new(2, '==', 2)
|
||||||
|
|
||||||
assert_equal true, condition.evaluate
|
assert_equal true, condition.evaluate
|
||||||
|
|
||||||
condition.and Condition.new('2', '==', '1')
|
condition.and Condition.new(2, '==', 1)
|
||||||
|
|
||||||
assert_equal false, condition.evaluate
|
assert_equal false, condition.evaluate
|
||||||
end
|
end
|
||||||
@@ -115,18 +116,17 @@ class ConditionUnitTest < Minitest::Test
|
|||||||
def test_should_allow_custom_proc_operator
|
def test_should_allow_custom_proc_operator
|
||||||
Condition.operators['starts_with'] = Proc.new { |cond, left, right| left =~ %r{^#{right}} }
|
Condition.operators['starts_with'] = Proc.new { |cond, left, right| left =~ %r{^#{right}} }
|
||||||
|
|
||||||
assert_evalutes_true "'bob'", 'starts_with', "'b'"
|
assert_evalutes_true 'bob', 'starts_with', 'b'
|
||||||
assert_evalutes_false "'bob'", 'starts_with', "'o'"
|
assert_evalutes_false 'bob', 'starts_with', 'o'
|
||||||
|
ensure
|
||||||
ensure
|
Condition.operators.delete 'starts_with'
|
||||||
Condition.operators.delete 'starts_with'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_left_or_right_may_contain_operators
|
def test_left_or_right_may_contain_operators
|
||||||
@context = Liquid::Context.new
|
@context = Liquid::Context.new
|
||||||
@context['one'] = @context['another'] = "gnomeslab-and-or-liquid"
|
@context['one'] = @context['another'] = "gnomeslab-and-or-liquid"
|
||||||
|
|
||||||
assert_evalutes_true "one", '==', "another"
|
assert_evalutes_true VariableLookup.new("one"), '==', VariableLookup.new("another")
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
Reference in New Issue
Block a user