From 6d4cffa000b575323cf7bbfdc3248d8d18e0db0a Mon Sep 17 00:00:00 2001 From: Albert Chu Date: Tue, 4 Mar 2025 17:08:23 -0700 Subject: [PATCH] Support for simple boolean comparisons and boolean assignments --- lib/liquid.rb | 1 + lib/liquid/boolean_expression.rb | 21 +++++++++++++++++++++ lib/liquid/variable.rb | 27 ++++++++++++++++++++------- 3 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 lib/liquid/boolean_expression.rb diff --git a/lib/liquid.rb b/lib/liquid.rb index 4d0a71a6..445dfbf7 100644 --- a/lib/liquid.rb +++ b/lib/liquid.rb @@ -89,3 +89,4 @@ require 'liquid/partial_cache' require 'liquid/usage' require 'liquid/registers' require 'liquid/template_factory' +require 'liquid/boolean_expression' diff --git a/lib/liquid/boolean_expression.rb b/lib/liquid/boolean_expression.rb new file mode 100644 index 00000000..bccffea0 --- /dev/null +++ b/lib/liquid/boolean_expression.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Liquid + class BooleanExpression + def self.parse(markup, ss = StringScanner.new(""), cache = nil) + # Split the markup by comparison operators + if (match = markup.match(/\A\s*(.+?)\s*(==|!=|<>|<=|>=|<|>|contains)\s*(.+)\s*\z/)) + left = Expression.parse(match[1], ss, cache) + operator = match[2] + right = Expression.parse(match[3], ss, cache) + + # Create a condition object to evaluate the expression + condition = Condition.new(left, operator, right) + return condition + end + + # If no comparison operator is found, just parse as regular expression + Expression.parse(markup, ss, cache) + end + end +end diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb index 20957065..fffa7fa9 100644 --- a/lib/liquid/variable.rb +++ b/lib/liquid/variable.rb @@ -17,6 +17,7 @@ module Liquid FilterArgsRegex = /(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o JustTagAttributes = /\A#{TagAttributes}\z/o MarkupWithQuotedFragment = /(#{QuotedFragment})(.*)/om + ComparisonOperator = /==|!=|<>|<=|>=|<|>|contains/o attr_accessor :filters, :name, :line_number attr_reader :parse_context @@ -47,7 +48,14 @@ module Liquid name_markup = Regexp.last_match(1) filter_markup = Regexp.last_match(2) - @name = parse_context.parse_expression(name_markup) + + # Check if name_markup contains a comparison operator + @name = if /\s*(#{ComparisonOperator})\s*/.match?(name_markup) + BooleanExpression.parse(name_markup) + else + parse_context.parse_expression(name_markup) + end + if filter_markup =~ FilterMarkupRegex filters = Regexp.last_match(1).scan(FilterParser) filters.each do |f| @@ -65,13 +73,18 @@ module Liquid return if p.look(:end_of_string) - @name = parse_context.parse_expression(p.expression) - while p.consume?(:pipe) - filtername = p.consume(:id) - filterargs = p.consume?(:colon) ? parse_filterargs(p) : Const::EMPTY_ARRAY - @filters << parse_filter_expressions(filtername, filterargs) + # Check if markup contains a comparison operator + if /\s*(#{ComparisonOperator})\s*/.match?(markup) + @name = BooleanExpression.parse(markup) + else + @name = parse_context.parse_expression(p.expression) + while p.consume?(:pipe) + filtername = p.consume(:id) + filterargs = p.consume?(:colon) ? parse_filterargs(p) : Const::EMPTY_ARRAY + @filters << parse_filter_expressions(filtername, filterargs) + end + p.consume(:end_of_string) end - p.consume(:end_of_string) end def parse_filterargs(p)