Module: DecisionAgent::Dsl::Operators::NumericOperators

Defined in:
lib/decision_agent/dsl/operators/numeric_operators.rb

Overview

Handles numeric operators: between, modulo

Class Method Summary collapse

Class Method Details

.handle(op, actual_value, expected_value, param_cache: nil, param_cache_mutex: nil) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/decision_agent/dsl/operators/numeric_operators.rb', line 8

def self.handle(op, actual_value, expected_value, param_cache: nil, param_cache_mutex: nil)
  case op
  when "between"
    # Checks if numeric value is between min and max (inclusive)
    # expected_value should be [min, max] or {min: x, max: y}
    if actual_value.is_a?(Numeric)
      range = parse_range(expected_value, param_cache: param_cache, param_cache_mutex: param_cache_mutex)
      range ? actual_value.between?(range[:min], range[:max]) : false
    else
      false
    end

  when "modulo"
    # Checks if value modulo divisor equals remainder
    # expected_value should be [divisor, remainder] or {divisor: x, remainder: y}
    if actual_value.is_a?(Numeric)
      params = parse_modulo_params(expected_value, param_cache: param_cache, param_cache_mutex: param_cache_mutex)
      params ? (actual_value % params[:divisor]) == params[:remainder] : false
    else
      false
    end
  end
  # Returns nil if not handled by this module
end

.normalize_param_cache_key(value, prefix) ⇒ Object



114
115
116
# File 'lib/decision_agent/dsl/operators/numeric_operators.rb', line 114

def self.normalize_param_cache_key(value, prefix)
  Base.normalize_param_cache_key(value, prefix)
end

.normalize_params_to_hash(value, keys) ⇒ Object

Use Base utilities



110
111
112
# File 'lib/decision_agent/dsl/operators/numeric_operators.rb', line 110

def self.normalize_params_to_hash(value, keys)
  Base.normalize_params_to_hash(value, keys)
end

.parse_modulo_params(value, param_cache: nil, param_cache_mutex: nil) ⇒ Object

Parse modulo parameters Accepts [divisor, remainder] or x, remainder: y Converts arrays to hash for consistency and better performance



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/decision_agent/dsl/operators/numeric_operators.rb', line 74

def self.parse_modulo_params(value, param_cache: nil, param_cache_mutex: nil)
  # Normalize to hash if array (for large params, hash is more efficient)
  normalized_value = normalize_params_to_hash(value, i[divisor remainder])

  # Use provided caches or access ConditionEvaluator class variables
  cache = param_cache
  mutex = param_cache_mutex

  if cache.nil? || mutex.nil?
    cache = ConditionEvaluator.instance_variable_get(:@param_cache)
    mutex = ConditionEvaluator.instance_variable_get(:@param_cache_mutex)
  end

  cache_key = normalize_param_cache_key(normalized_value, "modulo")

  # Fast path: check cache without lock
  cached = cache[cache_key]
  return cached if cached

  # Slow path: parse and cache
  mutex.synchronize do
    cache[cache_key] ||= parse_modulo_params_impl(normalized_value)
  end
end

.parse_modulo_params_impl(value) ⇒ Object



99
100
101
102
103
104
105
106
107
# File 'lib/decision_agent/dsl/operators/numeric_operators.rb', line 99

def self.parse_modulo_params_impl(value)
  return nil unless value.is_a?(Hash)

  divisor = value[:divisor] || value["divisor"]
  remainder = value[:remainder] || value["remainder"]
  return nil unless divisor && !remainder.nil?

  { divisor: divisor, remainder: remainder }
end

.parse_range(value, param_cache: nil, param_cache_mutex: nil) ⇒ Object

Parse range for 'between' operator Accepts [min, max] or x, max: y Converts arrays to hash for consistency and better performance



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/decision_agent/dsl/operators/numeric_operators.rb', line 36

def self.parse_range(value, param_cache: nil, param_cache_mutex: nil)
  # Normalize to hash if array (for large params, hash is more efficient)
  normalized_value = normalize_params_to_hash(value, i[min max])

  # Use provided caches or access ConditionEvaluator class variables
  cache = param_cache
  mutex = param_cache_mutex

  if cache.nil? || mutex.nil?
    cache = ConditionEvaluator.instance_variable_get(:@param_cache)
    mutex = ConditionEvaluator.instance_variable_get(:@param_cache_mutex)
  end

  cache_key = normalize_param_cache_key(normalized_value, "range")

  # Fast path: check cache without lock
  cached = cache[cache_key]
  return cached if cached

  # Slow path: parse and cache
  mutex.synchronize do
    cache[cache_key] ||= parse_range_impl(normalized_value)
  end
end

.parse_range_impl(value) ⇒ Object



61
62
63
64
65
66
67
68
69
# File 'lib/decision_agent/dsl/operators/numeric_operators.rb', line 61

def self.parse_range_impl(value)
  return nil unless value.is_a?(Hash)

  min = value[:min] || value["min"]
  max = value[:max] || value["max"]
  return nil unless min && max

  { min: min, max: max }
end