Class: ConvertSdk::RuleManager Private

Inherits:
Object
  • Object
show all
Defined in:
lib/convert_sdk/rule_manager.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

The audience/segmentation rule walk — OR -> AND -> OR_WHEN — ported EXACTLY from the JS SDK packages/rules/src/rule-manager.ts. JS is the only truth here; the PHP port is quarantined (it diverges on the existence operators and on isIn case-folding — see Comparisons).

Structure & short-circuit order (mirrors rule-manager.ts:117-255):

* Top OR (+isRuleMatched+): for each AND-group, +match = process_and+;
return +true+ on the first matching group; after the loop return +match+
unless it is +false+ (so a {RuleError} sentinel propagates out). A missing
or empty +OR+ logs +RULE_NOT_VALID+ at warn and returns +false+.
* AND (+process_and+): for each OR_WHEN leaf-list, +match = process_or_when+;
return +match+ on the FIRST non-+true+ result (a +false+ or a sentinel
short-circuits the AND). All +true+ -> +true+. Missing/empty +AND+ ->
+RULE_NOT_VALID+ warn + +false+.
* OR_WHEN (+process_or_when+): for each leaf rule, +match = process_rule_item+;
return +true+ on the first match; after the loop return +match+ unless it
is +false+. Missing/empty +OR_WHEN+ -> +RULE_NOT_VALID+ warn + +false+.

FR22 safety invariant: EVERY empty/missing block shape returns false with a RULE_NOT_VALID warn — an empty audience excludes everyone, it never matches everyone.

The undefined-fallback (rule-manager.ts:323-333): when the data key for a leaf is ABSENT and the operator is +exists+/+doesNotExist+, the operator is invoked against Comparisons::UNDEFINED (JS undefined) so existence semantics hold for absent keys. Ruby models key-absence with the Comparisons::UNDEFINED marker because a plain nil means "present null value" (JS null), which is a different existence outcome.

RuleError propagation: a leaf that returns a RuleError sentinel propagates it up the walk via the non-true / non-false short-circuits above (Story 2.11 maps the surfaced sentinel to the public return).

Pure in-memory (NFR1). Rule options (+keys_case_sensitive+, negation) come from the injected Config, never inline. Valid-rule outcomes log at debug; invalid/empty shapes log RULE_NOT_VALID at warn (rule-manager.ts levels).

Constant Summary collapse

RULE_NOT_VALID =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

The RULE_NOT_VALID message — byte-identical to the JS SDK dictionary (+packages/enums/src/dictionary.ts:12+: "Provided rule is not valid"). Logged at warn for every empty/missing/invalid block, the FR22 exclusion signal.

"Provided rule is not valid"

Instance Method Summary collapse

Constructor Details

#initialize(config:, comparisons: Comparisons, log_manager: nil) ⇒ RuleManager

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Build a rule walker bound to a Config's rule options and a comparison processor.

Parameters:

  • config (Config)

    supplies keys_case_sensitive and negation.

  • comparisons (#dispatch) (defaults to: Comparisons)

    the operator processor (defaults to Comparisons); must expose dispatch (wire-name => method symbol) and respond to each mapped method as (value, test_against, negation).

  • log_manager (LogManager, nil) (defaults to: nil)

    optional logger; warn for invalid shapes, debug for valid-rule outcomes.



57
58
59
60
61
# File 'lib/convert_sdk/rule_manager.rb', line 57

def initialize(config:, comparisons: Comparisons, log_manager: nil)
  @keys_case_sensitive = config.keys_case_sensitive
  @comparisons = comparisons
  @log_manager = log_manager
end

Instance Method Details

#is_rule_matched(data, rule_set, log_entry = nil) ⇒ Boolean, Sentinel

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Walk a rule set against a data hash. The top OR level.

Parameters:

  • data (Hash{String=>Object})

    the key-value data to match.

  • rule_set (Hash)

    the OR/AND/OR_WHEN rule structure.

  • log_entry (String, nil) (defaults to: nil)

    an optional label for the entity being matched.

Returns:



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/convert_sdk/rule_manager.rb', line 70

def is_rule_matched(data, rule_set, log_entry = nil)
  or_groups = nonempty_block(rule_set, "OR")
  unless or_groups
    warn_rule_not_valid("RuleManager#is_rule_matched", log_entry)
    return false
  end

  match = false
  or_groups.each do |and_group|
    match = process_and(data, and_group)
    return true if match == true

    log_outcome("RuleManager#is_rule_matched", match, log_entry)
  end
  return match if match != false

  false
end