kameleoon-client-ruby 3.16.2 → 3.17.1

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: 602844d249763c9165d740e924c71b8d98efbfdb77c8f70ef4cd0ad361dfb86f
4
- data.tar.gz: 1a9ee1ce8a3b3548f38ba19f21d3f0de86aeba513549405870bcd3150a617608
3
+ metadata.gz: 7fc2b3610def24ae9ceb3a3e11f8a1e6e360c12359631c47c1af18e7bdd67a2b
4
+ data.tar.gz: ebe8a7cd7920d0522c8cde5f09e02db0050b3ccbd81fe47ffde2452c1c40c136
5
5
  SHA512:
6
- metadata.gz: 8988b718fac058005be7ac57bc7519c9cc8ad4e6dd95d03e2505e3210eea483fc619362959b8af6788d5ee5f06045f52941b27cbca57f0b11b82c45e63e92612
7
- data.tar.gz: 41c1a2c1c2a7903dd352b5fe3a515d4f2639656eb05de89a19791e2d50ae0c4ef5b4336649491e2dc358dd55c51e92ab1e411132a7c7b1cd9784735c6bae3e81
6
+ metadata.gz: 2f4ec5f9d42e0260ad0646a837654c412b15e42583763992ab7df04167357e4d670874cfad5abfb017212cbcce224cef5828e4f7df10ae94305ee7efa1eb36ec
7
+ data.tar.gz: 2c562cccbdf690902f653fc13b961a3197ef493be9886253842e369943c2935d90fc50bac9e5aba98a4c1bff0171db1a6a663bf14c1b169a19bd418936d59f80
@@ -46,8 +46,12 @@ module Kameleoon
46
46
  def get_feature_flag(feature_key)
47
47
  ff = @feature_flags[feature_key]
48
48
  raise Exception::FeatureNotFound, feature_key if ff.nil?
49
- raise Exception::FeatureEnvironmentDisabled.new(feature_key, @environment) unless ff.environment_enabled
50
49
 
50
+ unless ff.environment_enabled
51
+ env = @environment.nil? ? 'default' : "'#{@environment}'"
52
+ msg = "Feature '#{feature_key}' is disabled for #{env} environment'"
53
+ raise Exception::FeatureEnvironmentDisabled, msg
54
+ end
51
55
  ff
52
56
  end
53
57
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'kameleoon/logging/kameleoon_logger'
4
+
3
5
  module Kameleoon
4
6
  # Module which contains all internal data of SDK
5
7
  module Configuration
@@ -7,7 +9,7 @@ module Kameleoon
7
9
  # state of real time update for site code and etc
8
10
  class Settings
9
11
  attr_accessor :real_time_update
10
- attr_reader :is_consent_required, :data_api_domain
12
+ attr_reader :is_consent_required, :blocking_behaviour_if_consent_not_given, :data_api_domain
11
13
 
12
14
  def to_s
13
15
  "Settings{real_time_update:#{@real_time_update},is_consent_required:#{@is_consent_required}," \
@@ -18,13 +20,37 @@ module Kameleoon
18
20
  if configuration.nil?
19
21
  @real_time_update = false
20
22
  @is_consent_required = false
23
+ @blocking_behaviour_if_consent_not_given = ConsentBlockingBehaviour::PARTIALLY_BLOCKED
21
24
  @data_api_domain = nil
22
25
  else
23
26
  @real_time_update = configuration['realTimeUpdate'] || false
24
27
  @is_consent_required = configuration['consentType'] == 'REQUIRED'
28
+ @blocking_behaviour_if_consent_not_given =
29
+ ConsentBlockingBehaviour.from_str(configuration['consentOptOutBehavior'])
25
30
  @data_api_domain = configuration['dataApiDomain']
26
31
  end
27
32
  end
28
33
  end
34
+
35
+ # ConsentBlockingBehaviour
36
+ module ConsentBlockingBehaviour
37
+ PARTIALLY_BLOCKED = 0
38
+ COMPLETELY_BLOCKED = 1
39
+
40
+ PARTIALLY_BLOCKED_STR = 'PARTIALLY_BLOCK'
41
+ COMPLETELY_BLOCKED_STR = 'FULLY_BLOCK'
42
+
43
+ def self.from_str(str)
44
+ case str
45
+ when PARTIALLY_BLOCKED_STR
46
+ PARTIALLY_BLOCKED
47
+ when COMPLETELY_BLOCKED_STR
48
+ COMPLETELY_BLOCKED
49
+ else
50
+ Logging::KameleoonLogger.warning("Unexpected consent blocking type '%s'", str)
51
+ PARTIALLY_BLOCKED
52
+ end
53
+ end
54
+ end
29
55
  end
30
56
  end
@@ -12,7 +12,7 @@ module Kameleoon
12
12
 
13
13
  # Variation of feature flag
14
14
  class Variation
15
- attr_accessor :key, :variables
15
+ attr_reader :key, :variables, :name
16
16
 
17
17
  def self.create_from_array(array)
18
18
  array&.map { |it| Variation.new(it) }
@@ -21,6 +21,7 @@ module Kameleoon
21
21
  def initialize(hash)
22
22
  @key = hash['key']
23
23
  @variables = Variable.create_from_array(hash['variables'])
24
+ @name = hash['name'] || ''
24
25
  end
25
26
 
26
27
  def get_variable_by_key(key)
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kameleoon
4
+ module DataManager
5
+ module LegalConsent
6
+ UNKNOWN = 0
7
+ GIVEN = 1
8
+ NOT_GIVEN = 2
9
+ end
10
+ end
11
+ end
@@ -18,6 +18,7 @@ require 'kameleoon/data/manager/data_array_storage'
18
18
  require 'kameleoon/data/manager/data_map_storage'
19
19
  require 'kameleoon/data/manager/forced_experiment_variation'
20
20
  require 'kameleoon/data/manager/forced_feature_variation'
21
+ require 'kameleoon/data/manager/legal_consent'
21
22
  require 'kameleoon/data/manager/page_view_visit'
22
23
  require 'kameleoon/logging/kameleoon_logger'
23
24
 
@@ -312,7 +313,7 @@ module Kameleoon
312
313
  Logging::KameleoonLogger.debug('CALL: VisitorData.new')
313
314
  @time_started = (Time.now.to_f * 1000).to_i
314
315
  @mutex = Concurrent::ReadWriteLock.new
315
- @legal_consent = false
316
+ @legal_consent = LegalConsent::UNKNOWN
316
317
  Logging::KameleoonLogger.debug('RETURN: VisitorData.new')
317
318
  end
318
319
 
@@ -53,10 +53,6 @@ module Kameleoon
53
53
 
54
54
  # Feature Environment Disabled
55
55
  class FeatureEnvironmentDisabled < FeatureError
56
- def initialize(feature_key, environment = nil)
57
- environment = environment.nil? ? 'default' : "'#{environment}'"
58
- super("Feature '#{feature_key}' is disabled for #{environment} environment'")
59
- end
60
56
  end
61
57
 
62
58
  # Config Error
@@ -8,6 +8,7 @@ require 'kameleoon/data/custom_data'
8
8
  require 'kameleoon/data/user_agent'
9
9
  require 'kameleoon/data/manager/assigned_variation'
10
10
  require 'kameleoon/data/manager/forced_experiment_variation'
11
+ require 'kameleoon/data/manager/legal_consent'
11
12
  require 'kameleoon/data/manager/visitor_manager'
12
13
  require 'kameleoon/exceptions'
13
14
  require 'kameleoon/hybrid/manager'
@@ -27,6 +28,9 @@ require 'kameleoon/targeting/models'
27
28
  require 'kameleoon/targeting/targeting_manager'
28
29
  require 'kameleoon/types/variable'
29
30
  require 'kameleoon/types/variation'
31
+ require 'kameleoon/types/rule'
32
+ require 'kameleoon/types/feature_flag'
33
+ require 'kameleoon/types/data_file'
30
34
  require 'rufus/scheduler'
31
35
  require 'yaml'
32
36
  require 'json'
@@ -123,8 +127,9 @@ module Kameleoon
123
127
  # visitor_code = get_visitor_code(cookies, 'my-domaine.com')
124
128
  #
125
129
  def get_visitor_code(cookies, default_visitor_code = nil)
126
- Logging::KameleoonLogger.info("CALL: KameleoonClient.get_visitor_code(cookies: %s, default_visitor_code: '%s')",
127
- cookies, default_visitor_code)
130
+ Logging::KameleoonLogger.info(
131
+ "CALL: KameleoonClient.get_visitor_code(cookies: %s, default_visitor_code: '%s')", cookies, default_visitor_code
132
+ )
128
133
  visitor_code = @cookie_manager.get_or_add(cookies, default_visitor_code)
129
134
  Logging::KameleoonLogger.info(
130
135
  "RETURN: KameleoonClient.get_visitor_code(cookies: %s, default_visitor_code: '%s') -> (visitor_code: '%s')",
@@ -140,7 +145,7 @@ module Kameleoon
140
145
  )
141
146
  Utils::VisitorCode.validate(visitor_code)
142
147
  visitor = @visitor_manager.get_or_create_visitor(visitor_code)
143
- visitor.legal_consent = consent
148
+ visitor.legal_consent = consent ? DataManager::LegalConsent::GIVEN : DataManager::LegalConsent::NOT_GIVEN
144
149
  @cookie_manager.update(visitor_code, consent, cookies)
145
150
  Logging::KameleoonLogger.info(
146
151
  "RETURN: KameleoonClient.set_legal_consent(visitor_code: '%s', consent: %s, cookies: %s)",
@@ -366,7 +371,11 @@ module Kameleoon
366
371
  @data_manager.data_file.feature_flags.each_value do |feature_flag|
367
372
  next unless feature_flag.environment_enabled
368
373
 
369
- variation_key, eval_exp = get_variation_info(visitor_code, feature_flag, track)
374
+ begin
375
+ variation_key, eval_exp = get_variation_info(visitor_code, feature_flag, track)
376
+ rescue Exception::FeatureEnvironmentDisabled
377
+ next
378
+ end
370
379
  next if only_active && (variation_key == Configuration::VariationType::VARIATION_OFF)
371
380
 
372
381
  variation = feature_flag.get_variation_by_key(variation_key)
@@ -631,7 +640,11 @@ module Kameleoon
631
640
  @data_manager.data_file.feature_flags.each do |feature_key, feature_flag|
632
641
  next unless feature_flag.environment_enabled
633
642
 
634
- eval_exp = evaluate(visitor, visitor_code, feature_flag, false, false)
643
+ begin
644
+ eval_exp = evaluate(visitor, visitor_code, feature_flag, false, false)
645
+ rescue Exception::FeatureEnvironmentDisabled
646
+ next
647
+ end
635
648
  variation_key = calculate_variation_key(eval_exp, feature_flag.default_variation_key)
636
649
  list_keys.push(feature_key) if variation_key != Kameleoon::Configuration::VariationType::VARIATION_OFF
637
650
  end
@@ -666,7 +679,11 @@ module Kameleoon
666
679
  @data_manager.data_file.feature_flags.each_value do |feature_flag|
667
680
  next unless feature_flag.environment_enabled
668
681
 
669
- eval_exp = evaluate(visitor, visitor_code, feature_flag, false, false)
682
+ begin
683
+ eval_exp = evaluate(visitor, visitor_code, feature_flag, false, false)
684
+ rescue Exception::FeatureEnvironmentDisabled
685
+ next
686
+ end
670
687
  variation_key = calculate_variation_key(eval_exp, feature_flag.default_variation_key)
671
688
 
672
689
  next if variation_key == Configuration::VariationType::VARIATION_OFF
@@ -779,6 +796,52 @@ module Kameleoon
779
796
  Logging::KameleoonLogger.info("RETURN: KameleoonClient.evaluate_audiences(visitor_code: '%s')", visitor_code)
780
797
  end
781
798
 
799
+ ##
800
+ # Retrieves the current SDK configuration (also known as the data file),
801
+ # containing all feature flags and their variations.
802
+ #
803
+ # @return [Kameleoon::Types::DataFile] The current DataFile instance.
804
+ def get_data_file
805
+ Logging::KameleoonLogger.info('CALL: KameleoonClient.get_data_file')
806
+
807
+ feature_flags_map = @data_manager.data_file.feature_flags.transform_values do |source_feature_flag|
808
+ # Collect variations
809
+ variations_map = source_feature_flag.variations.each_with_object({}) do |variation, variations_map|
810
+ variables_map = variation.variables.each_with_object({}) do |var, variables_map|
811
+ variables_map[var.key] = Types::Variable.new(var.key, var.type, _parse_feature_variable(var))
812
+ end
813
+ variations_map[variation.key] = Types::Variation.new(variation.key, nil, nil, variables_map, variation.name)
814
+ end
815
+
816
+ # Collect rules
817
+ rules = source_feature_flag.rules.map do |rule|
818
+ rule_variations = rule.experiment.variations_by_exposition.each_with_object({}) do |var_by_exp, rule_variations|
819
+ base_variation = variations_map[var_by_exp.variation_key]
820
+ next unless base_variation
821
+ rule_variations[base_variation.key] = Types::Variation.new(
822
+ base_variation.key,
823
+ var_by_exp.variation_id,
824
+ rule.experiment.id,
825
+ base_variation.variables,
826
+ base_variation.name
827
+ )
828
+ end
829
+ Types::Rule.new(rule_variations)
830
+ end
831
+
832
+ Types::FeatureFlag.new(
833
+ variations_map,
834
+ source_feature_flag.environment_enabled,
835
+ rules,
836
+ source_feature_flag.default_variation_key
837
+ )
838
+ end
839
+
840
+ data_file = Types::DataFile.new(feature_flags_map)
841
+ Logging::KameleoonLogger.info('RETURN: KameleoonClient.get_data_file -> (data_file: %s)', data_file)
842
+ data_file
843
+ end
844
+
782
845
  private
783
846
 
784
847
  HYBRID_EXPIRATION_TIME = 5
@@ -995,11 +1058,19 @@ module Kameleoon
995
1058
  holdout = @data_manager.data_file.holdout
996
1059
  return true if holdout.nil?
997
1060
 
998
- in_holdout_variation_key = 'in-holdout'
999
1061
  Logging::KameleoonLogger.debug(
1000
1062
  "CALL: KameleoonClient.visitor_not_in_holdout?(visitor, visitor_code: '%s', track: %s, save: %s, " \
1001
1063
  'bucketing_custom_data_index: %s)', visitor_code, track, save, bucketing_custom_data_index
1002
1064
  )
1065
+
1066
+ consent, blocking_behaviour = _get_consent_and_blocking_behaviour(visitor)
1067
+ if consent == DataManager::LegalConsent::NOT_GIVEN &&
1068
+ blocking_behaviour == Configuration::ConsentBlockingBehaviour::COMPLETELY_BLOCKED
1069
+ raise FeatureEnvironmentDisabled,
1070
+ "Evaluation for a holdout is blocked because visitor's consent was not provided."
1071
+ end
1072
+
1073
+ in_holdout_variation_key = 'in-holdout'
1003
1074
  is_not_in_holdout = true
1004
1075
  code_for_hash = get_code_for_hash(visitor, visitor_code, bucketing_custom_data_index)
1005
1076
  variation_hash = Utils::Hasher.obtain(code_for_hash, holdout.id)
@@ -1116,6 +1187,7 @@ module Kameleoon
1116
1187
  visitor_code, feature_flag
1117
1188
  )
1118
1189
  visitor = @visitor_manager.get_visitor(visitor_code)
1190
+ consent, blocking_behaviour = _get_consent_and_blocking_behaviour(visitor)
1119
1191
  code_for_hash = get_code_for_hash(visitor, visitor_code, feature_flag.bucketing_custom_data_index)
1120
1192
  # no rules -> return default_variation_key
1121
1193
  eval_exp = nil
@@ -1139,6 +1211,15 @@ module Kameleoon
1139
1211
  Logging::KameleoonLogger.debug("Calculated rule hash %s for code '%s'", hash_rule, code_for_hash)
1140
1212
  # check main expostion for rule with hashRule
1141
1213
  if hash_rule <= rule.exposition
1214
+ # Checking if the evaluation is blocked due to the consent policy
1215
+ if (consent == DataManager::LegalConsent::NOT_GIVEN) && rule.experimentation_type?
1216
+ break if blocking_behaviour == Configuration::ConsentBlockingBehaviour::PARTIALLY_BLOCKED
1217
+
1218
+ # TODO: In the next major, create a new error type for the Completely Blocked by Consent error
1219
+ msg = "Evaluation of #{rule} is blocked because consent is not provided for visitor '#{visitor_code}'"
1220
+ raise Exception::FeatureEnvironmentDisabled, msg
1221
+ end
1222
+ # Checking CBS
1142
1223
  eval_exp = evaluate_cbscores(visitor, visitor_code, rule, feature_flag.bucketing_custom_data_index)
1143
1224
  break unless eval_exp.nil?
1144
1225
 
@@ -1167,6 +1248,18 @@ module Kameleoon
1167
1248
  eval_exp
1168
1249
  end
1169
1250
 
1251
+ def _get_consent_and_blocking_behaviour(visitor)
1252
+ datafile = @data_manager.data_file
1253
+ behaviour = datafile.settings.blocking_behaviour_if_consent_not_given
1254
+
1255
+ consent = DataManager::LegalConsent::GIVEN
1256
+ if datafile.settings.is_consent_required
1257
+ consent = visitor&.legal_consent || DataManager::LegalConsent::UNKNOWN
1258
+ end
1259
+
1260
+ [consent, behaviour]
1261
+ end
1262
+
1170
1263
  def calculate_variation_key(eval_exp, default_value)
1171
1264
  Logging::KameleoonLogger.debug(
1172
1265
  "CALL: KameleoonClient.calculate_variation_key(eval_exp: %s, default_value: '%s') ", eval_exp, default_value
@@ -1193,7 +1286,11 @@ module Kameleoon
1193
1286
  end
1194
1287
  ext_variables.freeze
1195
1288
  ext_variation = Types::Variation.new(
1196
- variation&.key, eval_exp&.var_by_exp&.variation_id, eval_exp&.experiment&.id, ext_variables
1289
+ variation&.key || '',
1290
+ eval_exp&.var_by_exp&.variation_id,
1291
+ eval_exp&.experiment&.id,
1292
+ ext_variables,
1293
+ variation&.name || ''
1197
1294
  )
1198
1295
  Logging::KameleoonLogger.debug(
1199
1296
  'RETURN: KameleoonClient.create_external_variation(variation: %s, eval_exp: %s) -> (ext_variation: %s)',
@@ -24,15 +24,16 @@ module Kameleoon
24
24
  @filter = filter
25
25
  @visit_number = 0
26
26
  current_visit = hash['currentVisit']
27
- parse_visit(current_visit, false) unless current_visit.nil?
27
+ parse_visit(current_visit, 0) unless current_visit.nil?
28
28
  previous_visits = hash['previousVisits']
29
29
  previous_visits = [] if previous_visits.nil?
30
30
 
31
31
  if previous_visits.size.positive?
32
32
  prev_visits = []
33
- previous_visits.each do |visit|
33
+ previous_visits.each_index do |i|
34
+ visit = previous_visits[i]
34
35
  prev_visits.push(VisitorVisits::Visit.new(visit['timeStarted'] || 0, visit['timeLastEvent']))
35
- parse_visit(visit, true)
36
+ parse_visit(visit, i + 1)
36
37
  end
37
38
  @visitor_visits = VisitorVisits.new(prev_visits, @visit_number)
38
39
  end
@@ -74,7 +75,7 @@ module Kameleoon
74
75
 
75
76
  private
76
77
 
77
- def parse_visit(hash, is_prev_visit)
78
+ def parse_visit(hash, visit_offset)
78
79
  @visitor_code = hash['visitorCode'] if @visitor_code.nil?
79
80
  custom_data_events = hash['customDataEvents']
80
81
  parse_custom_data(custom_data_events) if !custom_data_events.nil? && custom_data_events.size.positive?
@@ -88,7 +89,7 @@ module Kameleoon
88
89
  @geolocation = parse_geolocation(geolocation_events) if @geolocation.nil? && !geolocation_events.nil? && \
89
90
  geolocation_events.size.positive?
90
91
  static_data_events = hash['staticDataEvent']
91
- parse_static_data(static_data_events, is_prev_visit) unless static_data_events.nil?
92
+ parse_static_data(static_data_events, visit_offset) unless static_data_events.nil?
92
93
  personalization_events = hash['personalizationEvents']
93
94
  parse_personalizations(personalization_events) unless personalization_events.nil?
94
95
  end
@@ -146,11 +147,11 @@ module Kameleoon
146
147
  Geolocation.new(data['country'], data['region'], data['city'])
147
148
  end
148
149
 
149
- def parse_static_data(static_data_event, is_prev_visit)
150
+ def parse_static_data(static_data_event, visit_offset)
150
151
  data = static_data_event['data']
151
152
  if @visit_number.zero?
152
- @visit_number = data['visitNumber'] || 0
153
- @visit_number += 1 if is_prev_visit && @visit_number.positive?
153
+ remote_visit_number = data['visitNumber']
154
+ @visit_number = remote_visit_number + visit_offset unless remote_visit_number.nil?
154
155
  end
155
156
  if @filter.device && @device.nil?
156
157
  device_type = data['deviceType']
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'kameleoon/data/custom_data'
4
+ require 'kameleoon/data/manager/legal_consent'
4
5
  require 'kameleoon/logging/kameleoon_logger'
5
6
  require 'kameleoon/network/activity_event'
6
7
  require 'kameleoon/network/uri_helper'
@@ -65,7 +66,8 @@ module Kameleoon
65
66
  end
66
67
 
67
68
  def consent_given?(visitor)
68
- !@data_file.settings.is_consent_required || visitor&.legal_consent
69
+ !@data_file.settings.is_consent_required ||
70
+ ((visitor&.legal_consent || DataManager::LegalConsent::UNKNOWN) == DataManager::LegalConsent::GIVEN)
69
71
  end
70
72
 
71
73
  def collect_tracking_data(visitor_code, visitor, is_consent_given)
@@ -45,16 +45,13 @@ module Kameleoon
45
45
  def update(visitor_code, consent, cookies)
46
46
  return if cookies.nil?
47
47
 
48
- Logging::KameleoonLogger.debug("CALL: CookieManager.update(visitor_code: '%s', consent: %s, cookies: %s)",
49
- visitor_code, consent, cookies)
50
-
51
- if consent
52
- add(visitor_code, cookies)
53
- else
54
- remove(cookies)
55
- end
56
- Logging::KameleoonLogger.debug("RETURN: CookieManager.update(visitor_code: '%s', consent: %s, cookies: %s)",
57
- visitor_code, consent, cookies)
48
+ Logging::KameleoonLogger.debug(
49
+ "CALL: CookieManager.update(visitor_code: '%s', consent: %s, cookies: %s)", visitor_code, consent, cookies
50
+ )
51
+ add(visitor_code, cookies) if consent
52
+ Logging::KameleoonLogger.debug(
53
+ "RETURN: CookieManager.update(visitor_code: '%s', consent: %s, cookies: %s)", visitor_code, consent, cookies
54
+ )
58
55
  end
59
56
 
60
57
  private
@@ -79,7 +76,7 @@ module Kameleoon
79
76
  visitor_code = default_visitor_code
80
77
  Utils::VisitorCode.validate(visitor_code)
81
78
  Logging::KameleoonLogger.debug("Used default visitor code '{%s}'", default_visitor_code)
82
- add(visitor_code, cookies)
79
+ add(visitor_code, cookies) unless @data_manager.visitor_code_managed?
83
80
  visitor_code
84
81
  end
85
82
 
@@ -100,13 +97,6 @@ module Kameleoon
100
97
  cookies
101
98
  end
102
99
 
103
- def remove(cookies)
104
- Logging::KameleoonLogger.debug('CALL: CookieManager.remove(cookies: %s)', cookies)
105
- cookies[VISITOR_CODE_COOKIE] = nil if @data_manager.visitor_code_managed?
106
- Logging::KameleoonLogger.debug('RETURN: CookieManager.remove(cookies: %s)', cookies)
107
- cookies
108
- end
109
-
110
100
  def process_simulated_variations(cookies, visitor_code)
111
101
  raw = get_value_from_cookies(cookies, KAMELEOON_SIMULATION_FF_DATA)
112
102
  return if raw.nil?
@@ -28,6 +28,22 @@ module Kameleoon
28
28
 
29
29
  class SyncNetProvider < NetProvider
30
30
  def make_request(request)
31
+ for _ in 0..8 do
32
+ response = make_single_request(request)
33
+ break if (response.code != 307) && (response.code != 308)
34
+
35
+ # supports only absolute urls
36
+ new_loc = response.headers['location'][0]
37
+ break unless new_loc
38
+
39
+ request.redirect(new_loc)
40
+ end
41
+ response
42
+ end
43
+
44
+ private
45
+
46
+ def make_single_request(request)
31
47
  resp = nil
32
48
  case request.method
33
49
  when Method::GET
@@ -31,6 +31,10 @@ module Kameleoon
31
31
  def authorize(access_token)
32
32
  @access_token = access_token
33
33
  end
34
+
35
+ def redirect(new_loc)
36
+ @url = new_loc
37
+ end
34
38
  end
35
39
  end
36
40
  end
@@ -29,7 +29,8 @@ module Kameleoon
29
29
  # Module for create different targeting conditions
30
30
  module ConditionFactory
31
31
  def get_condition(condition_json)
32
- case condition_json['targetingType']
32
+ cond_type = condition_json['targetingType']
33
+ case cond_type
33
34
  when ConditionType::CUSTOM_DATUM
34
35
  CustomDatum.new(condition_json)
35
36
  when ConditionType::TARGET_FEATURE_FLAG
@@ -77,6 +78,7 @@ module Kameleoon
77
78
  when ConditionType::HEAT_SLICE
78
79
  KcsHeatRangeCondition.new(condition_json)
79
80
  else
81
+ Logging::KameleoonLogger.info("Unexpected TargetingConditionType: '%s'", cond_type)
80
82
  UnknownCondition.new(condition_json)
81
83
  end
82
84
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kameleoon
4
+ module Types
5
+ # DataFile
6
+ class DataFile
7
+ attr_reader :feature_flags
8
+
9
+ # @api private
10
+ def initialize(feature_flags)
11
+ @feature_flags = feature_flags
12
+ end
13
+
14
+ def to_s
15
+ "DataFile{feature_flags:#{@feature_flags}}"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kameleoon
4
+ module Types
5
+ # FeatureFlag
6
+ class FeatureFlag
7
+ attr_reader :variations, :environment_enabled, :rules, :default_variation_key
8
+
9
+ # @api private
10
+ def initialize(variations, environment_enabled, rules, default_variation_key)
11
+ @variations = variations
12
+ @environment_enabled = environment_enabled
13
+ @rules = rules
14
+ @default_variation_key = default_variation_key
15
+ end
16
+
17
+ def default_variation
18
+ @variations[@default_variation_key]
19
+ end
20
+
21
+ def to_s
22
+ "FeatureFlag{variations:#{@variations},environment_enabled:#{@environment_enabled},rules:#{@rules},default_variation_key:#{@default_variation_key}}"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kameleoon
4
- # Module which contains all internal data of SDK
5
4
  module Types
6
5
  class RemoteVisitorDataFilter
7
6
  attr_reader :previous_visit_amount, :current_visit, :custom_data, :page_views, :geolocation, :device, :browser,
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kameleoon
4
+ module Types
5
+ # Rule
6
+ class Rule
7
+ attr_reader :variations
8
+
9
+ # @api private
10
+ def initialize(variations)
11
+ @variations = variations
12
+ end
13
+
14
+ def to_s
15
+ "Rule{variations:#{@variations}}"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kameleoon
4
- # Module which contains all internal data of SDK
5
4
  module Types
6
5
  # Variable
7
6
  class Variable
@@ -11,6 +10,7 @@ module Kameleoon
11
10
  "Variable{key:'#{@key}',type:'#{@type}',value:#{@value}}"
12
11
  end
13
12
 
13
+ # @api private
14
14
  def initialize(key, type, value)
15
15
  @key = key
16
16
  @type = type
@@ -3,21 +3,22 @@
3
3
  require 'kameleoon/configuration/variation'
4
4
 
5
5
  module Kameleoon
6
- # Module which contains all internal data of SDK
7
6
  module Types
8
7
  # Variation
9
8
  class Variation
10
- attr_reader :key, :id, :experiment_id, :variables
9
+ attr_reader :name, :key, :id, :experiment_id, :variables
11
10
 
12
11
  def to_s
13
- "Variation{key:'#{@key}',id:#{@id},experiment_id:#{@experiment_id},variables:#{@variables}}"
12
+ "Variation{name:'#{@name}',key:'#{@key}',id:#{@id},experiment_id:#{@experiment_id},variables:#{@variables}}"
14
13
  end
15
14
 
16
- def initialize(key, id, experiment_id, variables)
15
+ # @api private
16
+ def initialize(key, id, experiment_id, variables, name = '')
17
17
  @key = key
18
18
  @id = id
19
19
  @experiment_id = experiment_id
20
20
  @variables = variables
21
+ @name = name
21
22
  end
22
23
 
23
24
  def active?
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kameleoon
4
- SDK_VERSION = '3.16.2'
4
+ SDK_VERSION = '3.17.1'
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.16.2
4
+ version: 3.17.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kameleoon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-10-31 00:00:00.000000000 Z
11
+ date: 2025-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: em-http-request
@@ -101,6 +101,7 @@ files:
101
101
  - lib/kameleoon/data/manager/forced_experiment_variation.rb
102
102
  - lib/kameleoon/data/manager/forced_feature_variation.rb
103
103
  - lib/kameleoon/data/manager/forced_variation.rb
104
+ - lib/kameleoon/data/manager/legal_consent.rb
104
105
  - lib/kameleoon/data/manager/page_view_visit.rb
105
106
  - lib/kameleoon/data/manager/visitor.rb
106
107
  - lib/kameleoon/data/manager/visitor_manager.rb
@@ -178,7 +179,10 @@ files:
178
179
  - lib/kameleoon/targeting/models.rb
179
180
  - lib/kameleoon/targeting/targeting_manager.rb
180
181
  - lib/kameleoon/targeting/tree_builder.rb
182
+ - lib/kameleoon/types/data_file.rb
183
+ - lib/kameleoon/types/feature_flag.rb
181
184
  - lib/kameleoon/types/remote_visitor_data_filter.rb
185
+ - lib/kameleoon/types/rule.rb
182
186
  - lib/kameleoon/types/variable.rb
183
187
  - lib/kameleoon/types/variation.rb
184
188
  - lib/kameleoon/utils.rb