Class: ConvertSdk::SegmentsManager Private

Inherits:
Object
  • Object
show all
Defined in:
lib/convert_sdk/segments_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.

Visitor segmentation — the REPORTING-data layer that attaches segment ids to a visitor's StoreData in the JS SDK's wire shape (FR28–FR30). Ported from the JS SDK packages/segments/src/segments-manager.ts; the PHP reference is QUARANTINED here because it diverges on two wire keys.

PHP-divergence #2 — the wire-key quarantine (FR30)

JS SegmentsKeys (+segments-keys.ts:7-15+) emit camelCase: visitorType / customSegments. PHP SegmentsKeys.php:14-15 emit snake_case: visitor_type / custom_segments — a real, disk-verified divergence. Segment data rides the tracking payload's segments object (Epic 4 ApiManager emits the visitor's stored segments verbatim), so the wrong key would silently mis-filter every Ruby segment-report. Ruby follows JS: the seven report-segment keys, and customSegments in particular, are the ONLY ones persisted, as camelCase STRINGS at rest in StoreData. The SegmentsManager never produces the PHP variants; Story 3.2's quarantine spec asserts their absence.

The report-segment filter (#filter_report_segments, data-manager.ts:1180-1199)

Exactly seven keys are report-segments: country, browser, devices, source, campaign, visitorType, customSegments. #put_segments keeps ONLY these; every other key is silently DROPPED (JS routes them to a separate properties bucket the segments layer ignores) — IGNORE, not reject. Ruby adds a debug line naming the dropped keys (an observability addition; JS drops silently). A filter that leaves NOTHING is a no-op write (JS if (reportSegments)).

Custom-segment evaluation REUSES the rule engine (#select_custom_segments)

run_custom_segments does NOT introduce new rule logic. For each requested segment key it looks up the ConfigSegment entity (DataManager segments reader), evaluates that segment's rules against the supplied segment_rule data via RuleManager#is_rule_matched (so NEED_MORE_DATA and every operator semantic come for FREE), and — on a match — appends the segment's id to the visitor's stored customSegments list (deduped). A surfaced RuleError sentinel propagates out verbatim (mirrors JS +setCustomSegments+'s Object.values(RuleError).includes(...) early-return).

Persistence

All writes flow through the DataStoreManager atomic visitor-data merge (Story 2.1) into StoreData["segments"]. Stored data is string-keyed wire-world by design (so Epic 4's payload builder needs zero translation).

Zero-trace preview gate (qs-03 / RB-6)

#put_segments and #select_custom_segments accept an enable_storage: keyword (default true) that suppresses ONLY the persistence write above — filtering / rule MATCHING is never affected. Context#set_default_segments and Context#run_custom_segments thread !@preview through it so a preview-active context leaves zero trace in the store while still evaluating segment rules normally (mirrors JS SDK-6, segments-manager.ts:74-174).

Constant Summary collapse

CUSTOM_SEGMENTS =

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 customSegments wire key — byte-identical to JS SegmentsKeys.CUSTOM_SEGMENTS (+segments-keys.ts:14+). The visitor's matched custom-segment ids live under this key in StoreData["segments"].

"customSegments"
SEGMENTS_KEYS =

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 full report-segment key set — byte-identical to JS SegmentsKeys (+segments-keys.ts:7-15+). The report-segment filter is restricted to exactly these seven; +visitorType+/+customSegments+ are the JS wire keys that diverge from PHP's snake_case variants (FR30). The SINGLE source of the allowed set.

%w[
  country browser devices source campaign visitorType customSegments
].freeze

Instance Method Summary collapse

Constructor Details

#initialize(data_manager:, data_store_manager:, account_resolver:, project_resolver:, rule_manager:, log_manager: nil) ⇒ SegmentsManager

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.

Returns a new instance of SegmentsManager.

Parameters:

  • data_manager (DataManager)

    the config reader surface (supplies the ConfigSegment entities by key and the account/project store-key halves).

  • data_store_manager (DataStoreManager)

    the persistence port (atomic visitor-data merge into StoreData["segments"]).

  • account_resolver (#call)

    resolves the account id (store-key half).

  • project_resolver (#call)

    resolves the project id (store-key half).

  • rule_manager (RuleManager)

    the Epic 2 rule walker reused for custom-segment evaluation (never re-implemented here).

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

    optional logger; debug on misses/drops, warn on already-present ids.



82
83
84
85
86
87
88
89
90
# File 'lib/convert_sdk/segments_manager.rb', line 82

def initialize(data_manager:, data_store_manager:, account_resolver:,
               project_resolver:, rule_manager:, log_manager: nil)
  @data_manager = data_manager
  @data_store_manager = data_store_manager
  @account_resolver = 
  @project_resolver = project_resolver
  @rule_manager = rule_manager
  @log_manager = log_manager
end

Instance Method Details

#put_segments(visitor_id, segments, enable_storage: true) ⇒ void

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.

This method returns an undefined value.

Set default report-segments for a visitor (JS setDefaultSegments -> putSegments, context.ts:434-436 / segments-manager.ts:78-85).

The supplied segments are passed through #filter_report_segments (only the seven SEGMENTS_KEYS survive); a non-empty result is merged into the visitor's StoreData["segments"] via the atomic store merge. An all-dropped input is a no-op (JS if (reportSegments)).

Parameters:

  • visitor_id (String)
  • segments (Hash)

    the candidate report-segments (string-keyed wire shape).

  • enable_storage (Boolean) (defaults to: true)

    when false, suppress ONLY the persistence write below — the filtering above still runs identically. Threaded by Context#set_default_segments as !@preview (qs-03 / RB-6 zero-trace); mirrors JS +SegmentsManager#putSegments+'s enableStorage param (JS SDK-6, segments-manager.ts:74-89). Defaults to true (every pre-qs-03 caller is unaffected).



109
110
111
112
113
114
115
# File 'lib/convert_sdk/segments_manager.rb', line 109

def put_segments(visitor_id, segments, enable_storage: true)
  report_segments = filter_report_segments(segments)
  return if report_segments.empty?

  merge_segments(visitor_id, report_segments) if enable_storage
  nil
end

#select_custom_segments(visitor_id, segment_keys, segment_rule = nil, enable_storage: true) ⇒ Hash, ...

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.

Evaluate the named custom segments for a visitor and attach matching ids (JS selectCustomSegments -> setCustomSegments, segments-manager.ts:153-185).

Each requested key is resolved to a ConfigSegment via the DataManager segments reader; the segment's rules are walked against segment_rule by RuleManager#is_rule_matched. A surfaced RuleError sentinel propagates out verbatim (no attachment). Matching segment ids are appended to the visitor's stored customSegments list (deduped); an unknown key is skipped with a debug log.

Parameters:

  • visitor_id (String)
  • segment_keys (Array<String>)

    the segment keys to evaluate.

  • segment_rule (Hash, nil) (defaults to: nil)

    the visitor data the segment rules match against; nil attaches every resolved segment unconditionally (JS: if (!segmentRule || segmentsMatched)).

  • enable_storage (Boolean) (defaults to: true)

    when false, suppress ONLY the eventual #put_segments persistence write — rule MATCHING (and a propagated RuleError) is unaffected. Threaded by Context#run_custom_segments as !@preview (qs-03 / RB-6 zero-trace); mirrors JS +SegmentsManager#selectCustomSegments+'s enableStorage param (JS SDK-6, segments-manager.ts:156-174). Defaults to true.

Returns:

  • (Hash, Sentinel, nil)

    the updated segments hash, a propagated RuleError, or nil when nothing matched.



140
141
142
143
# File 'lib/convert_sdk/segments_manager.rb', line 140

def select_custom_segments(visitor_id, segment_keys, segment_rule = nil, enable_storage: true)
  segments = lookup_segments(segment_keys)
  set_custom_segments(visitor_id, segments, segment_rule, enable_storage: enable_storage)
end