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 | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |     # -----------   The following set of code was *adapted* from Liquid::If | ||||||
|  |     # -----------   ref: https://git.io/vp6K6 | ||||||
|  | 
 | ||||||
|     # Parse a string to a Liquid Condition |     # Parse a string to a Liquid Condition | ||||||
|     def parse_condition(exp) |     def parse_condition(exp) | ||||||
|       parser    = Liquid::Parser.new(exp) |       parser    = Liquid::Parser.new(exp) | ||||||
|       left_expr = parser.expression |       condition = parse_binary_comparison(parser) | ||||||
|       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.consume(:end_of_string) | ||||||
|       condition |       condition | ||||||
|     end |     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 | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -48,6 +48,7 @@ class TestFilters < JekyllUnitTest | ||||||
|       @time_as_numeric = 1_399_680_607 |       @time_as_numeric = 1_399_680_607 | ||||||
|       @integer_as_string = "142857" |       @integer_as_string = "142857" | ||||||
|       @array_of_objects = [ |       @array_of_objects = [ | ||||||
|  |         { "color" => "teal", "size" => "large"  }, | ||||||
|         { "color" => "red",  "size" => "large"  }, |         { "color" => "red",  "size" => "large"  }, | ||||||
|         { "color" => "red",  "size" => "medium" }, |         { "color" => "red",  "size" => "medium" }, | ||||||
|         { "color" => "blue", "size" => "medium" }, |         { "color" => "blue", "size" => "medium" }, | ||||||
|  | @ -914,6 +915,28 @@ class TestFilters < JekyllUnitTest | ||||||
|         ) |         ) | ||||||
|       end |       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 |       should "stringify during comparison for compatibility with liquid parsing" do | ||||||
|         hash = { |         hash = { | ||||||
|           "The Words" => { "rating" => 1.2, "featured" => false }, |           "The Words" => { "rating" => 1.2, "featured" => false }, | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue