kameleoon-client-ruby 3.14.0 → 3.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b5566ec9ff02ebb63ff3ee337f4c26fc0c229f2de8df0893fe85dc3f83fbc0ce
4
- data.tar.gz: fcd11bacbaead7a0c357a0fd4828fb6c4b7347ebf1fab728f4e00882b0224dc7
3
+ metadata.gz: 07240065fc16f98169c01fd4367321b2f633d79373f293b0bcf110f68d920d46
4
+ data.tar.gz: 52b83806f28aa0035eb8df2db89f84b98b774e2a53b0fd8a7c5abd71b0a59ac4
5
5
  SHA512:
6
- metadata.gz: 78418ebd561b9d1fe2639751d0dae68a875a4a76f4782ac079fe2f3f3c6e2b7466c41cb762e978b4895973a97ddf4940b10171d36c2695a565ed2e1b66445f53
7
- data.tar.gz: b91b577c23c13547d78c09c98a2c39bb788a314b280b50c57bf1cc25891dd74747127aec2bc14b0a5a4908a2cde2d0e2089ec13c6f5200087b7c52bd80b7a68f
6
+ metadata.gz: 88e8da4ec50eca784dd49b5861f373d84e60eaa521894d095104c10d6d469cb8e20d4fbf98416a473790fe77842411e4021beed153a4a4bb784603b90360abd0
7
+ data.tar.gz: 9068a2d4b8dfaff1020933c9e38e133965486ef0ddc722db19dd7eeee28a0327926d4d3beb1b17460615da176620699a2f7dcc5ada1dc63db4e6696aaa080131
@@ -11,9 +11,9 @@ require 'kameleoon/targeting/models'
11
11
  module Kameleoon
12
12
  module Configuration
13
13
  class DataFile
14
- attr_reader :last_modified, :settings, :feature_flags, :me_groups, :has_any_targeted_delivery_rule,
15
- :feature_flag_by_id, :rule_by_segment_id, :rule_info_by_exp_id, :variation_by_id, :custom_data_info,
16
- :experiment_ids_with_js_css_variable, :holdout
14
+ attr_reader :last_modified, :settings, :segments, :audience_tracking_segments, :feature_flags, :me_groups,
15
+ :has_any_targeted_delivery_rule, :feature_flag_by_id, :rule_info_by_exp_id, :variation_by_id,
16
+ :custom_data_info, :experiment_ids_with_js_css_variable, :holdout
17
17
 
18
18
  def to_s
19
19
  'DataFile{' \
@@ -70,9 +70,9 @@ module Kameleoon
70
70
  def init(configuration)
71
71
  Logging::KameleoonLogger.debug('CALL: DataFile.init(configuration: %s)', configuration)
72
72
  @settings = Settings.new(configuration['configuration'])
73
- segments = parse_segments(configuration)
73
+ @segments, @audience_tracking_segments = parse_segments(configuration)
74
74
  @custom_data_info = CustomDataInfo.new(configuration['customData'])
75
- @feature_flags = parse_feature_flags(configuration, segments, @custom_data_info)
75
+ @feature_flags = parse_feature_flags(configuration, @custom_data_info)
76
76
  @me_groups = make_me_groups(@feature_flags)
77
77
  @has_any_targeted_delivery_rule = any_targeted_delivery_rule?
78
78
  @holdout = Experiment.from_json(configuration['holdout']) if configuration.include?('holdout')
@@ -80,15 +80,20 @@ module Kameleoon
80
80
  end
81
81
 
82
82
  def parse_segments(configuration)
83
- configuration['segments'].to_h do |raw_seg|
83
+ audience_tracking_segments = []
84
+ segments = configuration['segments'].to_h do |raw_seg|
84
85
  seg = Targeting::Segment.new(raw_seg)
86
+ audience_tracking_segments.push(seg) if seg.audience_tracking
85
87
  [seg.id, seg]
86
88
  end
89
+ segments.freeze
90
+ audience_tracking_segments.freeze
91
+ [segments, audience_tracking_segments]
87
92
  end
88
93
 
89
- def parse_feature_flags(configuration, segments, cdi)
94
+ def parse_feature_flags(configuration, cdi)
90
95
  configuration['featureFlags'].to_h do |raw_ff|
91
- ff = FeatureFlag.new(raw_ff, segments, cdi)
96
+ ff = FeatureFlag.new(raw_ff, @segments, cdi)
92
97
  [ff.feature_key, ff]
93
98
  end
94
99
  end
@@ -99,7 +104,6 @@ module Kameleoon
99
104
 
100
105
  def collect_indices
101
106
  @feature_flag_by_id = {}
102
- @rule_by_segment_id = {}
103
107
  @rule_info_by_exp_id = {}
104
108
  @variation_by_id = {}
105
109
  @experiment_ids_with_js_css_variable = Set.new
@@ -110,7 +114,6 @@ module Kameleoon
110
114
 
111
115
  has_feature_flag_variable_js_css = feature_flag_variable_js_css?(feature_flag)
112
116
  feature_flag.rules.each do |rule|
113
- @rule_by_segment_id[rule.segment_id] = rule
114
117
  @rule_info_by_exp_id[rule.experiment.id] = RuleInfo.new(feature_flag, rule)
115
118
  rule.experiment.variations_by_exposition.each do |variation|
116
119
  @variation_by_id[variation.variation_id] = variation
@@ -119,7 +122,6 @@ module Kameleoon
119
122
  end
120
123
  end
121
124
  @feature_flag_by_id.freeze
122
- @rule_by_segment_id.freeze
123
125
  @variation_by_id.freeze
124
126
  @experiment_ids_with_js_css_variable.freeze
125
127
  end
@@ -19,6 +19,7 @@ module Kameleoon
19
19
  OPERATING_SYSTEM = 'OPERATING_SYSTEM'
20
20
  GEOLOCATION = 'GEOLOCATION'
21
21
  VISITOR_VISITS = 'VISITOR_VISITS'
22
+ TARGETED_SEGMENT = 'TARGETED_SEGMENT'
22
23
  end
23
24
 
24
25
  module DataState
@@ -10,6 +10,7 @@ require 'kameleoon/data/device'
10
10
  require 'kameleoon/data/kcs_heat'
11
11
  require 'kameleoon/data/page_view'
12
12
  require 'kameleoon/data/personalization'
13
+ require 'kameleoon/data/targeted_segment'
13
14
  require 'kameleoon/data/unique_identifier'
14
15
  require 'kameleoon/data/user_agent'
15
16
  require 'kameleoon/data/manager/assigned_variation'
@@ -186,6 +187,14 @@ module Kameleoon
186
187
  personalizations
187
188
  end
188
189
 
190
+ def targeted_segments
191
+ targeted_segments = @data.targeted_segments
192
+ Logging::KameleoonLogger.debug(
193
+ 'CALL/RETURN: Visitor.targeted_segments -> (targeted_segments: %s)', targeted_segments
194
+ )
195
+ targeted_segments
196
+ end
197
+
189
198
  def get_forced_feature_variation(feature_key)
190
199
  Logging::KameleoonLogger.debug("CALL: Visitor.get_forced_feature_variation(feature_key: '%s')", feature_key)
191
200
  variation = @data.get_from_map(@data.simulated_variations, feature_key)
@@ -241,6 +250,8 @@ module Kameleoon
241
250
  @data.add_variation(data, overwrite)
242
251
  when Personalization
243
252
  @data.add_personalization(data, overwrite)
253
+ when TargetedSegment
254
+ @data.add_targeted_segment(data)
244
255
  when ForcedFeatureVariation
245
256
  @data.add_forced_feature_variation(data)
246
257
  when ForcedExperimentVariation
@@ -329,6 +340,7 @@ module Kameleoon
329
340
  @custom_data_map&.each { |_, cd| blk.call(cd) }
330
341
  @page_view_visits&.each { |_, pvv| blk.call(pvv.page_view) }
331
342
  @variations&.each { |_, av| blk.call(av) }
343
+ @targeted_segments&.each { |_, ts| blk.call(ts) }
332
344
  @conversions&.each { |c| blk.call(c) }
333
345
  end
334
346
  end
@@ -344,8 +356,9 @@ module Kameleoon
344
356
  count += 1 unless @visitor_visits.nil?
345
357
  count += @custom_data_map.size unless @custom_data_map.nil?
346
358
  count += @page_view_visits.size unless @page_view_visits.nil?
347
- count += @conversions.size unless @conversions.nil?
348
359
  count += @variations.size unless @variations.nil?
360
+ count += @targeted_segments.size unless @targeted_segments.nil?
361
+ count += @conversions.size unless @conversions.nil?
349
362
  end
350
363
  Logging::KameleoonLogger.debug('RETURN: VisitorData.count_sendable_data -> (count: %s)', count)
351
364
  count
@@ -371,6 +384,10 @@ module Kameleoon
371
384
  DataMapStorage.new(@mutex, @personalizations)
372
385
  end
373
386
 
387
+ def targeted_segments
388
+ DataMapStorage.new(@mutex, @targeted_segments)
389
+ end
390
+
374
391
  def set_device(device, overwrite)
375
392
  @device = device if overwrite || @device.nil?
376
393
  end
@@ -389,6 +406,11 @@ module Kameleoon
389
406
  end
390
407
  end
391
408
 
409
+ def add_targeted_segment(targeted_segment)
410
+ @targeted_segments ||= {}
411
+ @targeted_segments[targeted_segment.id] = targeted_segment
412
+ end
413
+
392
414
  def set_browser(browser, overwrite)
393
415
  @browser = browser if overwrite || @browser.nil?
394
416
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kameleoon/data/data'
4
+ require 'kameleoon/network/uri_helper'
5
+
6
+ module Kameleoon
7
+ class TargetedSegment < DuplicationUnsafeData
8
+ EVENT_TYPE = 'targetingSegment'
9
+
10
+ attr_reader :id
11
+
12
+ def initialize(id)
13
+ super(DataType::TARGETED_SEGMENT)
14
+ @id = id
15
+ end
16
+
17
+ def obtain_full_post_text_line
18
+ params = {
19
+ eventType: EVENT_TYPE,
20
+ id: @id,
21
+ nonce: nonce
22
+ }
23
+ Network::UriHelper.encode_query(params)
24
+ end
25
+
26
+ def to_s
27
+ "TargetedSegment{id:#{@id}}"
28
+ end
29
+ end
30
+ end
@@ -758,6 +758,27 @@ module Kameleoon
758
758
  )
759
759
  end
760
760
 
761
+ ##
762
+ # Evaluates the visitor against all available Audiences Explorer segments and tracks those that match.
763
+ # A detailed analysis of segment performance can then be performed directly in Audiences Explorer.
764
+ #
765
+ # @param [String] visitor_code The unique visitor code identifying the visitor.
766
+ #
767
+ # @raise [Kameleoon::Exception::VisitorCodeInvalid] The provided **visitor code** is invalid.
768
+ def evaluate_audiences(visitor_code)
769
+ Logging::KameleoonLogger.info("CALL: KameleoonClient.evaluate_audiences(visitor_code: '%s')", visitor_code)
770
+ Utils::VisitorCode.validate(visitor_code)
771
+ segments = @data_manager.data_file.audience_tracking_segments.select do |seg|
772
+ check_targeting(visitor_code, nil, seg)
773
+ end
774
+ unless segments.empty?
775
+ segments.map! { |seg| TargetedSegment.new(seg.id) }
776
+ @visitor_manager.add_data(visitor_code, *segments)
777
+ end
778
+ @tracking_manager.add_visitor_code(visitor_code)
779
+ Logging::KameleoonLogger.info("RETURN: KameleoonClient.evaluate_audiences(visitor_code: '%s')", visitor_code)
780
+ end
781
+
761
782
  private
762
783
 
763
784
  HYBRID_EXPIRATION_TIME = 5
@@ -904,8 +925,8 @@ module Kameleoon
904
925
  # nil
905
926
  # end
906
927
 
907
- def check_targeting(visitor_code, campaign_id, exp_ff_rule)
908
- @targeting_manager.check_targeting(visitor_code, campaign_id, exp_ff_rule)
928
+ def check_targeting(visitor_code, campaign_id, segment)
929
+ @targeting_manager.check_targeting(visitor_code, campaign_id, segment)
909
930
  end
910
931
 
911
932
  def get_variation_info(visitor_code, feature_flag, track)
@@ -1106,7 +1127,7 @@ module Kameleoon
1106
1127
  break
1107
1128
  end
1108
1129
  # check if visitor is targeted for rule, else next rule
1109
- next unless check_targeting(visitor_code, rule.experiment.id, rule)
1130
+ next unless check_targeting(visitor_code, rule.experiment.id, rule.targeting_segment)
1110
1131
 
1111
1132
  unless forced_variation.nil?
1112
1133
  # Forcing experiment variation in targeting-only mode
@@ -19,10 +19,10 @@ module Kameleoon
19
19
  private
20
20
 
21
21
  def check_targeting(segment_info)
22
- rule = segment_info.data_file.rule_by_segment_id[@segment_id]
23
- return false unless rule.is_a?(Kameleoon::Configuration::Rule)
22
+ segment = segment_info.data_file.segments[@segment_id]
23
+ return false if segment.nil?
24
24
 
25
- rule.targeting_segment.check_tree(->(type) { segment_info.condition_data(type) })
25
+ segment.check_tree(->(type) { segment_info.condition_data(type) })
26
26
  end
27
27
  end
28
28
 
@@ -8,10 +8,10 @@ module Kameleoon
8
8
  module Targeting
9
9
  class Segment
10
10
  include TreeBuilder
11
- attr_accessor :id, :tree
11
+ attr_accessor :id, :tree, :audience_tracking
12
12
 
13
13
  def to_s
14
- @tree.to_s
14
+ "Segment{id:#{@id},audience_tracking:#{@audience_tracking}}"
15
15
  end
16
16
 
17
17
  def initialize(*args)
@@ -28,6 +28,7 @@ module Kameleoon
28
28
  if hash['conditionsData'].nil?
29
29
  raise Kameleoon::Exception::NotFound.new(hash['conditionsData']), 'hash[\'conditionsData\']'
30
30
  end
31
+ @audience_tracking = hash['audienceTracking'] || false
31
32
  @tree = create_tree(hash['conditionsData'])
32
33
  elsif args.length == 2
33
34
  @id = args[0]
@@ -19,25 +19,19 @@ module Kameleoon
19
19
  @visitor_manager = visitor_manager
20
20
  end
21
21
 
22
- def check_targeting(visitor_code, campaign_id, exp_ff_rule)
22
+ def check_targeting(visitor_code, campaign_id, segment)
23
23
  Logging::KameleoonLogger.debug(
24
- "CALL: TargetingManager.check_targeting(visitor_code: '%s', campaign_id: %s, exp_ff_rule: %s)",
25
- visitor_code, campaign_id, exp_ff_rule
24
+ "CALL: TargetingManager.check_targeting(visitor_code: '%s', campaign_id: %s, segment: %s)",
25
+ visitor_code, campaign_id, segment
26
26
  )
27
- segment = exp_ff_rule.targeting_segment
28
- if segment.nil?
29
- Logging::KameleoonLogger.debug(
30
- "RETURN: TargetingManager.check_targeting(visitor_code: '%s', campaign_id: %s, exp_ff_rule: %s) -> " \
31
- '(targeting: true)', visitor_code, campaign_id, exp_ff_rule
32
- )
33
- return true
27
+ targeting = true
28
+ unless segment.nil?
29
+ visitor = @visitor_manager.get_visitor(visitor_code)
30
+ targeting = segment.check_tree(->(type) { get_condition_data(type, visitor, visitor_code, campaign_id) })
34
31
  end
35
-
36
- visitor = @visitor_manager.get_visitor(visitor_code)
37
- targeting = segment.check_tree(->(type) { get_condition_data(type, visitor, visitor_code, campaign_id) })
38
32
  Logging::KameleoonLogger.debug(
39
- "RETURN: TargetingManager.check_targeting(visitor_code: '%s', campaign_id: %s, exp_ff_rule: %s) -> " \
40
- '(targeting: %s)', visitor_code, campaign_id, exp_ff_rule, targeting
33
+ "RETURN: TargetingManager.check_targeting(visitor_code: '%s', campaign_id: %s, segment: %s) -> " \
34
+ '(targeting: %s)', visitor_code, campaign_id, segment, targeting
41
35
  )
42
36
  targeting
43
37
  end
@@ -86,7 +80,9 @@ module Kameleoon
86
80
  when ConditionType::TARGET_PERSONALIZATION
87
81
  condition_data = TargetPersonalizationInfo.new(visitor&.personalizations)
88
82
  when ConditionType::EXCLUSIVE_EXPERIMENT
89
- condition_data = ExclusiveExperimentInfo.new(campaign_id, visitor&.variations, visitor&.personalizations)
83
+ unless campaign_id.nil?
84
+ condition_data = ExclusiveExperimentInfo.new(campaign_id, visitor&.variations, visitor&.personalizations)
85
+ end
90
86
  when ConditionType::FIRST_VISIT,
91
87
  ConditionType::LAST_VISIT,
92
88
  ConditionType::VISITS,
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kameleoon
4
- SDK_VERSION = '3.14.0'
4
+ SDK_VERSION = '3.15.0'
5
5
  SDK_NAME = 'RUBY'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kameleoon-client-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.14.0
4
+ version: 3.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kameleoon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-06-27 00:00:00.000000000 Z
11
+ date: 2025-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: em-http-request
@@ -108,6 +108,7 @@ files:
108
108
  - lib/kameleoon/data/operating_system.rb
109
109
  - lib/kameleoon/data/page_view.rb
110
110
  - lib/kameleoon/data/personalization.rb
111
+ - lib/kameleoon/data/targeted_segment.rb
111
112
  - lib/kameleoon/data/unique_identifier.rb
112
113
  - lib/kameleoon/data/user_agent.rb
113
114
  - lib/kameleoon/data/visitor_visits.rb