kameleoon-client-ruby 3.17.3 → 3.19.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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/lib/kameleoon/configuration/data_file.rb +9 -4
  3. data/lib/kameleoon/configuration/variable.rb +12 -0
  4. data/lib/kameleoon/configuration/variation.rb +1 -1
  5. data/lib/kameleoon/data/application_version.rb +21 -0
  6. data/lib/kameleoon/data/data.rb +1 -0
  7. data/lib/kameleoon/data/manager/visitor.rb +16 -1
  8. data/lib/kameleoon/data/manager/visitor_manager.rb +16 -5
  9. data/lib/kameleoon/kameleoon_client.rb +25 -77
  10. data/lib/kameleoon/kameleoon_client_config.rb +2 -2
  11. data/lib/kameleoon/managers/data/data_manager.rb +16 -2
  12. data/lib/kameleoon/managers/tracking/tracking_builder.rb +1 -1
  13. data/lib/kameleoon/network/access_token_source.rb +9 -1
  14. data/lib/kameleoon/network/net_provider.rb +4 -1
  15. data/lib/kameleoon/network/network_manager.rb +2 -3
  16. data/lib/kameleoon/network/request.rb +6 -3
  17. data/lib/kameleoon/network/url_provider.rb +21 -3
  18. data/lib/kameleoon/sem_version.rb +55 -0
  19. data/lib/kameleoon/targeting/condition.rb +1 -0
  20. data/lib/kameleoon/targeting/condition_factory.rb +3 -0
  21. data/lib/kameleoon/targeting/conditions/browser_condition.rb +2 -2
  22. data/lib/kameleoon/targeting/conditions/sdk_language_condition.rb +5 -33
  23. data/lib/kameleoon/targeting/conditions/unknown_condition.rb +1 -0
  24. data/lib/kameleoon/targeting/conditions/version_condition.rb +55 -0
  25. data/lib/kameleoon/targeting/targeting_manager.rb +2 -0
  26. data/lib/kameleoon/types/data_file.rb +14 -3
  27. data/lib/kameleoon/types/feature_flag.rb +22 -0
  28. data/lib/kameleoon/types/rule.rb +21 -0
  29. data/lib/kameleoon/types/variable.rb +8 -0
  30. data/lib/kameleoon/types/variation.rb +12 -0
  31. data/lib/kameleoon/version.rb +1 -1
  32. metadata +5 -3
  33. data/lib/kameleoon/sdk_version.rb +0 -31
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0d4abc01c7fc06b5cc0b0613dde8a40e004d6d11b358092398498a2c59ee766
4
- data.tar.gz: ec89564082cb1b270a9453c63741f1ae505c46dcbbc52fd583927b603a98a26f
3
+ metadata.gz: dde5f6ebb9e6779b9bf8d4edbdded4e11b82aa642ec046bd2493306e0b2a7ad8
4
+ data.tar.gz: 5a15f627b2832ec10f001ef7ee061fa31c6dbd618b02ec55ff9d1d66ee17d5a8
5
5
  SHA512:
6
- metadata.gz: 7b1e31f65a0c314810b5e020570d52cee18bc1a6cbe41bbdc564114dd9136257e78c06fd55b07a04106d42bfa996a3f979438647105df7d18d299cdb282dbc1d
7
- data.tar.gz: df793d553ff36d2e98e118fe5c2bc846417900958d81262bb9ec7fe0dc233a86420bb9c93b793b91beec097a073dba81907dee2290fa1b7b82ddf03dd297a59f
6
+ metadata.gz: 91d3f34ab6855ed62d571fa5d40b85a04504926f2d38650c9b62f052bd9f0b79b0ce95ece6636fa37ecc5062020f2361bc5e0e8af80383b0d2b377dffd5919e7
7
+ data.tar.gz: c2e5efd80b73d5f8ce9c48a6f069aadda0fc7d1a6bc390a2d98af4a8a69b36928bac0188c77406bd793d8db6c4701df24838c67efc89b98d4d0e6b7e425b9c68
@@ -13,12 +13,13 @@ module Kameleoon
13
13
  class DataFile
14
14
  attr_reader :last_modified, :settings, :segments, :audience_tracking_segments, :feature_flags, :me_groups,
15
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
16
+ :custom_data_info, :experiment_ids_with_js_css_variable, :holdout, :date_modified
17
17
 
18
18
  def to_s
19
19
  'DataFile{' \
20
20
  "environment:#{@environment}," \
21
21
  "last_modified:#{@last_modified}," \
22
+ "date_modified:#{@date_modified}," \
22
23
  "feature_flags:#{@feature_flags.size}," \
23
24
  "settings:#{@settings}" \
24
25
  '}'
@@ -46,13 +47,15 @@ module Kameleoon
46
47
  def get_feature_flag(feature_key)
47
48
  ff = @feature_flags[feature_key]
48
49
  raise Exception::FeatureNotFound, feature_key if ff.nil?
50
+ ff
51
+ end
49
52
 
50
- unless ff.environment_enabled
53
+ def ensure_environment_enabled(feature_flag)
54
+ unless feature_flag.environment_enabled
51
55
  env = @environment.nil? ? 'default' : "'#{@environment}'"
52
- msg = "Feature '#{feature_key}' is disabled for #{env} environment'"
56
+ msg = "Feature '#{feature_flag.feature_key}' is disabled for #{env} environment'"
53
57
  raise Exception::FeatureEnvironmentDisabled, msg
54
58
  end
55
- ff
56
59
  end
57
60
 
58
61
  def experiment_js_css_variable?(experiment_id)
@@ -63,6 +66,7 @@ module Kameleoon
63
66
 
64
67
  def init_default
65
68
  Logging::KameleoonLogger.debug('CALL: DataFile.init_default')
69
+ @date_modified = 0
66
70
  @settings = Settings.new
67
71
  @feature_flags = {}
68
72
  @me_groups = {}
@@ -73,6 +77,7 @@ module Kameleoon
73
77
 
74
78
  def init(configuration)
75
79
  Logging::KameleoonLogger.debug('CALL: DataFile.init(configuration: %s)', configuration)
80
+ @date_modified = configuration['dateModified'] || 0
76
81
  @settings = Settings.new(configuration['configuration'])
77
82
  @segments, @audience_tracking_segments = parse_segments(configuration)
78
83
  @custom_data_info = CustomDataInfo.new(configuration['customData'])
@@ -16,6 +16,18 @@ module Kameleoon
16
16
  @type = hash['type']
17
17
  @value = hash['value']
18
18
  end
19
+
20
+ def get_value
21
+ case @type
22
+ when 'BOOLEAN', 'STRING', 'NUMBER', 'JS', 'CSS'
23
+ @value
24
+ when 'JSON'
25
+ JSON.parse(@value)
26
+ else
27
+ Logging::KameleoonLogger.error("Unknown type '#{@type}' for feature variable")
28
+ @value
29
+ end
30
+ end
19
31
  end
20
32
  end
21
33
  end
@@ -19,7 +19,7 @@ module Kameleoon
19
19
  end
20
20
 
21
21
  def initialize(hash)
22
- @key = hash['key']
22
+ @key = hash['key'] || ''
23
23
  @variables = Variable.create_from_array(hash['variables'])
24
24
  @name = hash['name'] || ''
25
25
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'data'
4
+
5
+ module Kameleoon
6
+ # ApplicationVersion contains information about the application version on the visitor's device.
7
+ # It is used for targeting by application version.
8
+ class ApplicationVersion < Data
9
+ attr_reader :version
10
+
11
+ # @param [String] version Application version (semantic versioning: major, major.minor, or major.minor.patch)
12
+ def initialize(version)
13
+ super(DataType::APPLICATION_VERSION)
14
+ @version = version
15
+ end
16
+
17
+ def to_s
18
+ "ApplicationVersion{version:#{@version}}"
19
+ end
20
+ end
21
+ end
@@ -20,6 +20,7 @@ module Kameleoon
20
20
  GEOLOCATION = 'GEOLOCATION'
21
21
  VISITOR_VISITS = 'VISITOR_VISITS'
22
22
  TARGETED_SEGMENT = 'TARGETED_SEGMENT'
23
+ APPLICATION_VERSION = 'APPLICATION_VERSION'
23
24
  end
24
25
 
25
26
  module DataState
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'concurrent'
4
4
  require 'time'
5
+ require 'kameleoon/data/application_version'
5
6
  require 'kameleoon/data/browser'
6
7
  require 'kameleoon/data/cbscores'
7
8
  require 'kameleoon/data/conversion'
@@ -103,6 +104,13 @@ module Kameleoon
103
104
  operating_system
104
105
  end
105
106
 
107
+ def application_version
108
+ application_version = @data.application_version
109
+ Logging::KameleoonLogger.debug('CALL/RETURN: Visitor.application_version -> (application_version: %s)',
110
+ application_version)
111
+ application_version
112
+ end
113
+
106
114
  def cookie
107
115
  cookie = @data.cookie
108
116
  Logging::KameleoonLogger.debug('CALL/RETURN: Visitor.cookie -> (cookie: %s)', cookie)
@@ -275,6 +283,8 @@ module Kameleoon
275
283
  @data.cookie = data
276
284
  when OperatingSystem
277
285
  @data.set_operating_system(data, overwrite)
286
+ when ApplicationVersion
287
+ @data.set_application_version(data, overwrite)
278
288
  when Geolocation
279
289
  @data.set_geolocation(data, overwrite)
280
290
  when KcsHeat
@@ -305,7 +315,8 @@ module Kameleoon
305
315
  end
306
316
 
307
317
  class VisitorData
308
- attr_reader :time_started, :mutex, :device, :browser, :geolocation, :operating_system, :visitor_visits
318
+ attr_reader :time_started, :mutex, :device, :browser, :geolocation, :operating_system, :visitor_visits,
319
+ :application_version
309
320
  attr_accessor :last_activity_time, :legal_consent, :user_agent, :cookie, :kcs_heat, :cbscores,
310
321
  :mapping_identifier, :forced_variations, :simulated_variations
311
322
 
@@ -462,6 +473,10 @@ module Kameleoon
462
473
  @operating_system = operating_system if overwrite || @operating_system.nil?
463
474
  end
464
475
 
476
+ def set_application_version(application_version, overwrite)
477
+ @application_version = application_version if overwrite || @application_version.nil?
478
+ end
479
+
465
480
  def set_cbscores(cbs, overwrite)
466
481
  @cbscores = cbs if overwrite || @cbscores.nil?
467
482
  end
@@ -64,6 +64,16 @@ module Kameleoon
64
64
  visitor
65
65
  end
66
66
 
67
+ def peek_visitor(visitor_code)
68
+ Logging::KameleoonLogger.debug("CALL: VisitorManager.peek_visitor(visitor_code: '%s')", visitor_code)
69
+
70
+ visitor = @visitors[visitor_code]
71
+
72
+ Logging::KameleoonLogger.debug("RETURN: VisitorManager.peek_visitor(visitor_code: '%s') -> (visitor: %s)",
73
+ visitor_code, visitor)
74
+ visitor
75
+ end
76
+
67
77
  def enumerate(&blk)
68
78
  @visitors.each_pair { |vc, v| blk.call(vc, v) }
69
79
  end
@@ -72,10 +82,10 @@ module Kameleoon
72
82
  @visitors.size
73
83
  end
74
84
 
75
- def add_data(visitor_code, *args, overwrite: true)
85
+ def add_data(visitor_code, *args, overwrite: true, track: true)
76
86
  Logging::KameleoonLogger.debug(
77
- "CALL: VisitorManager.add_data(visitor_code: '%s', args: %s, overwrite: %s)",
78
- visitor_code, args, overwrite
87
+ "CALL: VisitorManager.add_data(visitor_code: '%s', args: %s, overwrite: %s, track: %s)",
88
+ visitor_code, args, overwrite, track
79
89
  )
80
90
  visitor = get_or_create_visitor(visitor_code)
81
91
  cdi = @data_manager.data_file.custom_data_info
@@ -87,12 +97,13 @@ module Kameleoon
87
97
  when Conversion
88
98
  data = process_conversion(data, cdi)
89
99
  end
100
+ data.mark_as_sent if !track && data.respond_to?(:mark_as_sent)
90
101
  args[i] = data
91
102
  end
92
103
  visitor.add_data(*args, overwrite: overwrite)
93
104
  Logging::KameleoonLogger.debug(
94
- "RETURN: VisitorManager.add_data(visitor_code: '%s', args: %s, overwrite: %s) -> (visitor)",
95
- visitor_code, args, overwrite
105
+ "RETURN: VisitorManager.add_data(visitor_code: '%s', args: %s, overwrite: %s, track: %s) -> (visitor)",
106
+ visitor_code, args, overwrite, track
96
107
  )
97
108
  visitor
98
109
  end
@@ -162,17 +162,18 @@ module Kameleoon
162
162
  #
163
163
  # @param [String] visitor_code Visitor code
164
164
  # @param [...Data] data Data to associate with the visitor code
165
+ # @param [Bool] track A boolean indicating whether the data should be tracked (sent to server). Default is true.
165
166
  #
166
167
  # @raise [Kameleoon::Exception::VisitorCodeInvalid] If the visitor code is empty or longer than 255 chars
167
168
  #
168
- def add_data(visitor_code, *args)
169
- Logging::KameleoonLogger.info("CALL: KameleoonClient.add_data(visitor_code: '%s', args: %s)",
170
- visitor_code, args)
169
+ def add_data(visitor_code, *args, track: true)
170
+ Logging::KameleoonLogger.info("CALL: KameleoonClient.add_data(visitor_code: '%s', args: %s, track: %s)",
171
+ visitor_code, args, track)
171
172
  Utils::VisitorCode.validate(visitor_code)
172
- @visitor_manager.add_data(visitor_code, *args)
173
+ @visitor_manager.add_data(visitor_code, *args, track: track)
173
174
  Logging::KameleoonLogger.info(
174
- "RETURN: KameleoonClient.add_data(visitor_code: '%s', args: %s)",
175
- visitor_code, args
175
+ "RETURN: KameleoonClient.add_data(visitor_code: '%s', args: %s, track: %s)",
176
+ visitor_code, args, track
176
177
  )
177
178
  end
178
179
 
@@ -368,8 +369,6 @@ module Kameleoon
368
369
  Utils::VisitorCode.validate(visitor_code)
369
370
  variations = {}
370
371
  @data_manager.data_file.feature_flags.each_value do |feature_flag|
371
- next unless feature_flag.environment_enabled
372
-
373
372
  begin
374
373
  variation_key, eval_exp = get_variation_info(visitor_code, feature_flag, track)
375
374
  rescue Exception::FeatureEnvironmentDisabled
@@ -467,7 +466,7 @@ module Kameleoon
467
466
  raise Exception::FeatureVariableNotFound.new(variable_name),
468
467
  "Feature variable #{variable_name} not found"
469
468
  end
470
- value = _parse_feature_variable(variable)
469
+ value = variable.get_value
471
470
  Logging::KameleoonLogger.info(
472
471
  "RETURN: KameleoonClient.get_feature_variable(visitor_code: '%s', feature_key: '%s', variable_name: '%s', " \
473
472
  'is_unique_identifier: %s) -> (variable: %s)',
@@ -502,12 +501,13 @@ module Kameleoon
502
501
  )
503
502
  feature_flag = @data_manager.data_file.get_feature_flag(feature_key)
504
503
  variation = feature_flag.get_variation_by_key(variation_key)
504
+ @data_manager.data_file.ensure_environment_enabled(feature_flag)
505
505
  if variation.nil?
506
506
  raise Exception::FeatureVariationNotFound.new(variation_key),
507
507
  "Variation key #{variation_key} not found"
508
508
  end
509
509
  variables = {}
510
- variation.variables.each { |var| variables[var.key] = _parse_feature_variable(var) }
510
+ variation.variables.each { |var| variables[var.key] = var.get_value }
511
511
  Logging::KameleoonLogger.info(
512
512
  "RETURN: KameleoonClient.get_feature_variation_variables(feature_key: '%s', variation_key: '%s') " \
513
513
  '-> (variables: %s)', feature_key, variation_key, variables
@@ -606,12 +606,16 @@ module Kameleoon
606
606
  )
607
607
  warehouse_audience
608
608
  end
609
-
610
609
  ##
611
- # Returns a list of all feature flag keys
610
+ # Returns a list of all feature flag keys.
612
611
  #
613
612
  # @return [Array] array of all feature flag keys
613
+ #
614
+ # DEPRECATED. Please use `get_data_file` instead.
614
615
  def get_feature_list # rubocop:disable Naming/AccessorMethodName
616
+ Logging::KameleoonLogger.info(
617
+ '[DEPRECATION] `get_feature_list` is deprecated. Please use `get_data_file` instead.'
618
+ )
615
619
  Logging::KameleoonLogger.info('CALL: KameleoonClient.get_feature_list')
616
620
  features = @data_manager.data_file.feature_flags.keys
617
621
  Logging::KameleoonLogger.info('RETURN: KameleoonClient.get_feature_list -> (features: %s)', features)
@@ -637,8 +641,6 @@ module Kameleoon
637
641
  visitor = @visitor_manager.get_visitor(visitor_code)
638
642
  list_keys = []
639
643
  @data_manager.data_file.feature_flags.each do |feature_key, feature_flag|
640
- next unless feature_flag.environment_enabled
641
-
642
644
  begin
643
645
  eval_exp = evaluate(visitor, visitor_code, feature_flag, false, false)
644
646
  rescue Exception::FeatureEnvironmentDisabled
@@ -676,8 +678,6 @@ module Kameleoon
676
678
  map_active_features = {}
677
679
 
678
680
  @data_manager.data_file.feature_flags.each_value do |feature_flag|
679
- next unless feature_flag.environment_enabled
680
-
681
681
  begin
682
682
  eval_exp = evaluate(visitor, visitor_code, feature_flag, false, false)
683
683
  rescue Exception::FeatureEnvironmentDisabled
@@ -802,41 +802,7 @@ module Kameleoon
802
802
  # @return [Kameleoon::Types::DataFile] The current DataFile instance.
803
803
  def get_data_file
804
804
  Logging::KameleoonLogger.info('CALL: KameleoonClient.get_data_file')
805
-
806
- feature_flags_map = @data_manager.data_file.feature_flags.transform_values do |source_feature_flag|
807
- # Collect variations
808
- variations_map = source_feature_flag.variations.each_with_object({}) do |variation, variations_map|
809
- variables_map = variation.variables.each_with_object({}) do |var, variables_map|
810
- variables_map[var.key] = Types::Variable.new(var.key, var.type, _parse_feature_variable(var))
811
- end
812
- variations_map[variation.key] = Types::Variation.new(variation.key, nil, nil, variables_map, variation.name)
813
- end
814
-
815
- # Collect rules
816
- rules = source_feature_flag.rules.map do |rule|
817
- rule_variations = rule.experiment.variations_by_exposition.each_with_object({}) do |var_by_exp, rule_variations|
818
- base_variation = variations_map[var_by_exp.variation_key]
819
- next unless base_variation
820
- rule_variations[base_variation.key] = Types::Variation.new(
821
- base_variation.key,
822
- var_by_exp.variation_id,
823
- rule.experiment.id,
824
- base_variation.variables,
825
- base_variation.name
826
- )
827
- end
828
- Types::Rule.new(rule_variations)
829
- end
830
-
831
- Types::FeatureFlag.new(
832
- variations_map,
833
- source_feature_flag.environment_enabled,
834
- rules,
835
- source_feature_flag.default_variation_key
836
- )
837
- end
838
-
839
- data_file = Types::DataFile.new(feature_flags_map)
805
+ data_file = @data_manager.external_data_file
840
806
  Logging::KameleoonLogger.info('RETURN: KameleoonClient.get_data_file -> (data_file: %s)', data_file)
841
807
  data_file
842
808
  end
@@ -1014,6 +980,11 @@ module Kameleoon
1014
980
  )
1015
981
  eval_exp = nil
1016
982
  forced_variation = visitor&.get_forced_feature_variation(feature_flag.feature_key)
983
+
984
+ unless forced_variation&.simulated
985
+ @data_manager.data_file.ensure_environment_enabled(feature_flag)
986
+ end
987
+
1017
988
  if forced_variation
1018
989
  eval_exp = EvaluatedExperiment.from_forced_variation(forced_variation)
1019
990
  elsif visitor_not_in_holdout?(visitor, visitor_code, track, save, feature_flag.bucketing_custom_data_index) && \
@@ -1275,21 +1246,10 @@ module Kameleoon
1275
1246
  Logging::KameleoonLogger.debug(
1276
1247
  'CALL: KameleoonClient.create_external_variation(variation: %s, eval_exp: %s)', variation, eval_exp
1277
1248
  )
1278
- ext_variables = {}
1279
- variation&.variables&.each do |variable|
1280
- ext_variables[variable.key] = Types::Variable.new(
1281
- variable.key,
1282
- variable.type,
1283
- _parse_feature_variable(variable)
1284
- )
1285
- end
1286
- ext_variables.freeze
1287
- ext_variation = Types::Variation.new(
1288
- variation&.key || '',
1249
+ ext_variation = Types::Variation._build_from_internal(
1250
+ variation,
1289
1251
  eval_exp&.var_by_exp&.variation_id,
1290
- eval_exp&.experiment&.id,
1291
- ext_variables,
1292
- variation&.name || ''
1252
+ eval_exp&.experiment&.id
1293
1253
  )
1294
1254
  Logging::KameleoonLogger.debug(
1295
1255
  'RETURN: KameleoonClient.create_external_variation(variation: %s, eval_exp: %s) -> (ext_variation: %s)',
@@ -1300,18 +1260,6 @@ module Kameleoon
1300
1260
 
1301
1261
  ##
1302
1262
  # helper method for fetching values from a Variable
1303
- def _parse_feature_variable(variable)
1304
- case variable.type
1305
- when 'BOOLEAN', 'STRING', 'NUMBER', 'JS', 'CSS'
1306
- variable.value
1307
- when 'JSON'
1308
- JSON.parse(variable.value)
1309
- else
1310
- Logging::KameleoonLogger.error("Unknown type '#{variable.type}' for feature variable")
1311
- variable.value
1312
- end
1313
- end
1314
-
1315
1263
  def set_unique_identifier(visitor_code, is_unique_identifier)
1316
1264
  Logging::KameleoonLogger.info(
1317
1265
  "The 'isUniqueIdentifier' parameter is deprecated. Please, add 'UniqueIdentifier' to a visitor instead."
@@ -9,8 +9,8 @@ module Kameleoon
9
9
  DEFAULT_SESSION_DURATION_MINUTES = 30
10
10
  DEFAULT_TIMEOUT_MILLISECONDS = 10_000
11
11
  DEFAULT_TRACKING_INTERVAL_MILLISECONDS = 1000
12
- MIN_TRACKING_INTERVAL_MILLISECONDS = 300
13
- MAX_TRACKING_INTERVAL_MILLISECONDS = 1000
12
+ MIN_TRACKING_INTERVAL_MILLISECONDS = 1000
13
+ MAX_TRACKING_INTERVAL_MILLISECONDS = 5000
14
14
 
15
15
  attr_reader :client_id, :client_secret, :refresh_interval_second, :session_duration_second,
16
16
  :default_timeout_millisecond, :tracking_interval_second, :environment, :top_level_domain,
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'kameleoon/types/data_file'
4
+
3
5
  module Kameleoon
4
6
  module Managers
5
7
  module Data
@@ -13,7 +15,11 @@ module Kameleoon
13
15
  end
14
16
 
15
17
  def data_file=(value)
16
- @container = Container.new(value)
18
+ @container = Container.new(value, create_external_data_file(value))
19
+ end
20
+
21
+ def external_data_file
22
+ @container.external_data_file
17
23
  end
18
24
 
19
25
  def visitor_code_managed?
@@ -22,14 +28,22 @@ module Kameleoon
22
28
 
23
29
  class Container
24
30
  attr_reader :data_file, :visitor_code_managed
31
+ attr_reader :external_data_file
25
32
 
26
- def initialize(data_file)
33
+ def initialize(data_file, external_data_file)
27
34
  @data_file = data_file
35
+ @external_data_file = external_data_file
28
36
  # Regarding GDPR policy we should set visitorCode if legal consent isn't required or we have at
29
37
  # least one Targeted Delivery rule in datafile
30
38
  @visitor_code_managed = data_file.settings.is_consent_required && !data_file.has_any_targeted_delivery_rule
31
39
  end
32
40
  end
41
+
42
+ private
43
+
44
+ def create_external_data_file(source_data_file)
45
+ Types::DataFile._build_from_internal(source_data_file)
46
+ end
33
47
  end
34
48
  end
35
49
  end
@@ -32,7 +32,7 @@ module Kameleoon
32
32
 
33
33
  @visitor_codes.each do |visitor_code|
34
34
  if @total_size <= @request_size_limit
35
- visitor = @visitor_manager.get_visitor(visitor_code)
35
+ visitor = @visitor_manager.peek_visitor(visitor_code)
36
36
  is_consent_given = consent_given?(visitor)
37
37
  data = collect_tracking_data(visitor_code, visitor, is_consent_given)
38
38
  if !data.empty?
@@ -5,6 +5,7 @@ require 'net/http'
5
5
  require 'time'
6
6
  require 'kameleoon/utils'
7
7
  require 'kameleoon/logging/kameleoon_logger'
8
+ require 'base64'
8
9
 
9
10
  module Kameleoon
10
11
  module Network
@@ -13,6 +14,7 @@ module Kameleoon
13
14
  TOKEN_OBSOLESCENCE_GAP = 1800 # in seconds
14
15
  JWT_ACCESS_TOKEN_FIELD = 'access_token'
15
16
  JWT_EXPIRES_IN_FIELD = 'expires_in'
17
+ BASIC_AUTHORIZATION_PREFIX = 'Basic '
16
18
 
17
19
  def initialize(network_manager, client_id, client_secret)
18
20
  Logging::KameleoonLogger.debug(lambda {
@@ -23,12 +25,18 @@ module Kameleoon
23
25
  @client_id = client_id
24
26
  @client_secret = client_secret
25
27
  @fetching = false
28
+ @basic_auth_token = AccessTokenSource.construct_basic_token(client_id, client_secret)
26
29
  Logging::KameleoonLogger.debug(lambda {
27
30
  format("RETURN: AccessTokenSource.new(network_manager, client_id: '%s', client_secret: '%s')",
28
31
  Utils::Strval.secret(client_id), Utils::Strval.secret(client_secret))
29
32
  })
30
33
  end
31
34
 
35
+ def self.construct_basic_token(client_id, client_secret)
36
+ basic_token_content = "#{client_id}:#{client_secret}"
37
+ "#{BASIC_AUTHORIZATION_PREFIX}#{Base64.strict_encode64(basic_token_content)}"
38
+ end
39
+
32
40
  def get_token(timeout = nil)
33
41
  Logging::KameleoonLogger.debug('CALL: AccessTokenSource.getToken(timeout: %s)', timeout)
34
42
  now = Time.new.to_i
@@ -70,7 +78,7 @@ module Kameleoon
70
78
 
71
79
  def fetch_token(timeout = nil)
72
80
  Logging::KameleoonLogger.debug('CALL: AccessTokenSource.fetch_token(timeout: %s)', timeout)
73
- response_content = @network_manager.fetch_access_jwtoken(@client_id, @client_secret, timeout)
81
+ response_content = @network_manager.fetch_access_jwtoken(@basic_auth_token, timeout)
74
82
  unless response_content
75
83
  Logging::KameleoonLogger.error('Failed to fetch access JWT')
76
84
  return nil
@@ -17,7 +17,10 @@ module Kameleoon
17
17
  def collect_headers(request)
18
18
  headers = { 'Content-Type' => request.content_type }
19
19
  headers.merge!(request.extra_headers) unless request.extra_headers.nil?
20
- headers['Authorization'] = "Bearer #{request.access_token}" unless request.access_token.nil?
20
+ unless request.access_token.nil? || request.access_token.empty?
21
+ token_prefix = request.access_token.start_with?('Basic') ? '' : 'Bearer '
22
+ headers['Authorization'] = "#{token_prefix}#{request.access_token}"
23
+ end
21
24
  headers
22
25
  end
23
26
 
@@ -70,16 +70,15 @@ module Kameleoon
70
70
  unwrap_response(*make_call(request, true, TRACKING_CALL_ATTEMPT_NUMBER - 1, TRACKING_CALL_RETRY_DELAY))
71
71
  end
72
72
 
73
- def fetch_access_jwtoken(client_id, client_secret, timeout = nil)
73
+ def fetch_access_jwtoken(basic_auth_token, timeout = nil)
74
74
  url = @url_provider.make_access_token_url
75
75
  timeout = ensure_timeout(timeout)
76
76
  data_map = {
77
77
  grant_type: ACCESS_TOKEN_GRANT_TYPE,
78
- client_id: client_id,
79
- client_secret: client_secret
80
78
  }
81
79
  data = UriHelper.encode_query(data_map).encode('UTF-8')
82
80
  request = Request.new(Method::POST, url, ContentType::FORM, timeout, data: data)
81
+ request.authorize(basic_auth_token)
83
82
  unwrap_response(*make_call(request, false))
84
83
  end
85
84
 
@@ -11,12 +11,15 @@ module Kameleoon
11
11
  body = 'null'
12
12
  unless @data.nil?
13
13
  if @data.is_a?(String)
14
- body = @data.start_with?('grant_type=client_credentials') ? '****' : @data
15
- else
16
14
  body = @data
17
15
  end
18
16
  end
19
- "Request{method:'#{@method}',url:'#{@url}',headers:#{@extra_headers},body:'#{body}'}"
17
+
18
+ headers = ''
19
+ headers += 'Authorization: ***' unless access_token.nil?
20
+ headers += @extra_headers.to_s unless @extra_headers.nil?
21
+
22
+ "Request{method:'#{@method}',url:'#{@url}',headers:#{headers},body:'#{body}'}"
20
23
  end
21
24
 
22
25
  def initialize(method, url, content_type, timeout, extra_headers: nil, data: nil)
@@ -22,7 +22,7 @@ module Kameleoon
22
22
  CONFIGURATION_API_URL_FORMAT = 'https://%s/v3/%s'
23
23
  DATA_API_URL_FORMAT = 'https://%s%s?%s'
24
24
  RT_CONFIGURATION_URL_FORMAT = 'https://%s:8110/sse?%s'
25
- ACCESS_TOKEN_URL_FORMAT = 'https://%s/oauth/token'
25
+ ACCESS_TOKEN_URL_FORMAT = 'https://%s/oauth/token?%s'
26
26
 
27
27
  TEST_DATA_API_DOMAIN = 'data.kameleoon.net'
28
28
  TEST_AUTOMATION_API_DOMAIN = 'api.kameleoon.net'
@@ -39,6 +39,15 @@ module Kameleoon
39
39
  @configuration_domain = DEFAULT_CONFIGURATION_DOMAIN
40
40
  @access_token_domain = DEFAULT_ACCESS_TOKEN_DOMAIN
41
41
  @is_custom_domain = false
42
+
43
+ url_params = {
44
+ sdkName: SDK_NAME,
45
+ sdkVersion: SDK_VERSION,
46
+ siteCode: @site_code
47
+ }
48
+ @access_token_url_params = UriHelper.encode_query(url_params)
49
+ url_params[:bodyUa] = true
50
+ @tracking_url_params = UriHelper.encode_query(url_params)
42
51
  update_domains(network_domain)
43
52
  end
44
53
 
@@ -60,7 +69,7 @@ module Kameleoon
60
69
  siteCode: @site_code,
61
70
  bodyUa: true
62
71
  }
63
- format(DATA_API_URL_FORMAT, @data_api_domain, TRACKING_PATH, UriHelper.encode_query(params))
72
+ format(DATA_API_URL_FORMAT, @data_api_domain, TRACKING_PATH, @tracking_url_params)
64
73
  end
65
74
 
66
75
  def make_visitor_data_get_url(visitor_code, filter, is_unique_identifier = false)
@@ -104,11 +113,20 @@ module Kameleoon
104
113
  end
105
114
 
106
115
  def make_access_token_url
107
- format(ACCESS_TOKEN_URL_FORMAT, @access_token_domain)
116
+ format(ACCESS_TOKEN_URL_FORMAT, @access_token_domain, @access_token_url_params)
108
117
  end
109
118
 
110
119
  private
111
120
 
121
+ def make_post_query_base(site_code)
122
+ data_map = {
123
+ "sdkName": Kameleoon::SDK_NAME,
124
+ "sdkVersion": Kameleoon::SDK_VERSION,
125
+ "siteCode": site_code
126
+ }
127
+ data = UriHelper.encode_query(data_map).encode('UTF-8')
128
+ end
129
+
112
130
  def update_domains(network_domain)
113
131
  return if network_domain.nil? || network_domain.empty?
114
132
 
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kameleoon/logging/kameleoon_logger'
4
+
5
+ module Kameleoon
6
+ # SemVersion is a utility class for semantic version comparison
7
+ class SemVersion
8
+ include Comparable
9
+
10
+ attr_reader :major, :minor, :patch
11
+
12
+ def initialize(major = 0, minor = 0, patch = 0)
13
+ @major = major
14
+ @minor = minor
15
+ @patch = patch
16
+ end
17
+
18
+ def <=>(other)
19
+ return nil unless other.is_a?(SemVersion)
20
+
21
+ c = @major <=> other.major
22
+ return c unless c.zero?
23
+
24
+ c = @minor <=> other.minor
25
+ return c unless c.zero?
26
+
27
+ @patch <=> other.patch
28
+ end
29
+
30
+ def to_f
31
+ "#{@major}.#{@minor}".to_f
32
+ end
33
+
34
+ def self.from_string(version_string)
35
+ return nil unless version_string.is_a?(String)
36
+
37
+ versions = [0, 0, 0]
38
+ version_parts = version_string.split('.')
39
+ return nil unless version_parts.length >= 1
40
+
41
+ version_parts.each_with_index do |part, i|
42
+ break if i >= 3
43
+
44
+ begin
45
+ versions[i] = Integer(part)
46
+ rescue ArgumentError
47
+ Logging::KameleoonLogger.error("Invalid version component, index: %s, value: '%s'", i, part)
48
+ return nil
49
+ end
50
+ end
51
+
52
+ SemVersion.new(versions[0], versions[1], versions[2])
53
+ end
54
+ end
55
+ end
@@ -31,6 +31,7 @@ module Kameleoon
31
31
  SAME_DAY_VISITS = 'SAME_DAY_VISITS'
32
32
  NEW_VISITORS = 'NEW_VISITORS'
33
33
  HEAT_SLICE = 'HEAT_SLICE'
34
+ APPLICATION_VERSION = 'APPLICATION_VERSION'
34
35
  end
35
36
 
36
37
  module Operator
@@ -1,4 +1,5 @@
1
1
  require_relative 'conditions/custom_datum'
2
+ require_relative 'conditions/version_condition'
2
3
  require_relative 'conditions/target_experiment_condition'
3
4
  require_relative 'conditions/target_feature_flag_condition'
4
5
  require_relative 'conditions/target_personalization_condition'
@@ -77,6 +78,8 @@ module Kameleoon
77
78
  TimeElapsedSinceVisitCondition.new(condition_json)
78
79
  when ConditionType::HEAT_SLICE
79
80
  KcsHeatRangeCondition.new(condition_json)
81
+ when ConditionType::APPLICATION_VERSION
82
+ VersionCondition.new(condition_json)
80
83
  else
81
84
  Logging::KameleoonLogger.info("Unexpected TargetingConditionType: '%s'", cond_type)
82
85
  UnknownCondition.new(condition_json)
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'kameleoon/data/browser'
4
4
  require 'kameleoon/logging/kameleoon_logger'
5
- require 'kameleoon/sdk_version'
5
+ require 'kameleoon/sem_version'
6
6
 
7
7
  module Kameleoon
8
8
  # @api private
@@ -33,7 +33,7 @@ module Kameleoon
33
33
 
34
34
  return true if @version.nil?
35
35
 
36
- version_number = SdkVersion.get_float_version(@version)
36
+ version_number = SemVersion.from_string(@version)&.to_f || Float::NAN
37
37
  return false if version_number.nan?
38
38
 
39
39
  case @version_match_type
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'kameleoon/data/data'
4
- require 'kameleoon/logging/kameleoon_logger'
5
3
  require 'kameleoon/version'
4
+ require_relative 'version_condition'
6
5
 
7
6
  module Kameleoon
8
7
  # @api private
@@ -18,12 +17,10 @@ module Kameleoon
18
17
  end
19
18
 
20
19
  # SdkLanguageCondition is a condition for checking targeting sdk type and version
21
- class SdkLanguageCondition < Condition
20
+ class SdkLanguageCondition < VersionCondition
22
21
  def initialize(json_condition)
23
22
  super(json_condition)
24
23
  @sdk_language = json_condition['sdkLanguage']
25
- @version = json_condition['version']
26
- @operator = json_condition['versionMatchType']
27
24
  end
28
25
 
29
26
  def check(data)
@@ -33,34 +30,9 @@ module Kameleoon
33
30
  private
34
31
 
35
32
  def check_targeting(sdk_info)
36
- return false if @sdk_language != sdk_info.language
37
-
38
- return true if @version.nil?
39
-
40
- version_components_condition = SdkVersion.get_version_components(@version)
41
- version_components_sdk_info = SdkVersion.get_version_components(sdk_info.version)
42
-
43
- return false if version_components_condition.nil? || version_components_sdk_info.nil?
44
-
45
- major_condition, minor_condition, patch_condition = version_components_condition
46
- major_sdk, minor_sdk, patch_sdk = version_components_sdk_info
47
-
48
- case @operator
49
- when Operator::EQUAL
50
- major_sdk == major_condition && minor_sdk == minor_condition && patch_sdk == patch_condition
51
- when Operator::GREATER
52
- major_sdk > major_condition ||
53
- (major_sdk == major_condition && minor_sdk > minor_condition) ||
54
- (major_sdk == major_condition && minor_sdk == minor_condition && patch_sdk > patch_condition)
55
- when Operator::LOWER
56
- major_sdk < major_condition ||
57
- (major_sdk == major_condition && minor_sdk < minor_condition) ||
58
- (major_sdk == major_condition && minor_sdk == minor_condition && patch_sdk < patch_condition)
59
- else
60
- Logging::KameleoonLogger.error("Unexpected comparing operation for 'SdkLanguage' condition: '#{@operator}'")
61
- false
62
- end
33
+ @sdk_language == sdk_info.language &&
34
+ (@version.nil? || compare_with_version(sdk_info.version))
63
35
  end
64
36
  end
65
37
  end
66
- end
38
+ end
@@ -8,6 +8,7 @@ module Kameleoon
8
8
  # UnknownCondition represents not defined condition, always returns that visitor is targeted (true)
9
9
  class UnknownCondition < Condition
10
10
  def check(_data)
11
+ Logging::KameleoonLogger.warning('Condition of unknown type \'%s\' evaluated as true', type)
11
12
  true
12
13
  end
13
14
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kameleoon/logging/kameleoon_logger'
4
+ require 'kameleoon/sem_version'
5
+ require 'kameleoon/targeting/condition'
6
+
7
+ module Kameleoon
8
+ # @api private
9
+ module Targeting
10
+ # VersionCondition is a base class for conditions that compare versions.
11
+ # Subclasses should implement `check` method and call `compare_with_version` for version comparison.
12
+ class VersionCondition < Condition
13
+ def initialize(json_condition)
14
+ super(json_condition)
15
+ @version = json_condition['version']
16
+ @version_match_type = json_condition['versionMatchType']
17
+ @cached_version_condition = nil
18
+ end
19
+
20
+ def check(data)
21
+ data.is_a?(String) && compare_with_version(data)
22
+ end
23
+
24
+ protected
25
+
26
+ def compare_with_version(version)
27
+ @cached_version_condition ||= SemVersion.from_string(@version)
28
+ version_compare = SemVersion.from_string(version)
29
+
30
+ if @cached_version_condition.nil? || version_compare.nil?
31
+ Logging::KameleoonLogger.error(
32
+ "VersionCondition has unexpected values to compare, condition version: '%s', provided version: '%s'",
33
+ @version, version
34
+ )
35
+ return false
36
+ end
37
+
38
+ case @version_match_type
39
+ when Operator::EQUAL
40
+ version_compare == @cached_version_condition
41
+ when Operator::GREATER
42
+ version_compare > @cached_version_condition
43
+ when Operator::LOWER
44
+ version_compare < @cached_version_condition
45
+ else
46
+ Logging::KameleoonLogger.error(
47
+ "Unexpected comparing operation for '%s' condition: '%s'",
48
+ type, @version_match_type
49
+ )
50
+ false
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -92,6 +92,8 @@ module Kameleoon
92
92
  condition_data = VisitNumberTodayCondition::TargetingData.new(visitor&.time_started, visitor&.visitor_visits)
93
93
  when ConditionType::HEAT_SLICE
94
94
  condition_data = visitor&.kcs_heat
95
+ when ConditionType::APPLICATION_VERSION
96
+ condition_data = visitor&.application_version&.version
95
97
  end
96
98
  Logging::KameleoonLogger.debug(
97
99
  "RETURN: TargetingManager.get_condition_data(type: %s, visitor, visitor_code: '%s', campaign_id: %s) -> " \
@@ -1,18 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'kameleoon/types/feature_flag'
4
+
3
5
  module Kameleoon
4
6
  module Types
5
7
  # DataFile
6
8
  class DataFile
7
- attr_reader :feature_flags
9
+ attr_reader :feature_flags, :date_modified
8
10
 
9
11
  # @api private
10
- def initialize(feature_flags)
12
+ def initialize(feature_flags, date_modified)
11
13
  @feature_flags = feature_flags
14
+ @date_modified = date_modified
15
+ end
16
+
17
+ # @api private
18
+ def self._build_from_internal(source_data_file)
19
+ feature_flags = (source_data_file.feature_flags || {}).transform_values do |feature_flag|
20
+ FeatureFlag._build_from_internal(feature_flag)
21
+ end
22
+ DataFile.new(feature_flags, source_data_file.date_modified)
12
23
  end
13
24
 
14
25
  def to_s
15
- "DataFile{feature_flags:#{@feature_flags}}"
26
+ "DataFile{feature_flags:#{@feature_flags},date_modified:#{@date_modified}}"
16
27
  end
17
28
  end
18
29
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'kameleoon/types/rule'
4
+ require 'kameleoon/types/variation'
5
+
3
6
  module Kameleoon
4
7
  module Types
5
8
  # FeatureFlag
@@ -18,6 +21,25 @@ module Kameleoon
18
21
  @variations[@default_variation_key]
19
22
  end
20
23
 
24
+ # @api private
25
+ def self._build_from_internal(source_feature_flag)
26
+ variations = (source_feature_flag.variations || []).each_with_object({}) do |variation, result|
27
+ ext_variation = Variation._build_from_internal(variation)
28
+ result[ext_variation.key] = ext_variation
29
+ end
30
+
31
+ rules = (source_feature_flag.rules || []).map do |rule|
32
+ Rule._build_from_internal(rule, variations)
33
+ end
34
+
35
+ FeatureFlag.new(
36
+ variations,
37
+ source_feature_flag.environment_enabled,
38
+ rules,
39
+ source_feature_flag.default_variation_key
40
+ )
41
+ end
42
+
21
43
  def to_s
22
44
  "FeatureFlag{variations:#{@variations},environment_enabled:#{@environment_enabled},rules:#{@rules},default_variation_key:#{@default_variation_key}}"
23
45
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'kameleoon/types/variation'
4
+
3
5
  module Kameleoon
4
6
  module Types
5
7
  # Rule
@@ -11,6 +13,25 @@ module Kameleoon
11
13
  @variations = variations
12
14
  end
13
15
 
16
+ # @api private
17
+ def self._build_from_internal(internal_rule, variations)
18
+ rule_variations = {}
19
+ vars_by_exposition = internal_rule.experiment&.variations_by_exposition || []
20
+ vars_by_exposition.each do |var_by_exp|
21
+ base_variation = variations[var_by_exp.variation_key]
22
+ next if base_variation.nil?
23
+
24
+ rule_variations[base_variation.key] = Variation.new(
25
+ base_variation.key,
26
+ var_by_exp.variation_id,
27
+ internal_rule.experiment&.id,
28
+ base_variation.variables,
29
+ base_variation.name
30
+ )
31
+ end
32
+ Rule.new(rule_variations)
33
+ end
34
+
14
35
  def to_s
15
36
  "Rule{variations:#{@variations}}"
16
37
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
4
+ require 'kameleoon/logging/kameleoon_logger'
5
+
3
6
  module Kameleoon
4
7
  module Types
5
8
  # Variable
@@ -16,6 +19,11 @@ module Kameleoon
16
19
  @type = type
17
20
  @value = value
18
21
  end
22
+
23
+ # @api private
24
+ def self._build_from_internal(source_variable)
25
+ Variable.new(source_variable.key, source_variable.type, source_variable.get_value)
26
+ end
19
27
  end
20
28
  end
21
29
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'kameleoon/configuration/variation'
4
+ require 'kameleoon/types/variable'
4
5
 
5
6
  module Kameleoon
6
7
  module Types
@@ -21,6 +22,17 @@ module Kameleoon
21
22
  @name = name
22
23
  end
23
24
 
25
+ # @api private
26
+ def self._build_from_internal(source_variation, variation_id = nil, experiment_id = nil)
27
+ variables = (source_variation&.variables || []).each_with_object({}) do |variable, result|
28
+ ext_variable = Variable._build_from_internal(variable)
29
+ result[ext_variable.key] = ext_variable
30
+ end
31
+ key = source_variation&.key || ''
32
+ name = source_variation&.name || ''
33
+ Variation.new(key, variation_id, experiment_id, variables, name)
34
+ end
35
+
24
36
  def active?
25
37
  @key != Configuration::VariationType::VARIATION_OFF
26
38
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kameleoon
4
- SDK_VERSION = '3.17.3'
4
+ SDK_VERSION = '3.19.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.17.3
4
+ version: 3.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kameleoon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-01-22 00:00:00.000000000 Z
11
+ date: 2026-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: em-http-request
@@ -86,6 +86,7 @@ files:
86
86
  - lib/kameleoon/configuration/variable.rb
87
87
  - lib/kameleoon/configuration/variation.rb
88
88
  - lib/kameleoon/configuration/variation_exposition.rb
89
+ - lib/kameleoon/data/application_version.rb
89
90
  - lib/kameleoon/data/browser.rb
90
91
  - lib/kameleoon/data/cbscores.rb
91
92
  - lib/kameleoon/data/conversion.rb
@@ -145,7 +146,7 @@ files:
145
146
  - lib/kameleoon/real_time/sse_client.rb
146
147
  - lib/kameleoon/real_time/sse_message.rb
147
148
  - lib/kameleoon/real_time/sse_request.rb
148
- - lib/kameleoon/sdk_version.rb
149
+ - lib/kameleoon/sem_version.rb
149
150
  - lib/kameleoon/storage/cache.rb
150
151
  - lib/kameleoon/storage/cache_factory.rb
151
152
  - lib/kameleoon/targeting/condition.rb
@@ -172,6 +173,7 @@ files:
172
173
  - lib/kameleoon/targeting/conditions/target_personalization_condition.rb
173
174
  - lib/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.rb
174
175
  - lib/kameleoon/targeting/conditions/unknown_condition.rb
176
+ - lib/kameleoon/targeting/conditions/version_condition.rb
175
177
  - lib/kameleoon/targeting/conditions/visit_number_today_condition.rb
176
178
  - lib/kameleoon/targeting/conditions/visit_number_total_condition.rb
177
179
  - lib/kameleoon/targeting/conditions/visitor_code_condition.rb
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'kameleoon/logging/kameleoon_logger'
4
-
5
- module Kameleoon
6
- # SdkManager is a helper method for fetching / obtaining version of SDK from string
7
- class SdkVersion
8
- def self.get_version_components(version_string)
9
- versions = [0, 0, 0]
10
-
11
- version_parts = version_string.split('.')
12
- version_parts.each_with_index do |part, i|
13
- versions[i] = Integer(part)
14
- rescue ArgumentError
15
- Logging::KameleoonLogger.error('Invalid version component, index: %s, value: %s', i, part)
16
- return nil
17
- end
18
- versions
19
- end
20
-
21
- def self.get_float_version(version_string)
22
- version_components = get_version_components(version_string)
23
-
24
- return Float::NAN if version_components.nil?
25
-
26
- major = version_components[0]
27
- minor = version_components[1]
28
- "#{major}.#{minor}".to_f
29
- end
30
- end
31
- end