Module: Ruby::Rego::Evaluator::OperatorEvaluator
- Defined in:
- lib/ruby/rego/evaluator/operator_evaluator.rb
Overview
Shared operator application helpers. rubocop:disable Metrics/ModuleLength
Constant Summary collapse
- EQUALITY_OPERATORS =
{ eq: lambda do |lhs, rhs| return UndefinedValue.new if lhs.is_a?(UndefinedValue) || rhs.is_a?(UndefinedValue) BooleanValue.new(lhs == rhs) end, neq: lambda do |lhs, rhs| return UndefinedValue.new if lhs.is_a?(UndefinedValue) || rhs.is_a?(UndefinedValue) BooleanValue.new(lhs != rhs) end }.freeze
- LOGICAL_OPERATORS =
{ and: ->(lhs, rhs) { BooleanValue.new(lhs.truthy? && rhs.truthy?) }, or: ->(lhs, rhs) { BooleanValue.new(lhs.truthy? || rhs.truthy?) } }.freeze
- COMPARISON_OPERATORS =
{ lt: ->(lhs, rhs) { lhs < rhs }, lte: ->(lhs, rhs) { lhs <= rhs }, gt: ->(lhs, rhs) { lhs > rhs }, gte: ->(lhs, rhs) { lhs >= rhs } }.freeze
- ARITHMETIC_OPERATORS =
{ plus: ->(lhs, rhs) { lhs + rhs }, minus: ->(lhs, rhs) { lhs - rhs }, mult: ->(lhs, rhs) { lhs * rhs }, div: ->(lhs, rhs) { lhs / rhs }, mod: ->(lhs, rhs) { lhs % rhs } }.freeze
- MEMBERSHIP_OPERATORS =
{ in: ->(lhs, rhs) { membership_value(lhs, rhs) } }.freeze
- UNARY_OPERATORS =
{ not: ->(operand) { BooleanValue.new(!operand.truthy?) }, minus: lambda do |operand| number = numeric_value(operand) number ? Value.from_ruby(-number) : UndefinedValue.new end }.freeze
Class Method Summary collapse
-
.apply(operator, left, right) ⇒ Value
rubocop:disable Metrics/MethodLength.
-
.apply_arithmetic(operator, left, right) ⇒ Object
-
.apply_comparison(operator, left, right) ⇒ Object
-
.apply_logical(operator, left, right) ⇒ Object
-
.apply_unary(operator, operand) ⇒ Value
-
.arithmetic_values(operator, left, right) ⇒ Object
-
.collection_values(value) ⇒ Object
:reek:DuplicateMethodCall.
-
.comparable?(left_value, right_value) ⇒ Boolean
-
.compare_values(left, right) ⇒ Object
-
.division_by_zero?(operator, right_value) ⇒ Boolean
-
.membership_value(lhs, rhs) ⇒ Object
-
.numeric_value(value) ⇒ Object
-
.undefined_operand?(lhs, rhs) ⇒ Boolean
Class Method Details
.apply(operator, left, right) ⇒ Value
rubocop:disable Metrics/MethodLength
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/ruby/rego/evaluator/operator_evaluator.rb', line 54 def self.apply(operator, left, right) handlers = [ -> { apply_logical(operator, left, right) }, -> { EQUALITY_OPERATORS[operator]&.call(left, right) }, -> { MEMBERSHIP_OPERATORS[operator]&.call(left, right) }, -> { apply_comparison(operator, left, right) }, -> { apply_arithmetic(operator, left, right) } ] handlers.each do |handler| value = handler.call return value if value end UndefinedValue.new end |
.apply_arithmetic(operator, left, right) ⇒ Object
94 95 96 97 98 99 |
# File 'lib/ruby/rego/evaluator/operator_evaluator.rb', line 94 def self.apply_arithmetic(operator, left, right) arithmetic = ARITHMETIC_OPERATORS[operator] return unless arithmetic arithmetic_values(operator, left, right, &arithmetic) end |
.apply_comparison(operator, left, right) ⇒ Object
87 88 89 90 91 92 |
# File 'lib/ruby/rego/evaluator/operator_evaluator.rb', line 87 def self.apply_comparison(operator, left, right) comparison = COMPARISON_OPERATORS[operator] return unless comparison compare_values(left, right, &comparison) end |
.apply_logical(operator, left, right) ⇒ Object
82 83 84 85 |
# File 'lib/ruby/rego/evaluator/operator_evaluator.rb', line 82 def self.apply_logical(operator, left, right) handler = LOGICAL_OPERATORS[operator] handler&.call(left, right) end |
.apply_unary(operator, operand) ⇒ Value
75 76 77 78 79 80 |
# File 'lib/ruby/rego/evaluator/operator_evaluator.rb', line 75 def self.apply_unary(operator, operand) handler = UNARY_OPERATORS[operator] return UndefinedValue.new unless handler handler.call(operand) end |
.arithmetic_values(operator, left, right) ⇒ Object
116 117 118 119 120 121 122 123 |
# File 'lib/ruby/rego/evaluator/operator_evaluator.rb', line 116 def self.arithmetic_values(operator, left, right) left_value = numeric_value(left) right_value = numeric_value(right) return UndefinedValue.new unless left_value && right_value return UndefinedValue.new if division_by_zero?(operator, right_value) Value.from_ruby(yield(left_value, right_value)) end |
.collection_values(value) ⇒ Object
:reek:DuplicateMethodCall
150 151 152 153 154 155 156 157 158 |
# File 'lib/ruby/rego/evaluator/operator_evaluator.rb', line 150 def self.collection_values(value) return UndefinedValue.new unless value.is_a?(ArrayValue) || value.is_a?(SetValue) || value.is_a?(ObjectValue) collection = value.value return collection if value.is_a?(ArrayValue) return collection.to_a if value.is_a?(SetValue) collection.keys.map { |key| Value.from_ruby(key) } end |
.comparable?(left_value, right_value) ⇒ Boolean
111 112 113 114 |
# File 'lib/ruby/rego/evaluator/operator_evaluator.rb', line 111 def self.comparable?(left_value, right_value) (left_value.is_a?(Numeric) && right_value.is_a?(Numeric)) || (left_value.is_a?(String) && right_value.is_a?(String)) end |
.compare_values(left, right) ⇒ Object
101 102 103 104 105 106 107 108 109 |
# File 'lib/ruby/rego/evaluator/operator_evaluator.rb', line 101 def self.compare_values(left, right) left_value = left.to_ruby right_value = right.to_ruby return UndefinedValue.new unless comparable?(left_value, right_value) BooleanValue.new(yield(left_value, right_value)) rescue ArgumentError UndefinedValue.new end |
.division_by_zero?(operator, right_value) ⇒ Boolean
125 126 127 |
# File 'lib/ruby/rego/evaluator/operator_evaluator.rb', line 125 def self.division_by_zero?(operator, right_value) %i[div mod].include?(operator) && right_value.zero? end |
.membership_value(lhs, rhs) ⇒ Object
136 137 138 139 140 141 142 143 |
# File 'lib/ruby/rego/evaluator/operator_evaluator.rb', line 136 def self.membership_value(lhs, rhs) return UndefinedValue.new if undefined_operand?(lhs, rhs) values = collection_values(rhs) return values if values.is_a?(UndefinedValue) BooleanValue.new(values.any? { |element| element == lhs }) end |
.numeric_value(value) ⇒ Object
129 130 131 132 133 134 |
# File 'lib/ruby/rego/evaluator/operator_evaluator.rb', line 129 def self.numeric_value(value) ruby = value.to_ruby return ruby if ruby.is_a?(Numeric) nil end |
.undefined_operand?(lhs, rhs) ⇒ Boolean
145 146 147 |
# File 'lib/ruby/rego/evaluator/operator_evaluator.rb', line 145 def self.undefined_operand?(lhs, rhs) lhs.is_a?(UndefinedValue) || rhs.is_a?(UndefinedValue) end |