Class: Featureflip::Evaluation::ConditionEvaluator
- Inherits:
-
Object
- Object
- Featureflip::Evaluation::ConditionEvaluator
- Defined in:
- lib/featureflip/evaluation/condition_evaluator.rb
Constant Summary collapse
- REGEX_TIMEOUT_SECONDS =
Per-regex match timeout (seconds) for MatchesRegex, mirroring the engine’s 100ms RegexMatchTimeout guard against catastrophic backtracking / ReDoS (#1460). Requires Ruby >= 3.2 (gemspec floor), which added the Regexp ‘timeout:` keyword.
0.1
Instance Method Summary collapse
- #evaluate_condition(condition, context) ⇒ Object
- #evaluate_condition_groups(condition_groups, context) ⇒ Object
- #evaluate_conditions(conditions, logic, context) ⇒ Object
Instance Method Details
#evaluate_condition(condition, context) ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/featureflip/evaluation/condition_evaluator.rb', line 12 def evaluate_condition(condition, context) attr_value = context[condition.attribute] return condition.negate if attr_value.nil? # Issue #1458: when the attribute is a native numeric (Integer/Float — # Ruby's `true`/`false` are NOT Numeric, so booleans are naturally # excluded), the equality-family operators coerce the condition values to # numbers and compare numerically, so 1.0 matches "1". This mirrors the # engine's type-aware path and runs BEFORE stringification — a String # attribute (even "1.0") stays on the string path below. if attr_value.is_a?(Numeric) && NUMERIC_EQUALITY_OPERATORS.include?(condition.operator) return evaluate_numeric_equality(condition, attr_value) end # Pass the raw (case-preserved) strings to the operator dispatcher. # Most operators compare case-insensitively and downcase internally, but # the semver operators rely on case-sensitive prerelease precedence # (semver §11), so the original casing must survive to that point. str_value = attr_value.to_s targets = condition.values.map(&:to_s) result = evaluate_operator(condition.operator, str_value, targets) condition.negate ? !result : result end |
#evaluate_condition_groups(condition_groups, context) ⇒ Object
48 49 50 51 52 53 54 |
# File 'lib/featureflip/evaluation/condition_evaluator.rb', line 48 def evaluate_condition_groups(condition_groups, context) return true if condition_groups.nil? || condition_groups.empty? condition_groups.all? do |group| evaluate_conditions(group.conditions, group.operator, context) end end |
#evaluate_conditions(conditions, logic, context) ⇒ Object
38 39 40 41 42 43 44 45 46 |
# File 'lib/featureflip/evaluation/condition_evaluator.rb', line 38 def evaluate_conditions(conditions, logic, context) return true if conditions.empty? if logic == "And" conditions.all? { |c| evaluate_condition(c, context) } else conditions.any? { |c| evaluate_condition(c, context) } end end |