Support for binary operators in where_exp filter (#6998)
Merge pull request 6998
This commit is contained in:
		
							parent
							
								
									4550f02b58
								
							
						
					
					
						commit
						e819bc4af0
					
				| 
						 | 
				
			
			@ -365,23 +365,49 @@ module Jekyll
 | 
			
		|||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # -----------   The following set of code was *adapted* from Liquid::If
 | 
			
		||||
    # -----------   ref: https://git.io/vp6K6
 | 
			
		||||
 | 
			
		||||
    # Parse a string to a Liquid Condition
 | 
			
		||||
    def parse_condition(exp)
 | 
			
		||||
      parser = Liquid::Parser.new(exp)
 | 
			
		||||
      left_expr = parser.expression
 | 
			
		||||
      operator = parser.consume?(:comparison)
 | 
			
		||||
      condition =
 | 
			
		||||
        if operator
 | 
			
		||||
          Liquid::Condition.new(Liquid::Expression.parse(left_expr),
 | 
			
		||||
                                operator,
 | 
			
		||||
                                Liquid::Expression.parse(parser.expression))
 | 
			
		||||
        else
 | 
			
		||||
          Liquid::Condition.new(Liquid::Expression.parse(left_expr))
 | 
			
		||||
        end
 | 
			
		||||
      parser.consume(:end_of_string)
 | 
			
		||||
      parser    = Liquid::Parser.new(exp)
 | 
			
		||||
      condition = parse_binary_comparison(parser)
 | 
			
		||||
 | 
			
		||||
      parser.consume(:end_of_string)
 | 
			
		||||
      condition
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # Generate a Liquid::Condition object from a Liquid::Parser object additionally processing
 | 
			
		||||
    # the parsed expression based on whether the expression consists of binary operations with
 | 
			
		||||
    # Liquid operators `and` or `or`
 | 
			
		||||
    #
 | 
			
		||||
    #  - parser: an instance of Liquid::Parser
 | 
			
		||||
    #
 | 
			
		||||
    # Returns an instance of Liquid::Condition
 | 
			
		||||
    def parse_binary_comparison(parser)
 | 
			
		||||
      parse_comparison(parser).tap do |condition|
 | 
			
		||||
        binary_operator = parser.id?("and") || parser.id?("or")
 | 
			
		||||
        condition.send(binary_operator, parse_comparison(parser)) if binary_operator
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # Generates a Liquid::Condition object from a Liquid::Parser object based on whether the parsed
 | 
			
		||||
    # expression involves a "comparison" operator (e.g. <, ==, >, !=, etc)
 | 
			
		||||
    #
 | 
			
		||||
    #  - parser: an instance of Liquid::Parser
 | 
			
		||||
    #
 | 
			
		||||
    # Returns an instance of Liquid::Condition
 | 
			
		||||
    def parse_comparison(parser)
 | 
			
		||||
      left_operand = Liquid::Expression.parse(parser.expression)
 | 
			
		||||
      operator     = parser.consume?(:comparison)
 | 
			
		||||
 | 
			
		||||
      # No comparison-operator detected. Initialize a Liquid::Condition using only left operand
 | 
			
		||||
      return Liquid::Condition.new(left_operand) unless operator
 | 
			
		||||
 | 
			
		||||
      # Parse what remained after extracting the left operand and the `:comparison` operator
 | 
			
		||||
      # and initialize a Liquid::Condition object using the operands and the comparison-operator
 | 
			
		||||
      Liquid::Condition.new(left_operand, operator, Liquid::Expression.parse(parser.expression))
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,6 +48,7 @@ class TestFilters < JekyllUnitTest
 | 
			
		|||
      @time_as_numeric = 1_399_680_607
 | 
			
		||||
      @integer_as_string = "142857"
 | 
			
		||||
      @array_of_objects = [
 | 
			
		||||
        { "color" => "teal", "size" => "large"  },
 | 
			
		||||
        { "color" => "red",  "size" => "large"  },
 | 
			
		||||
        { "color" => "red",  "size" => "medium" },
 | 
			
		||||
        { "color" => "blue", "size" => "medium" },
 | 
			
		||||
| 
						 | 
				
			
			@ -914,6 +915,28 @@ class TestFilters < JekyllUnitTest
 | 
			
		|||
        )
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      should "filter objects appropriately with 'or', 'and' operators" do
 | 
			
		||||
        assert_equal(
 | 
			
		||||
          [
 | 
			
		||||
            { "color" => "teal", "size" => "large"  },
 | 
			
		||||
            { "color" => "red",  "size" => "large"  },
 | 
			
		||||
            { "color" => "red",  "size" => "medium" },
 | 
			
		||||
          ],
 | 
			
		||||
          @filter.where_exp(
 | 
			
		||||
            @array_of_objects, "item", "item.color == 'red' or item.size == 'large'"
 | 
			
		||||
          )
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        assert_equal(
 | 
			
		||||
          [
 | 
			
		||||
            { "color" => "red", "size" => "large" },
 | 
			
		||||
          ],
 | 
			
		||||
          @filter.where_exp(
 | 
			
		||||
            @array_of_objects, "item", "item.color == 'red' and item.size == 'large'"
 | 
			
		||||
          )
 | 
			
		||||
        )
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      should "stringify during comparison for compatibility with liquid parsing" do
 | 
			
		||||
        hash = {
 | 
			
		||||
          "The Words" => { "rating" => 1.2, "featured" => false },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue