statsig 2.0.1 → 2.8.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: '059ef73434d227fde96790307f75b6922f1dbd840f3e7afca68c4600f217263d'
4
- data.tar.gz: 7eb241bdd104280ee49117094859ba9b9801747c32a2b4e8ed043b96e336a812
3
+ metadata.gz: 20ee1f5defc13286856fb81276a04db5e1078cc0b0c88223a4a361e71e8c2949
4
+ data.tar.gz: fd32bbe80668331c751091a7d9ddfad05c50eb1c2c37c037a50672731415af30
5
5
  SHA512:
6
- metadata.gz: b0b92e135f883955bd187971886822959656c644a9573f96de043c342f2930787152c0c16b293d8ed33cda25559dcd1298f9578056fc049a2042752a168ef0b1
7
- data.tar.gz: c0103fd2da0b70705540e391aa6afc2bfcd81a37a1dfa01791032aeb43b258ff782caf6eba8c8e4188b15d8676a643d8764a2bc9b6f2e9a022b07455fec221c3
6
+ metadata.gz: c42d83f65d9689eb181d54eb23e703962550270fd82950c808f34d5e1ce45098ebaa1e89860cc35e0fff20c5efd528bf335cb06a897ef7b0486159c4a3a0af22
7
+ data.tar.gz: 0c41f82dc93999a11e9419cd008d7dcdeb74c42c2d11208ce3ed13168ec3e13a42d2fc4fd6314b5717a51ea1d57ba2c6880b010b4ae3fb131a59bbf2b9def55e
data/lib/api_config.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'constants'
1
+ require_relative 'constants'
2
2
 
3
3
  class UnsupportedConfigException < StandardError
4
4
  end
@@ -1,7 +1,6 @@
1
+ require_relative 'constants'
1
2
  require_relative 'hash_utils'
2
3
 
3
- require 'constants'
4
-
5
4
  module Statsig
6
5
  class ResponseFormatter
7
6
  def self.get_responses(
@@ -31,7 +30,6 @@ module Statsig
31
30
  end
32
31
 
33
32
  def self.to_response(config_name, config_spec, evaluator, user, client_sdk_key, hash_algo, include_exposures, include_local_overrides)
34
- config_name_str = config_name.to_s
35
33
  category = config_spec[:type]
36
34
  entity_type = config_spec[:entity]
37
35
  if entity_type == Const::TYPE_SEGMENT || entity_type == Const::TYPE_HOLDOUT
@@ -47,11 +45,13 @@ module Statsig
47
45
  end
48
46
  end
49
47
 
48
+ config_name_str = config_name.to_s
50
49
  if local_override.nil?
51
50
  eval_result = ConfigResult.new(
52
51
  name: config_name,
53
52
  disable_evaluation_details: true,
54
- disable_exposures: !include_exposures
53
+ disable_exposures: !include_exposures,
54
+ include_local_overrides: include_local_overrides
55
55
  )
56
56
  evaluator.eval_spec(config_name_str, user, config_spec, eval_result)
57
57
  else
@@ -73,6 +73,7 @@ module Statsig
73
73
  result[:value] = eval_result.json_value
74
74
  result[:group] = eval_result.rule_id
75
75
  result[:is_device_based] = id_type.is_a?(String) && id_type.downcase == Statsig::Const::STABLEID
76
+ result[:passed] = eval_result.gate_value
76
77
  else
77
78
  return nil
78
79
  end
@@ -92,12 +93,26 @@ module Statsig
92
93
  result[:rule_id] = eval_result.rule_id
93
94
 
94
95
  if include_exposures
95
- result[:secondary_exposures] = eval_result.secondary_exposures
96
+ result[:secondary_exposures] = hash_exposures(eval_result.secondary_exposures, hash_algo)
96
97
  end
97
98
 
98
99
  [hashed_name, result]
99
100
  end
100
101
 
102
+ def self.hash_exposures(exposures, hash_algo)
103
+ return nil if exposures.nil?
104
+ hashed_exposures = []
105
+ exposures.each do |exp|
106
+ hashed_exposures << {
107
+ gate: hash_name(exp[:gate], hash_algo),
108
+ gateValue: exp[:gateValue],
109
+ ruleID: exp[:ruleID]
110
+ }
111
+ end
112
+
113
+ hashed_exposures
114
+ end
115
+
101
116
  def self.populate_experiment_fields(config_name, config_spec, eval_result, result, evaluator)
102
117
  result[:is_user_in_experiment] = eval_result.is_experiment_group
103
118
  result[:is_experiment_active] = config_spec[:isActive] == true
@@ -108,14 +123,6 @@ module Statsig
108
123
 
109
124
  result[:is_in_layer] = true
110
125
  result[:explicit_parameters] = config_spec[:explicitParameters] || []
111
-
112
- layer_name = evaluator.spec_store.experiment_to_layer[config_name]
113
- if layer_name.nil? || evaluator.spec_store.layers[layer_name].nil?
114
- return
115
- end
116
-
117
- layer = evaluator.spec_store.layers[layer_name]
118
- result[:value] = layer[:defaultValue].merge(result[:value])
119
126
  end
120
127
 
121
128
  def self.populate_layer_fields(config_spec, eval_result, result, evaluator, hash_algo, include_exposures)
@@ -132,18 +139,20 @@ module Statsig
132
139
  end
133
140
 
134
141
  if include_exposures
135
- result[:undelegated_secondary_exposures] = eval_result.undelegated_sec_exps || []
142
+ result[:undelegated_secondary_exposures] = hash_exposures(eval_result.undelegated_sec_exps || [], hash_algo)
136
143
  end
137
144
  end
138
145
 
139
146
  def self.hash_name(name, hash_algo)
140
- case hash_algo
141
- when Statsig::Const::NONE
142
- return name
143
- when Statsig::Const::DJB2
144
- return Statsig::HashUtils.djb2(name)
145
- else
146
- return Statsig::HashUtils.sha256(name)
147
+ Statsig::Memo.for_global(:hash_name, "#{hash_algo}|#{name}") do
148
+ case hash_algo
149
+ when Statsig::Const::NONE
150
+ name
151
+ when Statsig::Const::DJB2
152
+ Statsig::HashUtils.djb2(name)
153
+ else
154
+ Statsig::HashUtils.sha256(name)
155
+ end
147
156
  end
148
157
  end
149
158
  end
data/lib/config_result.rb CHANGED
@@ -16,6 +16,12 @@ module Statsig
16
16
  attr_accessor :target_app_ids
17
17
  attr_accessor :disable_evaluation_details
18
18
  attr_accessor :disable_exposures
19
+ attr_accessor :config_version
20
+ attr_accessor :include_local_overrides
21
+ attr_accessor :forward_all_exposures
22
+ attr_accessor :sampling_rate
23
+ attr_accessor :has_seen_analytical_gates
24
+ attr_accessor :override_config_name
19
25
 
20
26
  def initialize(
21
27
  name:,
@@ -31,7 +37,13 @@ module Statsig
31
37
  id_type: nil,
32
38
  target_app_ids: nil,
33
39
  disable_evaluation_details: false,
34
- disable_exposures: false
40
+ disable_exposures: false,
41
+ config_version: nil,
42
+ include_local_overrides: true,
43
+ forward_all_exposures: false,
44
+ sampling_rate: nil,
45
+ has_seen_analytical_gates: false,
46
+ override_config_name: nil
35
47
  )
36
48
  @name = name
37
49
  @gate_value = gate_value
@@ -48,6 +60,12 @@ module Statsig
48
60
  @target_app_ids = target_app_ids
49
61
  @disable_evaluation_details = disable_evaluation_details
50
62
  @disable_exposures = disable_exposures
63
+ @config_version = config_version
64
+ @include_local_overrides = include_local_overrides
65
+ @forward_all_exposures = forward_all_exposures
66
+ @sampling_rate = sampling_rate
67
+ @has_seen_analytical_gates = has_seen_analytical_gates
68
+ @override_config_name = override_config_name
51
69
  end
52
70
 
53
71
  def self.from_user_persisted_values(config_name, user_persisted_values)
@@ -67,7 +85,8 @@ module Statsig
67
85
  init_time: @init_time,
68
86
  group_name: @group_name,
69
87
  id_type: @id_type,
70
- target_app_ids: @target_app_ids
88
+ target_app_ids: @target_app_ids,
89
+ override_config_name: @override_config_name
71
90
  }
72
91
  end
73
92
  end
data/lib/constants.rb CHANGED
@@ -29,6 +29,8 @@ module Statsig
29
29
  DISABLED = 'disabled'.freeze
30
30
  DJB2 = 'djb2'.freeze
31
31
  EMAIL = 'email'.freeze
32
+ EXPLORE = ':explore'.freeze
33
+ FAILS_TARGETING = 'inlineTargetingRules'.freeze
32
34
  FALSE = 'false'.freeze
33
35
  IP = 'ip'.freeze
34
36
  LAYER = :layer
@@ -39,6 +41,7 @@ module Statsig
39
41
  OSNAME = 'osname'.freeze
40
42
  OSVERSION = 'osversion'.freeze
41
43
  OVERRIDE = 'override'.freeze
44
+ PRESTART = 'prestart'.freeze
42
45
  Q_RIGHT_CHEVRON = 'Q>'.freeze
43
46
  STABLEID = 'stableid'.freeze
44
47
  STATSIG_RUBY_SDK = 'statsig-ruby-sdk'.freeze
@@ -123,5 +126,11 @@ module Statsig
123
126
  # API Operators (Segments)
124
127
  OP_IN_SEGMENT_LIST = 'in_segment_list'.freeze
125
128
  OP_NOT_IN_SEGMENT_LIST = 'not_in_segment_list'.freeze
129
+
130
+ # API Operators (Array)
131
+ OP_ARRAY_CONTAINS_ANY = 'array_contains_any'.freeze
132
+ OP_ARRAY_CONTAINS_NONE = 'array_contains_none'.freeze
133
+ OP_ARRAY_CONTAINS_ALL = 'array_contains_all'.freeze
134
+ OP_NOT_ARRAY_CONTAINS_ALL = 'not_array_contains_all'.freeze
126
135
  end
127
136
  end
@@ -53,7 +53,19 @@ class DynamicConfig
53
53
  index_sym = index.to_sym
54
54
  return default_value unless @value.key?(index_sym)
55
55
 
56
- return default_value if @value[index_sym].class != default_value.class and default_value.class != TrueClass and default_value.class != FalseClass
57
- @value[index_sym]
56
+ value = @value[index_sym]
57
+
58
+ case default_value
59
+ when Integer
60
+ return value.to_i if value.is_a?(Numeric) && default_value.is_a?(Integer)
61
+ when Float
62
+ return value.to_f if value.is_a?(Numeric) && default_value.is_a?(Float)
63
+ when TrueClass, FalseClass
64
+ return value if [true, false].include?(value)
65
+ else
66
+ return value if value.class == default_value.class
67
+ end
68
+
69
+ default_value
58
70
  end
59
71
  end
@@ -1,4 +1,4 @@
1
- require 'statsig_errors'
1
+ require_relative 'statsig_errors'
2
2
 
3
3
  $endpoint = 'https://statsigapi.net/v1/sdk_exception'
4
4
 
@@ -58,6 +58,18 @@ module EvaluationHelpers
58
58
  end
59
59
  end
60
60
 
61
+ def self.array_contains_any(value, target)
62
+ return false if value.nil? || target.nil?
63
+ value_set = value.to_set
64
+ return target.any? { |item| value_set.include?(item) || value_set.include?(item.to_i) }
65
+ end
66
+
67
+ def self.array_contains_all(value, target)
68
+ return false if value.nil? || target.nil?
69
+ value_set = value.to_set
70
+ return target.all? { |item| value_set.include?(item) || value_set.include?(item.to_i) }
71
+ end
72
+
61
73
  private
62
74
 
63
75
  def self.is_numeric(v)
@@ -73,4 +85,4 @@ module EvaluationHelpers
73
85
  end
74
86
  return time.to_i
75
87
  end
76
- end
88
+ end