kameleoon-client-ruby 3.14.0 → 3.16.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: 3df9ec4718c2a87cff0c2ad6344d43ca3ad095531badca20a6ac1bc0c1db9126
4
+ data.tar.gz: ba946333858defdeedccfdd3468aab44eeae80a8e9f4f407b68db4b4701a47bb
5
5
  SHA512:
6
- metadata.gz: 78418ebd561b9d1fe2639751d0dae68a875a4a76f4782ac079fe2f3f3c6e2b7466c41cb762e978b4895973a97ddf4940b10171d36c2695a565ed2e1b66445f53
7
- data.tar.gz: b91b577c23c13547d78c09c98a2c39bb788a314b280b50c57bf1cc25891dd74747127aec2bc14b0a5a4908a2cde2d0e2089ec13c6f5200087b7c52bd80b7a68f
6
+ metadata.gz: d01c49dabf864637880c54117b74580d8b9f08567fe3755dbdaf3483e8da91e44c46041bfc537de1efb9bbcc969fdf106a273a235e4b933ccf85da74cafa00f2
7
+ data.tar.gz: 287fc1558d2f377db0cbe20b31069fa216bdffa5cc640286897895bb7a18903f2b1f706c1697c37ac1f1af0fe1e9b88a7beded87aaa056ec810ef571f77793d9
@@ -14,13 +14,18 @@ module Kameleoon
14
14
  @local_only = Set[]
15
15
  @visitor_scope = Set[]
16
16
  @custom_data_index_by_id = {}
17
+ @custom_data_index_by_name = {}
17
18
  unless hashes.nil?
18
19
  for hash in hashes
19
20
  index = hash['index']
20
21
  @local_only.add(index) if hash['localOnly']
21
22
  @visitor_scope.add(index) if hash['scope'] == SCOPE_VISITOR
22
- id = hash['id']
23
- @custom_data_index_by_id[id] = index if id && index
23
+ if index
24
+ id = hash['id']
25
+ name = hash['name']
26
+ @custom_data_index_by_id[id] = index if id
27
+ @custom_data_index_by_name[name] = index if name
28
+ end
24
29
  if hash['isMappingIdentifier']
25
30
  unless @mapping_identifier_index.nil?
26
31
  Logging::KameleoonLogger.warning('More than one mapping identifier is set. Undefined behavior ' \
@@ -48,8 +53,12 @@ module Kameleoon
48
53
  @custom_data_index_by_id[custom_data_id]
49
54
  end
50
55
 
56
+ def get_custom_data_index_by_name(custom_data_name)
57
+ @custom_data_index_by_name[custom_data_name]
58
+ end
59
+
51
60
  def self.mapping_identifier?(custom_data_info, custom_data)
52
- !custom_data_info.nil? && (custom_data.id == custom_data_info.mapping_identifier_index) && \
61
+ !custom_data_info.nil? && (custom_data.index == custom_data_info.mapping_identifier_index) && \
53
62
  !(custom_data.values.empty? || custom_data.values[0].empty?)
54
63
  end
55
64
  end
@@ -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
@@ -8,50 +8,88 @@ require_relative 'data'
8
8
  module Kameleoon
9
9
  # Represents any custom data for targeting conditions
10
10
  class CustomData < DuplicationUnsafeData
11
- attr_reader :id, :values
11
+ attr_reader :index, :name, :values, :overwrite
12
12
 
13
13
  def to_s
14
- "CustomData{id:#{@id},values:#{@values}}"
14
+ "CustomData{index:#{@index},name:'#{@name}',values:#{@values},overwrite:#{@overwrite}}"
15
15
  end
16
16
 
17
- # @param [Integer] id Id of the custom data
17
+ # @param [Integer] index Index of the custom data
18
18
  # @param [String] value Value of the custom data
19
19
  # @param [Array] values Array of values of the custom data
20
+ # @param [Boolean] overwrite Flag to explicitly control how the values are stored and how they appear in reports
21
+ #
22
+ # @overload
23
+ # @param [String] name Custom Data name, can be used instead of Custom Data index
24
+ # @param [String] value Value of the custom data
25
+ # @param [Array] values Array of values of the custom data
26
+ # @param [Boolean] overwrite Flag to explicitly control how the values are stored and how they appear in reports
20
27
  #
21
28
  # @overload
22
29
  # @param [Hash] hash Json value encoded in a hash.
23
30
  # rubocop:disable Metrics/MethodLength
24
- def initialize(arg0, *args)
31
+ def initialize(arg0, *args, overwrite: true)
25
32
  super(DataType::CUSTOM)
26
33
  if arg0.is_a?(Hash)
27
34
  hash = arg0
28
- id = hash['id']
29
- raise Kameleoon::Exception::NotFound.new('id'), '"id" is mandatory' if id.nil?
35
+ index = hash['index'] || hash['id']
36
+ name = hash['name']
37
+ if index.nil? && name.nil?
38
+ raise Kameleoon::Exception::NotFound.new('index/id/name'), '"index/id/name" is mandatory'
39
+ end
30
40
 
31
- @id = id
41
+ @index = index || -1
42
+ @name = name
32
43
  values = hash['values']
33
44
  raise Kameleoon::Exception::NotFound.new('values'), '"values" is mandatory' if values.nil?
34
45
 
35
46
  @values = values.is_a?(Array) ? values.dup : [values]
47
+ @overwrite = hash.fetch('overwrite', true)
36
48
  else
37
- @id = arg0
49
+ case arg0
50
+ when Integer
51
+ @index = arg0
52
+ when String
53
+ @index = -1
54
+ @name = arg0
55
+ else
56
+ raise Kameleoon::Exception.new('Unexpected arg0 type'), 'Unexpected arg0 type'
57
+ end
38
58
  @values = args
59
+ @overwrite = overwrite
39
60
  end
40
61
 
41
- return if @id.is_a?(Integer)
62
+ return if @index.is_a?(Integer)
42
63
 
43
- Logging::KameleoonLogger.warning("CustomData field 'id' must be of 'Integer' type")
44
- @id = @id.is_a?(String) ? @id.to_i : -1
64
+ Logging::KameleoonLogger.warning("CustomData field 'index' must be of 'Integer' type")
65
+ @index = @index.is_a?(String) ? @index.to_i : -1
45
66
  end
46
67
  # rubocop:enable Metrics/MethodLength
47
68
 
69
+ def named_to_indexed(index)
70
+ CustomData.new(
71
+ {
72
+ 'index' => index,
73
+ 'name' => @name,
74
+ 'values' => @values,
75
+ 'overwrite' => @overwrite
76
+ }
77
+ )
78
+ end
79
+
80
+ ##
81
+ # DEPRECATED. Please use `index` instead.
82
+ def id
83
+ @index
84
+ end
85
+
48
86
  def obtain_full_post_text_line
49
87
  str_values = JSON.generate(Hash[@values.collect { |k| [k, 1] }])
50
88
  params = {
51
89
  eventType: 'customData',
52
- index: @id,
90
+ index: @index,
53
91
  valuesCountMap: str_values,
54
- overwrite: 'true',
92
+ overwrite: @overwrite,
55
93
  nonce: nonce
56
94
  }
57
95
  Kameleoon::Network::UriHelper.encode_query(params)
@@ -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)
@@ -234,6 +243,8 @@ module Kameleoon
234
243
  Logging::KameleoonLogger.debug('CALL: Visitor.add_data(args: %s, overwrite: %s)', args, overwrite)
235
244
  @data.mutex.with_write_lock do
236
245
  args.each do |data|
246
+ next if data.nil?
247
+
237
248
  case data
238
249
  when UserAgent
239
250
  @data.user_agent = data.value
@@ -241,6 +252,8 @@ module Kameleoon
241
252
  @data.add_variation(data, overwrite)
242
253
  when Personalization
243
254
  @data.add_personalization(data, overwrite)
255
+ when TargetedSegment
256
+ @data.add_targeted_segment(data)
244
257
  when ForcedFeatureVariation
245
258
  @data.add_forced_feature_variation(data)
246
259
  when ForcedExperimentVariation
@@ -329,6 +342,7 @@ module Kameleoon
329
342
  @custom_data_map&.each { |_, cd| blk.call(cd) }
330
343
  @page_view_visits&.each { |_, pvv| blk.call(pvv.page_view) }
331
344
  @variations&.each { |_, av| blk.call(av) }
345
+ @targeted_segments&.each { |_, ts| blk.call(ts) }
332
346
  @conversions&.each { |c| blk.call(c) }
333
347
  end
334
348
  end
@@ -344,8 +358,9 @@ module Kameleoon
344
358
  count += 1 unless @visitor_visits.nil?
345
359
  count += @custom_data_map.size unless @custom_data_map.nil?
346
360
  count += @page_view_visits.size unless @page_view_visits.nil?
347
- count += @conversions.size unless @conversions.nil?
348
361
  count += @variations.size unless @variations.nil?
362
+ count += @targeted_segments.size unless @targeted_segments.nil?
363
+ count += @conversions.size unless @conversions.nil?
349
364
  end
350
365
  Logging::KameleoonLogger.debug('RETURN: VisitorData.count_sendable_data -> (count: %s)', count)
351
366
  count
@@ -371,6 +386,10 @@ module Kameleoon
371
386
  DataMapStorage.new(@mutex, @personalizations)
372
387
  end
373
388
 
389
+ def targeted_segments
390
+ DataMapStorage.new(@mutex, @targeted_segments)
391
+ end
392
+
374
393
  def set_device(device, overwrite)
375
394
  @device = device if overwrite || @device.nil?
376
395
  end
@@ -389,14 +408,19 @@ module Kameleoon
389
408
  end
390
409
  end
391
410
 
411
+ def add_targeted_segment(targeted_segment)
412
+ @targeted_segments ||= {}
413
+ @targeted_segments[targeted_segment.id] = targeted_segment
414
+ end
415
+
392
416
  def set_browser(browser, overwrite)
393
417
  @browser = browser if overwrite || @browser.nil?
394
418
  end
395
419
 
396
420
  def add_custom_data(custom_data, overwrite)
397
421
  @custom_data_map ||= {}
398
- if overwrite || !@custom_data_map.include?(custom_data.id)
399
- @custom_data_map[custom_data.id] = custom_data
422
+ if overwrite || !@custom_data_map.include?(custom_data.index)
423
+ @custom_data_map[custom_data.index] = custom_data
400
424
  end
401
425
  end
402
426
 
@@ -77,21 +77,8 @@ module Kameleoon
77
77
  cdi = @data_manager.data_file.custom_data_info
78
78
  args.size.times do |i|
79
79
  custom_data = args[i]
80
- next unless custom_data.is_a?(Kameleoon::CustomData)
81
-
82
- # We shouldn't send custom data with local only type
83
- custom_data.mark_as_sent if cdi.local_only?(custom_data.id)
84
- # If mappingIdentifier is passed, we should link anonymous visitor with real unique userId.
85
- # After authorization, customer must be able to continue work with userId, but hash for variation
86
- # should be calculated based on anonymous visitor code, that's why set MappingIdentifier to visitor.
87
- if Configuration::CustomDataInfo.mapping_identifier?(cdi, custom_data)
88
- visitor.mapping_identifier = visitor_code
89
- user_id = custom_data.values[0]
90
- args[i] = MappingIdentifier.new(custom_data)
91
- if visitor_code != user_id
92
- @visitors[user_id] = visitor.clone
93
- Logging::KameleoonLogger.info(-> { "Linked anonymous visitor '#{visitor_code}' with user '#{user_id}'" })
94
- end
80
+ if custom_data.is_a?(Kameleoon::CustomData)
81
+ args[i] = process_custom_data(cdi, visitor_code, visitor, custom_data)
95
82
  end
96
83
  end
97
84
  visitor.add_data(*args, overwrite: overwrite)
@@ -104,6 +91,30 @@ module Kameleoon
104
91
 
105
92
  private
106
93
 
94
+ def process_custom_data(cdi, visitor_code, visitor, custom_data)
95
+ unless custom_data.name.nil?
96
+ cd_index = cdi.get_custom_data_index_by_name(custom_data.name)
97
+ return nil if cd_index.nil?
98
+
99
+ custom_data = custom_data.named_to_indexed(cd_index)
100
+ end
101
+ # We shouldn't send custom data with local only type
102
+ custom_data.mark_as_sent if cdi.local_only?(custom_data.index)
103
+ # If mappingIdentifier is passed, we should link anonymous visitor with real unique userId.
104
+ # After authorization, customer must be able to continue work with userId, but hash for variation
105
+ # should be calculated based on anonymous visitor code, that's why set MappingIdentifier to visitor.
106
+ if Configuration::CustomDataInfo.mapping_identifier?(cdi, custom_data)
107
+ visitor.mapping_identifier = visitor_code
108
+ user_id = custom_data.values[0]
109
+ custom_data = MappingIdentifier.new(custom_data)
110
+ if visitor_code != user_id
111
+ @visitors[user_id] = visitor.clone
112
+ Logging::KameleoonLogger.info(-> { "Linked anonymous visitor '#{visitor_code}' with user '#{user_id}'" })
113
+ end
114
+ end
115
+ custom_data
116
+ end
117
+
107
118
  def purge
108
119
  Logging::KameleoonLogger.debug('CALL: VisitorManager.purge')
109
120
  expired_time = Time.new.to_i - @expiration_period
@@ -6,7 +6,14 @@ require 'kameleoon/network/uri_helper'
6
6
  module Kameleoon
7
7
  class MappingIdentifier < CustomData
8
8
  def initialize(custom_data)
9
- super(custom_data.id, *custom_data.values)
9
+ super(
10
+ {
11
+ 'index' => custom_data.index,
12
+ 'name' => custom_data.name,
13
+ 'values' => custom_data.values,
14
+ 'overwrite' => custom_data.overwrite
15
+ }
16
+ )
10
17
  end
11
18
 
12
19
  def unsent
@@ -27,7 +34,7 @@ module Kameleoon
27
34
  end
28
35
 
29
36
  def to_s
30
- "MappingIdentifier{id:#{@id},values:#{@values}}"
37
+ "MappingIdentifier{index:#{@index},name:'#{@name}',values:#{@values},overwrite:#{@overwrite}}"
31
38
  end
32
39
  end
33
40
  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.16.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.16.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-08-29 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