# frozen_string_literal: true module Synvert::Core::NodeQuery::Compiler # Compare acutal value with expected value. module Comparable SIMPLE_VALID_OPERATORS = [:==, :!=, :includes] NUMBER_VALID_OPERATORS = [:==, :!=, :>, :>=, :<, :<=, :includes] ARRAY_VALID_OPERATORS = [:==, :!=, :in, :not_in] REGEXP_VALID_OPERATORS = [:=~, :!~] # Check if the actual value matches the expected value. # # @param node [Parser::AST::Node] node to calculate actual value # @param operator [Symbol] operator to compare with expected value, operator can be :==, :!=, :>, :>=, :<, :<=, :includes, :in, :not_in, :=~, !~ # @return [Boolean] true if actual value matches the expected value # @raise [Synvert::Core::NodeQuery::Compiler::InvalidOperatorError] if operator is invalid def match?(node, operator) raise InvalidOperatorError, "invalid operator #{operator}" unless valid_operator?(operator) case operator when :!= if expected_value.is_a?(::Array) actual = actual_value(node) !actual.is_a?(::Array) || actual.size != expected_value.size || actual.zip(expected_value).any? { |actual_node, expected_node| expected_node.match?(actual_node, :!=) } else actual_value(node) != expected_value end when :=~ actual_value(node) =~ expected_value when :!~ actual_value(node) !~ expected_value when :> actual_value(node) > expected_value when :>= actual_value(node) >= expected_value when :< actual_value(node) < expected_value when :<= actual_value(node) <= expected_value when :in expected_value.any? { |expected| expected.match?(node, :==) } when :not_in expected_value.all? { |expected| expected.match?(node, :!=) } when :includes actual_value(node).any? { |actual| actual == expected_value } else if expected_value.is_a?(::Array) actual = actual_value(node) actual.is_a?(::Array) && actual.size == expected_value.size && actual.zip(expected_value).all? { |actual_node, expected_node| expected_node.match?(actual_node, :==) } else actual_value(node) == expected_value end end end # Get the actual value from ast node. # @return if node is a {Parser::AST::Node}, return the node value, otherwise, return the node itself. def actual_value(node) if node.is_a?(::Parser::AST::Node) node.to_value else node end end # Get the expected value def expected_value @value end # Check if the operator is valid. # @return [Boolean] true if the operator is valid def valid_operator?(operator) valid_operators.include?(operator) end end end