kameleoon-client-ruby 3.8.0 → 3.9.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: a64d8edfee07c22561b166de49f9185d89a6fbdec9b49f6fd65860125bd54eab
4
- data.tar.gz: ee7ccf78d0d11dec198b930e77e496c39a220b87471d724015c78114b85368f8
3
+ metadata.gz: 8d0ea98aa7ca7ea1585f83f6bd231aa577a774124b4332d18ca4e2c2649bfbc2
4
+ data.tar.gz: ec43717ed1dd3a61828a9c062f10040a7e214e070f30f6deb2a76bec9d60fb76
5
5
  SHA512:
6
- metadata.gz: ccfba38b35f50d2b1dda0ef2bf31406f74fd92663276f4297ae867bc7b88b8606b345a8a4234f24ef71c71fdc3555cc9852d7324c1a6a668ed8b6cbc98cfeedb
7
- data.tar.gz: 38543c67b7c8949ccba5c8e0f08eae86d2755a737bc25a5dc82e94dd92011c7678cb4b32647ffae0edb606913bff537455f2f42295fe9f421554726a57675808
6
+ metadata.gz: bec6bd1d823d247b5b1e561e621f454e4d451bec12fb1312dc2a9f348f1e2ccbcc884e6927bae254da107e6314e4d91acad9bb1ef67012d96b62a34253f2978f
7
+ data.tar.gz: d5f5c2c4d85b5d2f706d35fc77f3bc5ce8b6e24ce56413e5d9086fd95aae0d8adf1bbe37a6b5d041f389575db0c8c3815e005a78a7a9d45f255a9325b4f11c46
@@ -3,15 +3,16 @@
3
3
  require 'kameleoon/configuration/custom_data_info'
4
4
  require 'kameleoon/configuration/experiment'
5
5
  require 'kameleoon/configuration/feature_flag'
6
+ require 'kameleoon/configuration/me_group'
6
7
  require 'kameleoon/configuration/settings'
7
8
  require 'kameleoon/logging/kameleoon_logger'
8
9
 
9
10
  module Kameleoon
10
11
  module Configuration
11
12
  class DataFile
12
- attr_reader :settings, :feature_flags, :has_any_targeted_delivery_rule, :feature_flag_by_id, :rule_by_segment_id,
13
- :rule_info_by_exp_id, :variation_by_id, :custom_data_info, :experiment_ids_with_js_css_variable,
14
- :holdout
13
+ attr_reader :settings, :feature_flags, :me_groups, :has_any_targeted_delivery_rule, :feature_flag_by_id,
14
+ :rule_by_segment_id, :rule_info_by_exp_id, :variation_by_id, :custom_data_info,
15
+ :experiment_ids_with_js_css_variable, :holdout
15
16
 
16
17
  def to_s
17
18
  'DataFile{' \
@@ -51,6 +52,7 @@ module Kameleoon
51
52
  Logging::KameleoonLogger.debug('CALL: DataFile.init_default')
52
53
  @settings = Settings.new
53
54
  @feature_flags = {}
55
+ @me_groups = {}
54
56
  @has_any_targeted_delivery_rule = false
55
57
  @custom_data_info = Kameleoon::Configuration::CustomDataInfo.new(nil)
56
58
  Logging::KameleoonLogger.debug('RETURN: DataFile.init_default')
@@ -64,6 +66,7 @@ module Kameleoon
64
66
  ff = FeatureFlag.new(raw)
65
67
  @feature_flags[ff.feature_key] = ff
66
68
  end
69
+ @me_groups = make_me_groups(@feature_flags)
67
70
  @has_any_targeted_delivery_rule = any_targeted_delivery_rule?
68
71
  @custom_data_info = CustomDataInfo.new(configuration['customData'])
69
72
  @holdout = Experiment.from_json(configuration['holdout']) if configuration.include?('holdout')
@@ -101,6 +104,21 @@ module Kameleoon
101
104
  @experiment_ids_with_js_css_variable.freeze
102
105
  end
103
106
 
107
+ def make_me_groups(feature_flags)
108
+ me_group_lists = {}
109
+ feature_flags.each_value do |feature_flag|
110
+ next if feature_flag.me_group_name.nil?
111
+
112
+ me_group_list = me_group_lists[feature_flag.me_group_name]
113
+ if me_group_list
114
+ me_group_list.push(feature_flag)
115
+ else
116
+ me_group_lists[feature_flag.me_group_name] = [feature_flag]
117
+ end
118
+ end
119
+ me_group_lists.transform_values { |me_group_list| MEGroup.new(me_group_list) }
120
+ end
121
+
104
122
  def feature_flag_variable_js_css?(feature_flag)
105
123
  feature_flag.variations.first&.variables&.any? do |variable|
106
124
  %w[JS CSS].include?(variable.type)
@@ -8,7 +8,7 @@ module Kameleoon
8
8
  module Configuration
9
9
  # Class for manage all feature flags with rules
10
10
  class FeatureFlag
11
- attr_accessor :id, :feature_key, :variations, :default_variation_key, :environment_enabled, :rules
11
+ attr_accessor :id, :feature_key, :variations, :default_variation_key, :me_group_name, :environment_enabled, :rules
12
12
 
13
13
  def self.create_from_array(array)
14
14
  array&.map { |it| FeatureFlag.new(it) }
@@ -16,10 +16,11 @@ module Kameleoon
16
16
 
17
17
  def to_s
18
18
  'FeatureFlag{' \
19
- "id:#{@id}, " \
20
- "feature_key:#{@feature_key}, " \
21
- "environment_enabled:#{@environment_enabled}, " \
22
- "default_variation_key:#{@default_variation_key}, " \
19
+ "id:#{@id}," \
20
+ "feature_key:'#{@feature_key}'," \
21
+ "environment_enabled:#{@environment_enabled}," \
22
+ "default_variation_key:'#{@default_variation_key}'," \
23
+ "me_group_name:'#{@me_group_name}'," \
23
24
  "rules:#{@rules.size}" \
24
25
  '}'
25
26
  end
@@ -29,6 +30,7 @@ module Kameleoon
29
30
  @feature_key = hash['featureKey']
30
31
  @variations = Variation.create_from_array(hash['variations'])
31
32
  @default_variation_key = hash['defaultVariationKey']
33
+ @me_group_name = hash['mutuallyExclusiveGroup']
32
34
  @environment_enabled = hash['environmentEnabled']
33
35
  @rules = Rule.create_from_array(hash['rules'])
34
36
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kameleoon
4
+ module Configuration
5
+ class MEGroup
6
+ attr_reader :feature_flags
7
+
8
+ def initialize(feature_flags)
9
+ @feature_flags = feature_flags.sort { |a, b| a.id <=> b.id }
10
+ end
11
+
12
+ def get_feature_flag_by_hash(hash)
13
+ idx = (hash * @feature_flags.size).to_i
14
+ idx = @feature_flags.size - 1 if idx >= @feature_flags.size
15
+ @feature_flags[idx]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -922,37 +922,62 @@ module Kameleoon
922
922
  forced_variation = visitor&.get_forced_feature_variation(feature_flag.feature_key)
923
923
  if forced_variation
924
924
  eval_exp = EvaluatedExperiment.from_forced_variation(forced_variation)
925
- elsif visitor_not_in_holdout?(visitor, visitor_code, track, save)
925
+ elsif visitor_not_in_holdout?(visitor, visitor_code, track, save) && \
926
+ ff_unrestricted_by_me_group?(visitor, visitor_code, feature_flag)
926
927
  eval_exp = _calculate_variation_key_for_feature(visitor_code, feature_flag)
927
928
  end
928
929
  save_variation(visitor_code, eval_exp, track: track) if save && !forced_variation&.simulated
929
930
  Logging::KameleoonLogger.debug(
930
931
  "RETURN: KameleoonClient.evaluate(visitor, visitor_code: '%s', feature_flag: %s, track: %s, save: %s)" \
931
- ' -> (eval_exp: %s)',
932
- visitor_code, feature_flag, track, save, eval_exp
932
+ ' -> (eval_exp: %s)', visitor_code, feature_flag, track, save, eval_exp
933
933
  )
934
934
  eval_exp
935
935
  end
936
936
 
937
+ def ff_unrestricted_by_me_group?(visitor, visitor_code, feature_flag)
938
+ return true if feature_flag.me_group_name.nil?
939
+
940
+ Logging::KameleoonLogger.debug(
941
+ "CALL: KameleoonClient.ff_unrestricted_by_me_group?(visitor, visitor_code: '%s', feature_flag: %s)",
942
+ visitor_code, feature_flag
943
+ )
944
+ unrestricted = true
945
+ me_group = @data_manager.data_file.me_groups[feature_flag.me_group_name]
946
+ if me_group
947
+ code_for_hash = get_code_for_hash(visitor, visitor_code)
948
+ me_group_hash = Utils::Hasher.obtain_hash_for_me_group(code_for_hash, feature_flag.me_group_name)
949
+ Logging::KameleoonLogger.debug(
950
+ "Calculated ME group hash %s for code: '%s', meGroup: '%s'",
951
+ me_group_hash, code_for_hash, feature_flag.me_group_name
952
+ )
953
+ unrestricted = me_group.get_feature_flag_by_hash(me_group_hash) == feature_flag
954
+ end
955
+ Logging::KameleoonLogger.debug(
956
+ "RETURN: KameleoonClient.ff_unrestricted_by_me_group?(visitor, visitor_code: '%s', feature_flag: %s)" \
957
+ ' -> (unrestricted: %s)', visitor_code, feature_flag, unrestricted
958
+ )
959
+ unrestricted
960
+ end
961
+
937
962
  def visitor_not_in_holdout?(visitor, visitor_code, track, save)
963
+ holdout = @data_manager.data_file.holdout
964
+ return true if holdout.nil?
965
+
938
966
  in_holdout_variation_key = 'in-holdout'
939
967
  Logging::KameleoonLogger.debug(
940
968
  "CALL: KameleoonClient.visitor_not_in_holdout?(visitor, visitor_code: '%s', track: %s, save: %s)",
941
969
  visitor_code, track, save
942
970
  )
943
- holdout = @data_manager.data_file.holdout
944
971
  is_not_in_holdout = true
945
- unless holdout.nil?
946
- code_for_hash = get_code_for_hash(visitor, visitor_code)
947
- variation_hash = Utils::Hasher.obtain(code_for_hash, holdout.id)
948
- Logging::KameleoonLogger.debug("Calculated holdout hash %s for code '%s'", variation_hash, code_for_hash)
949
- var_by_exp = holdout.get_variation(variation_hash)
950
- unless var_by_exp.nil?
951
- is_not_in_holdout = var_by_exp.variation_key != in_holdout_variation_key
952
- if save
953
- eval_exp = EvaluatedExperiment.new(var_by_exp, holdout, Configuration::RuleType::EXPERIMENTATION)
954
- save_variation(visitor_code, eval_exp, track: track)
955
- end
972
+ code_for_hash = get_code_for_hash(visitor, visitor_code)
973
+ variation_hash = Utils::Hasher.obtain(code_for_hash, holdout.id)
974
+ Logging::KameleoonLogger.debug("Calculated holdout hash %s for code '%s'", variation_hash, code_for_hash)
975
+ var_by_exp = holdout.get_variation(variation_hash)
976
+ unless var_by_exp.nil?
977
+ is_not_in_holdout = var_by_exp.variation_key != in_holdout_variation_key
978
+ if save
979
+ eval_exp = EvaluatedExperiment.new(var_by_exp, holdout, Configuration::RuleType::EXPERIMENTATION)
980
+ save_variation(visitor_code, eval_exp, track: track)
956
981
  end
957
982
  end
958
983
  Logging::KameleoonLogger.debug(
@@ -38,6 +38,10 @@ module Kameleoon
38
38
  calculate("#{visitor_code}#{container_id}#{suffix}")
39
39
  end
40
40
 
41
+ def self.obtain_hash_for_me_group(visitor_code, me_group_name)
42
+ calculate("#{visitor_code}#{me_group_name}")
43
+ end
44
+
41
45
  def self.calculate(string_to_hash)
42
46
  parsed_value = Digest::SHA256.hexdigest(string_to_hash.encode('UTF-8')).to_i(16)
43
47
  max_value = BigDecimal('2')**BigDecimal('256')
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kameleoon
4
- SDK_VERSION = '3.8.0'
4
+ SDK_VERSION = '3.9.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.8.0
4
+ version: 3.9.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-02-10 00:00:00.000000000 Z
11
+ date: 2025-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: em-http-request
@@ -80,6 +80,7 @@ files:
80
80
  - lib/kameleoon/configuration/data_file.rb
81
81
  - lib/kameleoon/configuration/experiment.rb
82
82
  - lib/kameleoon/configuration/feature_flag.rb
83
+ - lib/kameleoon/configuration/me_group.rb
83
84
  - lib/kameleoon/configuration/rule.rb
84
85
  - lib/kameleoon/configuration/settings.rb
85
86
  - lib/kameleoon/configuration/variable.rb