statsig 1.31.1 → 1.32.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 +4 -4
- data/lib/api_config.rb +128 -0
- data/lib/client_initialize_helpers.rb +78 -88
- data/lib/config_result.rb +17 -32
- data/lib/constants.rb +60 -0
- data/lib/diagnostics.rb +1 -38
- data/lib/dynamic_config.rb +1 -24
- data/lib/error_boundary.rb +0 -5
- data/lib/evaluation_details.rb +4 -1
- data/lib/evaluation_helpers.rb +35 -3
- data/lib/evaluator.rb +332 -327
- data/lib/feature_gate.rb +0 -24
- data/lib/id_list.rb +1 -1
- data/lib/interfaces/data_store.rb +1 -1
- data/lib/interfaces/user_persistent_storage.rb +1 -1
- data/lib/layer.rb +1 -20
- data/lib/network.rb +6 -33
- data/lib/spec_store.rb +86 -74
- data/lib/statsig.rb +72 -97
- data/lib/statsig_driver.rb +63 -70
- data/lib/statsig_errors.rb +1 -1
- data/lib/statsig_event.rb +8 -8
- data/lib/statsig_logger.rb +21 -21
- data/lib/statsig_options.rb +0 -50
- data/lib/statsig_user.rb +27 -68
- data/lib/ua_parser.rb +1 -1
- data/lib/uri_helper.rb +1 -9
- data/lib/user_persistent_storage_utils.rb +0 -17
- metadata +8 -6
data/lib/statsig_logger.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require 'constants'
|
2
2
|
require 'statsig_event'
|
3
3
|
require 'concurrent-ruby'
|
4
4
|
|
@@ -6,7 +6,7 @@ $gate_exposure_event = 'statsig::gate_exposure'
|
|
6
6
|
$config_exposure_event = 'statsig::config_exposure'
|
7
7
|
$layer_exposure_event = 'statsig::layer_exposure'
|
8
8
|
$diagnostics_event = 'statsig::diagnostics'
|
9
|
-
$ignored_metadata_keys = [
|
9
|
+
$ignored_metadata_keys = [:serverTime, :configSyncTime, :initTime, :reason]
|
10
10
|
module Statsig
|
11
11
|
class StatsigLogger
|
12
12
|
def initialize(network, options, error_boundary)
|
@@ -41,9 +41,9 @@ module Statsig
|
|
41
41
|
event = StatsigEvent.new($gate_exposure_event)
|
42
42
|
event.user = user
|
43
43
|
metadata = {
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
gate: gate_name,
|
45
|
+
gateValue: value.to_s,
|
46
|
+
ruleID: rule_id || Statsig::Const::EMPTY_STR,
|
47
47
|
}
|
48
48
|
return false if not is_unique_exposure(user, $gate_exposure_event, metadata)
|
49
49
|
event.metadata = metadata
|
@@ -59,8 +59,8 @@ module Statsig
|
|
59
59
|
event = StatsigEvent.new($config_exposure_event)
|
60
60
|
event.user = user
|
61
61
|
metadata = {
|
62
|
-
|
63
|
-
|
62
|
+
config: config_name,
|
63
|
+
ruleID: rule_id || Statsig::Const::EMPTY_STR,
|
64
64
|
}
|
65
65
|
return false if not is_unique_exposure(user, $config_exposure_event, metadata)
|
66
66
|
event.metadata = metadata
|
@@ -72,8 +72,8 @@ module Statsig
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def log_layer_exposure(user, layer, parameter_name, config_evaluation, context = nil)
|
75
|
-
exposures = config_evaluation.undelegated_sec_exps
|
76
|
-
allocated_experiment =
|
75
|
+
exposures = config_evaluation.undelegated_sec_exps || []
|
76
|
+
allocated_experiment = Statsig::Const::EMPTY_STR
|
77
77
|
is_explicit = (config_evaluation.explicit_parameters&.include? parameter_name) || false
|
78
78
|
if is_explicit
|
79
79
|
allocated_experiment = config_evaluation.config_delegate
|
@@ -83,13 +83,13 @@ module Statsig
|
|
83
83
|
event = StatsigEvent.new($layer_exposure_event)
|
84
84
|
event.user = user
|
85
85
|
metadata = {
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
86
|
+
config: layer.name,
|
87
|
+
ruleID: layer.rule_id || Statsig::Const::EMPTY_STR,
|
88
|
+
allocatedExperiment: allocated_experiment,
|
89
|
+
parameterName: parameter_name,
|
90
|
+
isExplicitParameter: String(is_explicit)
|
91
91
|
}
|
92
|
-
return false
|
92
|
+
return false unless is_unique_exposure(user, $layer_exposure_event, metadata)
|
93
93
|
event.metadata = metadata
|
94
94
|
event.secondary_exposures = exposures.is_a?(Array) ? exposures : []
|
95
95
|
|
@@ -167,10 +167,10 @@ module Statsig
|
|
167
167
|
return
|
168
168
|
end
|
169
169
|
|
170
|
-
event.metadata[
|
171
|
-
event.metadata[
|
172
|
-
event.metadata[
|
173
|
-
event.metadata[
|
170
|
+
event.metadata[:reason] = eval_details.reason
|
171
|
+
event.metadata[:configSyncTime] = eval_details.config_sync_time
|
172
|
+
event.metadata[:initTime] = eval_details.init_time
|
173
|
+
event.metadata[:serverTime] = eval_details.server_time
|
174
174
|
end
|
175
175
|
|
176
176
|
def safe_add_exposure_context(context, event)
|
@@ -178,8 +178,8 @@ module Statsig
|
|
178
178
|
return
|
179
179
|
end
|
180
180
|
|
181
|
-
if context[
|
182
|
-
event.metadata[
|
181
|
+
if context[:is_manual_exposure]
|
182
|
+
event.metadata[:isManualExposure] = 'true'
|
183
183
|
end
|
184
184
|
end
|
185
185
|
|
data/lib/statsig_options.rb
CHANGED
@@ -1,142 +1,92 @@
|
|
1
|
-
# typed: true
|
2
|
-
|
3
|
-
require 'sorbet-runtime'
|
4
1
|
require_relative 'interfaces/data_store'
|
5
2
|
require_relative 'interfaces/user_persistent_storage'
|
6
3
|
|
7
4
|
##
|
8
5
|
# Configuration options for the Statsig SDK.
|
9
6
|
class StatsigOptions
|
10
|
-
extend T::Sig
|
11
7
|
|
12
|
-
sig { returns(T.any(T::Hash[String, String], NilClass)) }
|
13
8
|
# Hash you can use to set environment variables that apply to all of your users in
|
14
9
|
# the same session and will be used for targeting purposes.
|
15
10
|
# eg. { "tier" => "development" }
|
16
11
|
attr_accessor :environment
|
17
12
|
|
18
|
-
sig { returns(String) }
|
19
13
|
# The base url used to make network calls to Statsig.
|
20
14
|
# default: https://statsigapi.net/v1
|
21
15
|
attr_accessor :api_url_base
|
22
16
|
|
23
17
|
# The base url used specifically to call download_config_specs.
|
24
18
|
# Takes precedence over api_url_base
|
25
|
-
sig { returns(String) }
|
26
19
|
attr_accessor :api_url_download_config_specs
|
27
20
|
|
28
|
-
sig { returns(T.any(Float, Integer)) }
|
29
21
|
# The interval (in seconds) to poll for changes to your Statsig configuration
|
30
22
|
# default: 10s
|
31
23
|
attr_accessor :rulesets_sync_interval
|
32
24
|
|
33
|
-
sig { returns(T.any(Float, Integer)) }
|
34
25
|
# The interval (in seconds) to poll for changes to your id lists
|
35
26
|
# default: 60s
|
36
27
|
attr_accessor :idlists_sync_interval
|
37
28
|
|
38
29
|
# Disable background syncing for rulesets
|
39
|
-
sig { returns(T::Boolean) }
|
40
30
|
attr_accessor :disable_rulesets_sync
|
41
31
|
|
42
32
|
# Disable background syncing for id lists
|
43
|
-
sig { returns(T::Boolean) }
|
44
33
|
attr_accessor :disable_idlists_sync
|
45
34
|
|
46
|
-
sig { returns(T.any(Float, Integer)) }
|
47
35
|
# How often to flush logs to Statsig
|
48
36
|
# default: 60s
|
49
37
|
attr_accessor :logging_interval_seconds
|
50
38
|
|
51
|
-
sig { returns(Integer) }
|
52
39
|
# The maximum number of events to batch before flushing logs to the server
|
53
40
|
# default: 1000
|
54
41
|
attr_accessor :logging_max_buffer_size
|
55
42
|
|
56
|
-
sig { returns(T::Boolean) }
|
57
43
|
# Restricts the SDK to not issue any network requests and only respond with default values (or local overrides)
|
58
44
|
# default: false
|
59
45
|
attr_accessor :local_mode
|
60
46
|
|
61
|
-
sig { returns(T.any(String, NilClass)) }
|
62
47
|
# A string that represents all rules for all feature gates, dynamic configs and experiments.
|
63
48
|
# It can be provided to bootstrap the Statsig server SDK at initialization in case your server runs
|
64
49
|
# into network issue or Statsig is down temporarily.
|
65
50
|
attr_accessor :bootstrap_values
|
66
51
|
|
67
|
-
sig { returns(T.any(Method, Proc, NilClass)) }
|
68
52
|
# A callback function that will be called anytime the rulesets are updated.
|
69
53
|
attr_accessor :rules_updated_callback
|
70
54
|
|
71
|
-
sig { returns(T.any(Statsig::Interfaces::IDataStore, NilClass)) }
|
72
55
|
# A class that extends IDataStore. Can be used to provide values from a
|
73
56
|
# common data store (like Redis) to initialize the Statsig SDK.
|
74
57
|
attr_accessor :data_store
|
75
58
|
|
76
|
-
sig { returns(Integer) }
|
77
59
|
# The number of threads allocated to syncing IDLists.
|
78
60
|
# default: 3
|
79
61
|
attr_accessor :idlist_threadpool_size
|
80
62
|
|
81
|
-
sig { returns(Integer) }
|
82
63
|
# The number of threads allocated to posting event logs.
|
83
64
|
# default: 3
|
84
65
|
attr_accessor :logger_threadpool_size
|
85
66
|
|
86
|
-
sig { returns(T::Boolean) }
|
87
67
|
# Should diagnostics be logged. These include performance metrics for initialize.
|
88
68
|
# default: false
|
89
69
|
attr_accessor :disable_diagnostics_logging
|
90
70
|
|
91
|
-
sig { returns(T::Boolean) }
|
92
71
|
# Statsig utilizes Sorbet (https://sorbet.org) to ensure type safety of the SDK. This includes logging
|
93
72
|
# to console when errors are detected. You can disable this logging by setting this flag to true.
|
94
73
|
# default: false
|
95
74
|
attr_accessor :disable_sorbet_logging_handlers
|
96
75
|
|
97
|
-
sig { returns(T.any(Integer, NilClass)) }
|
98
76
|
# Number of seconds before a network call is timed out
|
99
77
|
attr_accessor :network_timeout
|
100
78
|
|
101
|
-
sig { returns(Integer) }
|
102
79
|
# Number of times to retry sending a batch of failed log events
|
103
80
|
attr_accessor :post_logs_retry_limit
|
104
81
|
|
105
|
-
sig { returns(T.any(Method, Proc, Integer, NilClass)) }
|
106
82
|
# The number of seconds, or a function that returns the number of seconds based on the number of retries remaining
|
107
83
|
# which overrides the default backoff time between retries
|
108
84
|
attr_accessor :post_logs_retry_backoff
|
109
85
|
|
110
|
-
sig { returns(T.any(Statsig::Interfaces::IUserPersistentStorage, NilClass)) }
|
111
86
|
# A storage adapter for persisted values. Can be used for sticky bucketing users in experiments.
|
112
87
|
# Implements Statsig::Interfaces::IUserPersistentStorage.
|
113
88
|
attr_accessor :user_persistent_storage
|
114
89
|
|
115
|
-
sig do
|
116
|
-
params(
|
117
|
-
environment: T.any(T::Hash[String, String], NilClass),
|
118
|
-
api_url_base: T.nilable(String),
|
119
|
-
api_url_download_config_specs: T.any(String, NilClass),
|
120
|
-
rulesets_sync_interval: T.any(Float, Integer),
|
121
|
-
idlists_sync_interval: T.any(Float, Integer),
|
122
|
-
disable_rulesets_sync: T::Boolean,
|
123
|
-
disable_idlists_sync: T::Boolean,
|
124
|
-
logging_interval_seconds: T.any(Float, Integer),
|
125
|
-
logging_max_buffer_size: Integer,
|
126
|
-
local_mode: T::Boolean,
|
127
|
-
bootstrap_values: T.any(String, NilClass),
|
128
|
-
rules_updated_callback: T.any(Method, Proc, NilClass),
|
129
|
-
data_store: T.any(Statsig::Interfaces::IDataStore, NilClass),
|
130
|
-
idlist_threadpool_size: Integer,
|
131
|
-
logger_threadpool_size: Integer,
|
132
|
-
disable_diagnostics_logging: T::Boolean,
|
133
|
-
disable_sorbet_logging_handlers: T::Boolean,
|
134
|
-
network_timeout: T.any(Integer, NilClass),
|
135
|
-
post_logs_retry_limit: Integer,
|
136
|
-
post_logs_retry_backoff: T.any(Method, Proc, Integer, NilClass),
|
137
|
-
user_persistent_storage: T.any(Statsig::Interfaces::IUserPersistentStorage, NilClass)
|
138
|
-
).void
|
139
|
-
end
|
140
90
|
def initialize(
|
141
91
|
environment = nil,
|
142
92
|
api_url_base = nil,
|
data/lib/statsig_user.rb
CHANGED
@@ -1,65 +1,49 @@
|
|
1
|
-
# typed: true
|
2
|
-
|
3
|
-
require 'sorbet-runtime'
|
4
1
|
require 'json'
|
2
|
+
require 'constants'
|
5
3
|
|
6
4
|
##
|
7
5
|
# The user object to be evaluated against your Statsig configurations (gates/experiments/dynamic configs).
|
8
6
|
class StatsigUser
|
9
|
-
extend T::Sig
|
10
7
|
|
11
|
-
sig { returns(T.any(String, NilClass)) }
|
12
8
|
# An identifier for this user. Evaluated against the User ID criteria. (https://docs.statsig.com/feature-gates/conditions#userid)
|
13
9
|
attr_accessor :user_id
|
14
10
|
|
15
|
-
sig { returns(T.any(String, NilClass)) }
|
16
11
|
# An identifier for this user. Evaluated against the Email criteria. (https://docs.statsig.com/feature-gates/conditions#email)
|
17
12
|
attr_accessor :email
|
18
13
|
|
19
|
-
sig { returns(T.any(String, NilClass)) }
|
20
14
|
# An IP address associated with this user. Evaluated against the IP Address criteria. (https://docs.statsig.com/feature-gates/conditions#ip)
|
21
15
|
attr_accessor :ip
|
22
16
|
|
23
|
-
sig { returns(T.any(String, NilClass)) }
|
24
17
|
# A user agent string associated with this user. Evaluated against Browser Version and Name (https://docs.statsig.com/feature-gates/conditions#browser-version)
|
25
18
|
attr_accessor :user_agent
|
26
19
|
|
27
|
-
sig { returns(T.any(String, NilClass)) }
|
28
20
|
# The country code associated with this user (e.g New Zealand => NZ). Evaluated against the Country criteria. (https://docs.statsig.com/feature-gates/conditions#country)
|
29
21
|
attr_accessor :country
|
30
22
|
|
31
|
-
sig { returns(T.any(String, NilClass)) }
|
32
23
|
# An locale for this user.
|
33
24
|
attr_accessor :locale
|
34
25
|
|
35
|
-
sig { returns(T.any(String, NilClass)) }
|
36
26
|
# The current app version the user is interacting with. Evaluated against the App Version criteria. (https://docs.statsig.com/feature-gates/conditions#app-version)
|
37
27
|
attr_accessor :app_version
|
38
28
|
|
39
|
-
sig { returns(T.any(T::Hash[String, String], NilClass)) }
|
40
29
|
# A Hash you can use to set environment variables that apply to this user. e.g. { "tier" => "development" }
|
41
30
|
attr_accessor :statsig_environment
|
42
31
|
|
43
|
-
sig { returns(T.any(T::Hash[String, String], NilClass)) }
|
44
32
|
# Any Custom IDs to associated with the user. (See https://docs.statsig.com/guides/experiment-on-custom-id-types)
|
45
33
|
attr_accessor :custom_ids
|
46
34
|
|
47
|
-
sig { returns(T.any(T::Hash[String, String], NilClass)) }
|
48
35
|
# Any value you wish to use in evaluation, but do not want logged with events, can be stored in this field.
|
49
36
|
attr_accessor :private_attributes
|
50
37
|
|
51
|
-
sig { returns(T.any(T::Hash[String, T.untyped], NilClass)) }
|
52
38
|
def custom
|
53
39
|
@custom
|
54
40
|
end
|
55
41
|
|
56
|
-
sig { params(value: T.any(T::Hash[String, T.untyped], NilClass)).void }
|
57
42
|
# Any custom fields for this user. Evaluated against the Custom criteria. (https://docs.statsig.com/feature-gates/conditions#custom)
|
58
43
|
def custom=(value)
|
59
44
|
@custom = value.is_a?(Hash) ? value : Hash.new
|
60
45
|
end
|
61
46
|
|
62
|
-
sig { params(user_hash: T.any(T::Hash[T.any(String, Symbol), T.untyped], NilClass)).void }
|
63
47
|
def initialize(user_hash)
|
64
48
|
the_hash = user_hash
|
65
49
|
begin
|
@@ -83,55 +67,56 @@ class StatsigUser
|
|
83
67
|
|
84
68
|
def serialize(for_logging)
|
85
69
|
hash = {
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
70
|
+
:userID => @user_id,
|
71
|
+
:email => @email,
|
72
|
+
:ip => @ip,
|
73
|
+
:userAgent => @user_agent,
|
74
|
+
:country => @country,
|
75
|
+
:locale => @locale,
|
76
|
+
:appVersion => @app_version,
|
77
|
+
:custom => @custom,
|
78
|
+
:statsigEnvironment => @statsig_environment,
|
79
|
+
:privateAttributes => @private_attributes,
|
80
|
+
:customIDs => @custom_ids,
|
97
81
|
}
|
98
82
|
if for_logging
|
99
|
-
hash.delete(
|
83
|
+
hash.delete(:privateAttributes)
|
100
84
|
end
|
101
85
|
hash.compact
|
102
86
|
end
|
103
87
|
|
104
|
-
def to_hash_without_stable_id
|
88
|
+
def to_hash_without_stable_id
|
105
89
|
hash = {}
|
90
|
+
|
106
91
|
if @user_id != nil
|
107
|
-
hash[
|
92
|
+
hash[:userID] = @user_id
|
108
93
|
end
|
109
94
|
if @email != nil
|
110
|
-
hash[
|
95
|
+
hash[:email] = @email
|
111
96
|
end
|
112
97
|
if @ip != nil
|
113
|
-
hash[
|
98
|
+
hash[:ip] = @ip
|
114
99
|
end
|
115
100
|
if @user_agent != nil
|
116
|
-
hash[
|
101
|
+
hash[:userAgent] = @user_agent
|
117
102
|
end
|
118
103
|
if @country != nil
|
119
|
-
hash[
|
104
|
+
hash[:country] = @country
|
120
105
|
end
|
121
106
|
if @locale != nil
|
122
|
-
hash[
|
107
|
+
hash[:locale] = @locale
|
123
108
|
end
|
124
109
|
if @app_version != nil
|
125
|
-
hash[
|
110
|
+
hash[:appVersion] = @app_version
|
126
111
|
end
|
127
112
|
if @custom != nil
|
128
|
-
hash[
|
113
|
+
hash[:custom] = Statsig::HashUtils.sortHash(@custom)
|
129
114
|
end
|
130
115
|
if @statsig_environment != nil
|
131
|
-
hash[
|
116
|
+
hash[:statsigEnvironment] = @statsig_environment.clone.sort_by { |key| key }.to_h
|
132
117
|
end
|
133
118
|
if @private_attributes != nil
|
134
|
-
hash[
|
119
|
+
hash[:privateAttributes] = Statsig::HashUtils.sortHash(@private_attributes)
|
135
120
|
end
|
136
121
|
custom_ids = {}
|
137
122
|
if @custom_ids != nil
|
@@ -140,32 +125,12 @@ class StatsigUser
|
|
140
125
|
custom_ids.delete("stableID")
|
141
126
|
end
|
142
127
|
end
|
143
|
-
hash[
|
128
|
+
hash[:customIDs] = custom_ids.sort_by { |key| key }.to_h
|
144
129
|
return Statsig::HashUtils.djb2ForHash(hash.sort_by { |key| key }.to_h)
|
145
130
|
end
|
146
131
|
|
147
|
-
def value_lookup
|
148
|
-
{
|
149
|
-
'userID' => @user_id,
|
150
|
-
'userid' => @user_id,
|
151
|
-
'user_id' => @user_id,
|
152
|
-
'email' => @email,
|
153
|
-
'ip' => @ip,
|
154
|
-
'userAgent' => @user_agent,
|
155
|
-
'useragent' => @user_agent,
|
156
|
-
'user_agent' => @user_agent,
|
157
|
-
'country' => @country,
|
158
|
-
'locale' => @locale,
|
159
|
-
'appVersion' => @app_version,
|
160
|
-
'appversion' => @app_version,
|
161
|
-
'app_version' => @app_version,
|
162
|
-
'custom' => @custom,
|
163
|
-
'privateAttributes' => @private_attributes,
|
164
|
-
}
|
165
|
-
end
|
166
|
-
|
167
132
|
def get_unit_id(id_type)
|
168
|
-
if id_type.is_a?(String) && id_type
|
133
|
+
if id_type.is_a?(String) && id_type != Statsig::Const::CML_USER_ID
|
169
134
|
return nil unless @custom_ids.is_a? Hash
|
170
135
|
|
171
136
|
return @custom_ids[id_type] || @custom_ids[id_type.downcase]
|
@@ -175,12 +140,6 @@ class StatsigUser
|
|
175
140
|
|
176
141
|
private
|
177
142
|
|
178
|
-
sig {
|
179
|
-
params(user_hash: T.any(T::Hash[T.any(String, Symbol), T.untyped], NilClass),
|
180
|
-
keys: T::Array[Symbol],
|
181
|
-
type: T.untyped)
|
182
|
-
.returns(T.untyped)
|
183
|
-
}
|
184
143
|
# Pulls fields from the user hash via Symbols and Strings
|
185
144
|
def from_hash(user_hash, keys, type)
|
186
145
|
if user_hash.nil?
|
data/lib/ua_parser.rb
CHANGED
data/lib/uri_helper.rb
CHANGED
@@ -1,24 +1,16 @@
|
|
1
|
-
# typed: true
|
2
|
-
|
3
|
-
require 'sorbet-runtime'
|
4
|
-
|
5
1
|
class URIHelper
|
6
2
|
class URIBuilder
|
7
|
-
extend T::Sig
|
8
3
|
|
9
|
-
sig { returns(StatsigOptions) }
|
10
4
|
attr_accessor :options
|
11
5
|
|
12
|
-
sig { params(options: StatsigOptions).void }
|
13
6
|
def initialize(options)
|
14
7
|
@options = options
|
15
8
|
end
|
16
9
|
|
17
|
-
sig { params(endpoint: String).returns(String) }
|
18
10
|
def build_url(endpoint)
|
19
11
|
api = @options.api_url_base
|
20
12
|
if endpoint.include?('download_config_specs')
|
21
|
-
api =
|
13
|
+
api = @options.api_url_download_config_specs
|
22
14
|
end
|
23
15
|
unless api.end_with?('/')
|
24
16
|
api += '/'
|
@@ -1,27 +1,17 @@
|
|
1
|
-
# typed: false
|
2
|
-
|
3
|
-
require 'sorbet-runtime'
|
4
1
|
require 'statsig_options'
|
5
2
|
|
6
3
|
module Statsig
|
7
|
-
UserPersistedValues = T.type_alias { T::Hash[String, Hash] }
|
8
|
-
|
9
4
|
class UserPersistentStorageUtils
|
10
|
-
extend T::Sig
|
11
5
|
|
12
|
-
sig { returns(T::Hash[String, UserPersistedValues]) }
|
13
6
|
attr_accessor :cache
|
14
7
|
|
15
|
-
sig { returns(T.nilable(Interfaces::IUserPersistentStorage)) }
|
16
8
|
attr_accessor :storage
|
17
9
|
|
18
|
-
sig { params(options: StatsigOptions).void }
|
19
10
|
def initialize(options)
|
20
11
|
@storage = options.user_persistent_storage
|
21
12
|
@cache = {}
|
22
13
|
end
|
23
14
|
|
24
|
-
sig { params(user: StatsigUser, id_type: String).returns(T.nilable(UserPersistedValues)) }
|
25
15
|
def get_user_persisted_values(user, id_type)
|
26
16
|
key = self.class.get_storage_key(user, id_type)
|
27
17
|
return @cache[key] unless @cache[key].nil?
|
@@ -29,7 +19,6 @@ module Statsig
|
|
29
19
|
return load_from_storage(key)
|
30
20
|
end
|
31
21
|
|
32
|
-
sig { params(key: String).returns(T.nilable(UserPersistedValues)) }
|
33
22
|
def load_from_storage(key)
|
34
23
|
return if @storage.nil?
|
35
24
|
|
@@ -50,7 +39,6 @@ module Statsig
|
|
50
39
|
return nil
|
51
40
|
end
|
52
41
|
|
53
|
-
sig { params(user: StatsigUser, id_type: String, user_persisted_values: UserPersistedValues).void }
|
54
42
|
def save_to_storage(user, id_type, user_persisted_values)
|
55
43
|
return if @storage.nil?
|
56
44
|
|
@@ -65,7 +53,6 @@ module Statsig
|
|
65
53
|
end
|
66
54
|
end
|
67
55
|
|
68
|
-
sig { params(user: StatsigUser, id_type: String, config_name: String).void }
|
69
56
|
def remove_experiment_from_storage(user, id_type, config_name)
|
70
57
|
persisted_values = get_user_persisted_values(user, id_type)
|
71
58
|
unless persisted_values.nil?
|
@@ -74,7 +61,6 @@ module Statsig
|
|
74
61
|
end
|
75
62
|
end
|
76
63
|
|
77
|
-
sig { params(user_persisted_values: T.nilable(UserPersistedValues), config_name: String, evaluation: ConfigResult).void }
|
78
64
|
def add_evaluation_to_user_persisted_values(user_persisted_values, config_name, evaluation)
|
79
65
|
if user_persisted_values.nil?
|
80
66
|
user_persisted_values = {}
|
@@ -84,21 +70,18 @@ module Statsig
|
|
84
70
|
|
85
71
|
private
|
86
72
|
|
87
|
-
sig { params(values_string: String).returns(T.nilable(UserPersistedValues)) }
|
88
73
|
def self.parse(values_string)
|
89
74
|
return JSON.parse(values_string)
|
90
75
|
rescue JSON::ParserError
|
91
76
|
return nil
|
92
77
|
end
|
93
78
|
|
94
|
-
sig { params(values_object: UserPersistedValues).returns(T.nilable(String)) }
|
95
79
|
def self.stringify(values_object)
|
96
80
|
return JSON.generate(values_object)
|
97
81
|
rescue StandardError
|
98
82
|
return nil
|
99
83
|
end
|
100
84
|
|
101
|
-
sig { params(user: StatsigUser, id_type: String).returns(String) }
|
102
85
|
def self.get_storage_key(user, id_type)
|
103
86
|
"#{user.get_unit_id(id_type)}:#{id_type}"
|
104
87
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statsig
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.32.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Statsig, Inc
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-01-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -322,8 +322,10 @@ executables: []
|
|
322
322
|
extensions: []
|
323
323
|
extra_rdoc_files: []
|
324
324
|
files:
|
325
|
+
- lib/api_config.rb
|
325
326
|
- lib/client_initialize_helpers.rb
|
326
327
|
- lib/config_result.rb
|
328
|
+
- lib/constants.rb
|
327
329
|
- lib/diagnostics.rb
|
328
330
|
- lib/dynamic_config.rb
|
329
331
|
- lib/error_boundary.rb
|
@@ -352,7 +354,7 @@ homepage: https://rubygems.org/gems/statsig
|
|
352
354
|
licenses:
|
353
355
|
- ISC
|
354
356
|
metadata: {}
|
355
|
-
post_install_message:
|
357
|
+
post_install_message:
|
356
358
|
rdoc_options: []
|
357
359
|
require_paths:
|
358
360
|
- lib
|
@@ -367,8 +369,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
367
369
|
- !ruby/object:Gem::Version
|
368
370
|
version: '0'
|
369
371
|
requirements: []
|
370
|
-
rubygems_version: 3.
|
371
|
-
signing_key:
|
372
|
+
rubygems_version: 3.2.33
|
373
|
+
signing_key:
|
372
374
|
specification_version: 4
|
373
375
|
summary: Statsig server SDK for Ruby
|
374
376
|
test_files: []
|