eppo-server-sdk 0.3.0 → 3.1.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/.gitignore +22 -0
- data/.rspec +3 -0
- data/.rubocop.yml +8 -0
- data/Cargo.lock +2015 -0
- data/Cargo.toml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +22 -0
- data/Rakefile +53 -0
- data/Steepfile +27 -0
- data/ext/eppo_client/Cargo.toml +19 -0
- data/ext/eppo_client/build.rs +5 -0
- data/ext/eppo_client/extconf.rb +6 -0
- data/ext/eppo_client/src/client.rs +178 -0
- data/ext/eppo_client/src/lib.rs +34 -0
- data/lib/eppo_client/assignment_logger.rb +7 -3
- data/lib/eppo_client/client.rb +159 -205
- data/lib/eppo_client/config.rb +4 -4
- data/lib/eppo_client/custom_errors.rb +0 -17
- data/lib/eppo_client/validation.rb +2 -2
- data/lib/eppo_client/version.rb +2 -1
- data/lib/eppo_client.rb +7 -45
- data/sig/eppo_server_sdk.rbs +96 -0
- metadata +26 -172
- data/lib/eppo_client/configuration_requestor.rb +0 -108
- data/lib/eppo_client/configuration_store.rb +0 -35
- data/lib/eppo_client/constants.rb +0 -20
- data/lib/eppo_client/http_client.rb +0 -75
- data/lib/eppo_client/lru_cache.rb +0 -28
- data/lib/eppo_client/poller.rb +0 -48
- data/lib/eppo_client/rules.rb +0 -119
- data/lib/eppo_client/shard.rb +0 -30
- data/lib/eppo_client/variation_type.rb +0 -39
data/lib/eppo_client/client.rb
CHANGED
@@ -1,238 +1,192 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "singleton"
|
4
|
+
require "logger"
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
require_relative 'rules'
|
9
|
-
require_relative 'shard'
|
10
|
-
require_relative 'validation'
|
11
|
-
require_relative 'variation_type'
|
6
|
+
require_relative "config"
|
7
|
+
require_relative "eppo_client"
|
12
8
|
|
13
9
|
module EppoClient
|
14
10
|
# The main client singleton
|
15
|
-
# rubocop:disable Metrics/ClassLength
|
16
11
|
class Client
|
17
|
-
extend Gem::Deprecate
|
18
12
|
include Singleton
|
19
|
-
attr_accessor :
|
13
|
+
attr_accessor :assignment_logger
|
20
14
|
|
21
|
-
def
|
22
|
-
|
15
|
+
def init(config)
|
16
|
+
config.validate
|
17
|
+
|
18
|
+
if !@core.nil? then
|
19
|
+
STDERR.puts "Eppo Warning: multiple initialization of the client"
|
20
|
+
@core.shutdown
|
21
|
+
end
|
22
|
+
|
23
|
+
@assignment_logger = config.assignment_logger
|
24
|
+
@core = EppoClient::Core::Client.new(config)
|
23
25
|
end
|
24
26
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
flag_key,
|
43
|
-
|
44
|
-
|
45
|
-
)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
subject_attributes
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
flag_key,
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
)
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
def get_assignment(
|
101
|
-
subject_key,
|
102
|
-
flag_key,
|
103
|
-
subject_attributes = {},
|
104
|
-
log_level = EppoClient::DEFAULT_LOGGER_LEVEL
|
105
|
-
)
|
27
|
+
def shutdown
|
28
|
+
@core.shutdown
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_string_assignment(flag_key, subject_key, subject_attributes, default_value)
|
32
|
+
get_assignment_inner(flag_key, subject_key, subject_attributes, "STRING", default_value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_numeric_assignment(flag_key, subject_key, subject_attributes, default_value)
|
36
|
+
get_assignment_inner(flag_key, subject_key, subject_attributes, "NUMERIC", default_value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_integer_assignment(flag_key, subject_key, subject_attributes, default_value)
|
40
|
+
get_assignment_inner(flag_key, subject_key, subject_attributes, "INTEGER", default_value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_boolean_assignment(flag_key, subject_key, subject_attributes, default_value)
|
44
|
+
get_assignment_inner(flag_key, subject_key, subject_attributes, "BOOLEAN", default_value)
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_json_assignment(flag_key, subject_key, subject_attributes, default_value)
|
48
|
+
get_assignment_inner(flag_key, subject_key, subject_attributes, "JSON", default_value)
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_string_assignment_details(flag_key, subject_key, subject_attributes, default_value)
|
52
|
+
get_assignment_details_inner(flag_key, subject_key, subject_attributes, "STRING", default_value)
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_numeric_assignment_details(flag_key, subject_key, subject_attributes, default_value)
|
56
|
+
get_assignment_details_inner(flag_key, subject_key, subject_attributes, "NUMERIC", default_value)
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_integer_assignment_details(flag_key, subject_key, subject_attributes, default_value)
|
60
|
+
get_assignment_details_inner(flag_key, subject_key, subject_attributes, "INTEGER", default_value)
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_boolean_assignment_details(flag_key, subject_key, subject_attributes, default_value)
|
64
|
+
get_assignment_details_inner(flag_key, subject_key, subject_attributes, "BOOLEAN", default_value)
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_json_assignment_details(flag_key, subject_key, subject_attributes, default_value)
|
68
|
+
get_assignment_details_inner(flag_key, subject_key, subject_attributes, "JSON", default_value)
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_bandit_action(flag_key, subject_key, subject_attributes, actions, default_variation)
|
72
|
+
attributes = coerce_context_attributes(subject_attributes)
|
73
|
+
actions = actions.to_h { |action, attributes| [action, coerce_context_attributes(attributes)] }
|
74
|
+
result = @core.get_bandit_action(flag_key, subject_key, attributes, actions, default_variation)
|
75
|
+
|
76
|
+
log_assignment(result[:assignment_event])
|
77
|
+
log_bandit_action(result[:bandit_event])
|
78
|
+
|
79
|
+
return {:variation => result[:variation], :action => result[:action]}
|
80
|
+
end
|
81
|
+
|
82
|
+
def get_bandit_action_details(flag_key, subject_key, subject_attributes, actions, default_variation)
|
83
|
+
attributes = coerce_context_attributes(subject_attributes)
|
84
|
+
actions = actions.to_h { |action, attributes| [action, coerce_context_attributes(attributes)] }
|
85
|
+
result, details = @core.get_bandit_action_details(flag_key, subject_key, attributes, actions, default_variation)
|
86
|
+
|
87
|
+
log_assignment(result[:assignment_event])
|
88
|
+
log_bandit_action(result[:bandit_event])
|
89
|
+
|
90
|
+
return {
|
91
|
+
:variation => result[:variation],
|
92
|
+
:action => result[:action],
|
93
|
+
:evaluationDetails => details
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
# rubocop:disable Metrics/MethodLength
|
100
|
+
def get_assignment_inner(flag_key, subject_key, subject_attributes, expected_type, default_value)
|
106
101
|
logger = Logger.new($stdout)
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
assigned_variation&.value
|
112
|
-
end
|
113
|
-
deprecate :get_assignment, 'the get_<typed>_assignment methods', 2024, 1
|
114
|
-
|
115
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
116
|
-
def get_assignment_variation(
|
117
|
-
subject_key,
|
118
|
-
flag_key,
|
119
|
-
subject_attributes,
|
120
|
-
expected_variation_type,
|
121
|
-
logger
|
122
|
-
)
|
123
|
-
EppoClient.validate_not_blank('subject_key', subject_key)
|
124
|
-
EppoClient.validate_not_blank('flag_key', flag_key)
|
125
|
-
experiment_config = @config_requestor.get_configuration(flag_key)
|
126
|
-
override = get_subject_variation_override(experiment_config, subject_key)
|
127
|
-
unless override.nil?
|
128
|
-
unless expected_variation_type.nil?
|
129
|
-
variation_is_expected_type =
|
130
|
-
EppoClient::VariationType.expected_type?(
|
131
|
-
override, expected_variation_type
|
132
|
-
)
|
133
|
-
return nil unless variation_is_expected_type
|
102
|
+
begin
|
103
|
+
assignment = @core.get_assignment(flag_key, subject_key, subject_attributes, expected_type)
|
104
|
+
if not assignment then
|
105
|
+
return default_value
|
134
106
|
end
|
135
|
-
return override
|
136
|
-
end
|
137
107
|
|
138
|
-
|
139
|
-
logger.debug(
|
140
|
-
'[Eppo SDK] No assigned variation. No active experiment or flag for '\
|
141
|
-
"key: #{flag_key}"
|
142
|
-
)
|
143
|
-
return nil
|
144
|
-
end
|
108
|
+
log_assignment(assignment[:event])
|
145
109
|
|
146
|
-
|
147
|
-
|
148
|
-
logger.debug(
|
149
|
-
'[Eppo SDK] No assigned variation. Subject attributes do not match '\
|
150
|
-
"targeting rules: #{subject_attributes}"
|
151
|
-
)
|
152
|
-
return nil
|
153
|
-
end
|
110
|
+
return assignment[:value][:value]
|
111
|
+
rescue StandardError => error
|
112
|
+
logger.debug("[Eppo SDK] Failed to get assignment: #{error}")
|
154
113
|
|
155
|
-
|
156
|
-
|
157
|
-
subject_key,
|
158
|
-
flag_key,
|
159
|
-
experiment_config.subject_shards,
|
160
|
-
allocation.percent_exposure
|
161
|
-
)
|
162
|
-
logger.debug(
|
163
|
-
'[Eppo SDK] No assigned variation. Subject is not part of experiment'\
|
164
|
-
' sample population'
|
165
|
-
)
|
166
|
-
return nil
|
114
|
+
# TODO: non-graceful mode?
|
115
|
+
default_value
|
167
116
|
end
|
117
|
+
end
|
118
|
+
# rubocop:enable Metrics/MethodLength
|
168
119
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
)
|
173
|
-
|
174
|
-
|
120
|
+
# rubocop:disable Metrics/MethodLength
|
121
|
+
def get_assignment_details_inner(flag_key, subject_key, subject_attributes, expected_type, default_value)
|
122
|
+
result, event = @core.get_assignment_details(flag_key, subject_key, subject_attributes, expected_type)
|
123
|
+
log_assignment(event)
|
124
|
+
|
125
|
+
if not result[:variation] then
|
126
|
+
result[:variation] = default_value
|
127
|
+
else
|
128
|
+
# unwrap from AssignmentValue to untyped value
|
129
|
+
result[:variation] = result[:variation][:value]
|
175
130
|
end
|
176
131
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
unless expected_variation_type.nil?
|
181
|
-
variation_is_expected_type = EppoClient::VariationType.expected_type?(
|
182
|
-
assigned_variation, expected_variation_type
|
183
|
-
)
|
184
|
-
return nil unless variation_is_expected_type
|
185
|
-
end
|
186
|
-
end
|
132
|
+
return result
|
133
|
+
end
|
134
|
+
# rubocop:enable Metrics/MethodLength
|
187
135
|
|
188
|
-
|
189
|
-
|
190
|
-
"experiment": "#{flag_key}-#{matched_rule.allocation_key}",
|
191
|
-
"featureFlag": flag_key,
|
192
|
-
"variation": assigned_variation_value_to_log,
|
193
|
-
"subject": subject_key,
|
194
|
-
"timestamp": Time.now.utc.iso8601,
|
195
|
-
"subjectAttributes": subject_attributes
|
196
|
-
}
|
136
|
+
def log_assignment(event)
|
137
|
+
if not event then return end
|
197
138
|
|
139
|
+
# Because rust's AssignmentEvent has a #[flatten] extra_logging
|
140
|
+
# field, serde_magnus serializes it as a normal HashMap with
|
141
|
+
# string keys.
|
142
|
+
#
|
143
|
+
# Convert keys to symbols here, so that logger sees symbol-keyed
|
144
|
+
# events for both flag assignment and bandit actions.
|
145
|
+
event = event.to_h { |key, value| [key.to_sym, value]}
|
146
|
+
|
147
|
+
enrich_event_metadata(event)
|
198
148
|
begin
|
199
|
-
@assignment_logger.log_assignment(
|
200
|
-
rescue EppoClient::AssignmentLoggerError
|
201
|
-
|
202
|
-
rescue StandardError =>
|
203
|
-
logger.
|
149
|
+
@assignment_logger.log_assignment(event)
|
150
|
+
rescue EppoClient::AssignmentLoggerError
|
151
|
+
# Error means log_assignment was not set up. This is okay to ignore.
|
152
|
+
rescue StandardError => error
|
153
|
+
logger = Logger.new($stdout)
|
154
|
+
logger.error("[Eppo SDK] Error logging assignment event: #{error}")
|
204
155
|
end
|
205
|
-
|
206
|
-
assigned_variation
|
207
156
|
end
|
208
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
209
157
|
|
210
|
-
def
|
211
|
-
|
212
|
-
end
|
158
|
+
def log_bandit_action(event)
|
159
|
+
if not event then return end
|
213
160
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
experiment_config.overrides[subject_hash],
|
223
|
-
experiment_config.typed_overrides[subject_hash],
|
224
|
-
EppoClient::ShardRange.new(0, 1000)
|
225
|
-
)
|
161
|
+
enrich_event_metadata(event)
|
162
|
+
begin
|
163
|
+
@assignment_logger.log_bandit_action(event)
|
164
|
+
rescue EppoClient::AssignmentLoggerError
|
165
|
+
# Error means log_assignment was not set up. This is okay to ignore.
|
166
|
+
rescue StandardError => error
|
167
|
+
logger = Logger.new($stdout)
|
168
|
+
logger.error("[Eppo SDK] Error logging bandit action event: #{error}")
|
226
169
|
end
|
227
170
|
end
|
228
|
-
# rubocop:enable Metrics/MethodLength
|
229
171
|
|
230
|
-
def
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
172
|
+
def enrich_event_metadata(event)
|
173
|
+
event[:metaData]["sdkName"] = "ruby"
|
174
|
+
event[:metaData]["sdkVersion"] = EppoClient::VERSION
|
175
|
+
end
|
176
|
+
|
177
|
+
def coerce_context_attributes(attributes)
|
178
|
+
numeric_attributes = attributes[:numeric_attributes] || attributes["numericAttributes"]
|
179
|
+
categorical_attributes = attributes[:categorical_attributes] || attributes["categoricalAttributes"]
|
180
|
+
if numeric_attributes || categorical_attributes then
|
181
|
+
{
|
182
|
+
numericAttributes: numeric_attributes.to_h do |key, value|
|
183
|
+
value.is_a?(Numeric) ? [key, value] : [nil, nil]
|
184
|
+
end.compact,
|
185
|
+
categoricalAttributes: categorical_attributes.to_h do |key, value|
|
186
|
+
value.nil? ? [nil, nil] : [key, value.to_s]
|
187
|
+
end.compact,
|
188
|
+
}
|
189
|
+
end
|
235
190
|
end
|
236
191
|
end
|
237
|
-
# rubocop:enable Metrics/ClassLength
|
238
192
|
end
|
data/lib/eppo_client/config.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
3
|
+
require_relative "validation"
|
4
|
+
require_relative "assignment_logger"
|
5
5
|
|
6
6
|
module EppoClient
|
7
7
|
# The class for configuring the Eppo client singleton
|
8
8
|
class Config
|
9
9
|
attr_reader :api_key, :assignment_logger, :base_url
|
10
10
|
|
11
|
-
def initialize(api_key, assignment_logger: AssignmentLogger.new, base_url:
|
11
|
+
def initialize(api_key, assignment_logger: AssignmentLogger.new, base_url: EppoClient::Core::DEFAULT_BASE_URL)
|
12
12
|
@api_key = api_key
|
13
13
|
@assignment_logger = assignment_logger
|
14
14
|
@base_url = base_url
|
15
15
|
end
|
16
16
|
|
17
17
|
def validate
|
18
|
-
EppoClient.validate_not_blank(
|
18
|
+
EppoClient.validate_not_blank("api_key", @api_key)
|
19
19
|
end
|
20
20
|
|
21
21
|
# Hide instance variables (specifically api_key) from logs
|
@@ -8,23 +8,6 @@ module EppoClient
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
# A custom error class for unauthorized requests
|
12
|
-
class UnauthorizedError < StandardError
|
13
|
-
def initialize(message)
|
14
|
-
super("Unauthorized: #{message}")
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# A custom error class for HTTP requests
|
19
|
-
class HttpRequestError < StandardError
|
20
|
-
attr_reader :status_code
|
21
|
-
|
22
|
-
def initialize(message, status_code)
|
23
|
-
@status_code = status_code
|
24
|
-
super("HttpRequestError: #{message}")
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
11
|
# A custom error class for invalid values
|
29
12
|
class InvalidValueError < StandardError
|
30
13
|
def initialize(message)
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "custom_errors"
|
4
4
|
|
5
5
|
# The helper module to validate keys
|
6
6
|
module EppoClient
|
7
7
|
module_function
|
8
8
|
|
9
9
|
def validate_not_blank(field_name, field_value)
|
10
|
-
(field_value.nil? || field_value ==
|
10
|
+
(field_value.nil? || field_value == "") && raise(
|
11
11
|
EppoClient::InvalidValueError, "#{field_name} cannot be blank"
|
12
12
|
)
|
13
13
|
end
|
data/lib/eppo_client/version.rb
CHANGED
data/lib/eppo_client.rb
CHANGED
@@ -1,53 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative 'eppo_client/poller'
|
6
|
-
require_relative 'eppo_client/config'
|
7
|
-
require_relative 'eppo_client/client'
|
8
|
-
require_relative 'eppo_client/constants'
|
9
|
-
require_relative 'eppo_client/configuration_requestor'
|
10
|
-
require_relative 'eppo_client/configuration_store'
|
11
|
-
require_relative 'eppo_client/version'
|
3
|
+
require_relative "eppo_client/client"
|
4
|
+
require_relative "eppo_client/version"
|
12
5
|
|
13
|
-
#
|
6
|
+
# EppoClient is the main module for initializing the Eppo client.
|
7
|
+
# It provides a method to initialize the client with a given configuration.
|
14
8
|
module EppoClient
|
15
|
-
# rubocop:disable Metrics/MethodLength
|
16
|
-
def initialize_client(config_requestor, assignment_logger)
|
17
|
-
client = EppoClient::Client.instance
|
18
|
-
!client.poller.nil? && client.shutdown
|
19
|
-
client.config_requestor = config_requestor
|
20
|
-
client.assignment_logger = assignment_logger
|
21
|
-
client.poller = EppoClient::Poller.new(
|
22
|
-
EppoClient::POLL_INTERVAL_MILLIS,
|
23
|
-
EppoClient::POLL_JITTER_MILLIS,
|
24
|
-
proc { client.config_requestor.fetch_and_store_configurations }
|
25
|
-
)
|
26
|
-
client.poller.start
|
27
|
-
client
|
28
|
-
end
|
29
|
-
# rubocop:enable Metrics/MethodLength
|
30
|
-
|
31
|
-
# rubocop:disable Metrics/MethodLength
|
32
9
|
def init(config)
|
33
|
-
|
34
|
-
|
35
|
-
EppoClient::VERSION)
|
36
|
-
http_client = EppoClient::HttpClient.new(config.base_url,
|
37
|
-
sdk_params.formatted)
|
38
|
-
config_store = EppoClient::ConfigurationStore.new(
|
39
|
-
EppoClient::MAX_CACHE_ENTRIES
|
40
|
-
)
|
41
|
-
config_store.lock.with_write_lock do
|
42
|
-
EppoClient.initialize_client(
|
43
|
-
EppoClient::ExperimentConfigurationRequestor.new(
|
44
|
-
http_client, config_store
|
45
|
-
),
|
46
|
-
config.assignment_logger
|
47
|
-
)
|
48
|
-
end
|
10
|
+
client = EppoClient::Client.instance
|
11
|
+
client.init(config)
|
49
12
|
end
|
50
|
-
# rubocop:enable Metrics/MethodLength
|
51
13
|
|
52
|
-
module_function :init
|
14
|
+
module_function :init
|
53
15
|
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# EppoClient is the main module for initializing the Eppo client.
|
2
|
+
# It provides a method to initialize the client with a given configuration.
|
3
|
+
module EppoClient
|
4
|
+
def self.init: (Config config) -> void
|
5
|
+
|
6
|
+
# The base assignment logger class to override
|
7
|
+
class AssignmentLogger
|
8
|
+
def log_assignment: (untyped assignment_event) -> void
|
9
|
+
|
10
|
+
def log_bandit_action: (untyped assignment_event) -> void
|
11
|
+
end
|
12
|
+
|
13
|
+
# The main client singleton
|
14
|
+
class Client
|
15
|
+
@assignment_logger: AssignmentLogger
|
16
|
+
@core: Core::Client
|
17
|
+
|
18
|
+
include Singleton
|
19
|
+
|
20
|
+
attr_accessor assignment_logger: AssignmentLogger
|
21
|
+
|
22
|
+
def self.instance: () -> Client
|
23
|
+
|
24
|
+
def init: (Config config) -> void
|
25
|
+
|
26
|
+
def shutdown: () -> void
|
27
|
+
|
28
|
+
def get_string_assignment: (String flag_key, String subject_key, Hash[String, untyped] subject_attributes, String default_value) -> String
|
29
|
+
|
30
|
+
def get_numeric_assignment: (String flag_key, String subject_key, Hash[String, untyped] subject_attributes, Numeric default_value) -> Numeric
|
31
|
+
|
32
|
+
def get_integer_assignment: (String flag_key, String subject_key, Hash[String, untyped] subject_attributes, Integer default_value) -> Integer
|
33
|
+
|
34
|
+
def get_boolean_assignment: (String flag_key, String subject_key, Hash[String, untyped] subject_attributes, bool default_value) -> bool
|
35
|
+
|
36
|
+
def get_json_assignment: (String flag_key, String subject_key, Hash[String, untyped] subject_attributes, Object default_value) -> Object
|
37
|
+
|
38
|
+
def get_bandit_action: (String flag_key, String subject_key, Hash[String, untyped] subject_attributes, Hash[String, untyped] actions, String default_variation) -> { variation: untyped, action: untyped }
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# rubocop:disable Metrics/MethodLength
|
43
|
+
def get_assignment_inner: (untyped flag_key, String subject_key, untyped subject_attributes, untyped expected_type, untyped default_value) -> untyped
|
44
|
+
|
45
|
+
def log_assignment: (untyped event) -> void
|
46
|
+
|
47
|
+
def log_bandit_action: (untyped event) -> void
|
48
|
+
|
49
|
+
def enrich_event_metadata: (untyped event) -> void
|
50
|
+
|
51
|
+
def coerce_context_attributes: (untyped attributes) -> untyped
|
52
|
+
end
|
53
|
+
|
54
|
+
# The class for configuring the Eppo client singleton
|
55
|
+
class Config
|
56
|
+
@api_key: String
|
57
|
+
@assignment_logger: AssignmentLogger
|
58
|
+
@base_url: String
|
59
|
+
|
60
|
+
attr_reader api_key: String
|
61
|
+
attr_reader assignment_logger: AssignmentLogger
|
62
|
+
attr_reader base_url: String
|
63
|
+
|
64
|
+
def initialize: (String api_key, ?assignment_logger: AssignmentLogger, ?base_url: String) -> void
|
65
|
+
|
66
|
+
def validate: () -> void
|
67
|
+
|
68
|
+
# Hide instance variables (specifically api_key) from logs
|
69
|
+
def inspect: () -> ::String
|
70
|
+
end
|
71
|
+
|
72
|
+
# A custom error class for AssignmentLogger
|
73
|
+
class AssignmentLoggerError < StandardError
|
74
|
+
def initialize: (String message) -> void
|
75
|
+
end
|
76
|
+
|
77
|
+
# A custom error class for invalid values
|
78
|
+
class InvalidValueError < StandardError
|
79
|
+
def initialize: (String message) -> void
|
80
|
+
end
|
81
|
+
|
82
|
+
def self?.validate_not_blank: (String field_name, String field_value) -> void
|
83
|
+
|
84
|
+
VERSION: String
|
85
|
+
end
|
86
|
+
|
87
|
+
# Exposed from Rust
|
88
|
+
module EppoClient::Core
|
89
|
+
DEFAULT_BASE_URL: String
|
90
|
+
class Client
|
91
|
+
def self.new: (untyped config) -> Client
|
92
|
+
def shutdown: () -> void
|
93
|
+
def get_assignment: (String flag_key, String subject_key, untyped subject_attributes, String expected_type) -> untyped
|
94
|
+
def get_bandit_action: (String flag_key, String subject_key, untyped attributes, untyped actions, String default_variation) -> untyped
|
95
|
+
end
|
96
|
+
end
|