optimizely-sdk 3.6.0 → 3.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/optimizely/audience.rb +18 -39
- data/lib/optimizely/bucketer.rb +35 -27
- data/lib/optimizely/condition_tree_evaluator.rb +2 -0
- data/lib/optimizely/config/datafile_project_config.rb +97 -14
- data/lib/optimizely/decide/optimizely_decide_option.rb +28 -0
- data/lib/optimizely/decide/optimizely_decision.rb +60 -0
- data/lib/optimizely/decide/optimizely_decision_message.rb +26 -0
- data/lib/optimizely/decision_service.rb +164 -141
- data/lib/optimizely/event/entity/decision.rb +6 -4
- data/lib/optimizely/event/entity/impression_event.rb +4 -2
- data/lib/optimizely/event/event_factory.rb +4 -3
- data/lib/optimizely/event/user_event_factory.rb +4 -3
- data/lib/optimizely/helpers/constants.rb +1 -0
- data/lib/optimizely/optimizely_config.rb +180 -25
- data/lib/optimizely/optimizely_user_context.rb +107 -0
- data/lib/optimizely/project_config.rb +14 -2
- data/lib/optimizely/version.rb +1 -1
- data/lib/optimizely.rb +245 -18
- metadata +7 -3
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2016-
|
3
|
+
# Copyright 2016-2021, Optimizely and contributors
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
6
|
# you may not use this file except in compliance with the License.
|
@@ -46,12 +46,20 @@ module Optimizely
|
|
46
46
|
|
47
47
|
def revision; end
|
48
48
|
|
49
|
+
def sdk_key; end
|
50
|
+
|
51
|
+
def environment_key; end
|
52
|
+
|
53
|
+
def send_flag_decisions; end
|
54
|
+
|
49
55
|
def rollouts; end
|
50
56
|
|
51
57
|
def experiment_running?(experiment); end
|
52
58
|
|
53
59
|
def get_experiment_from_key(experiment_key); end
|
54
60
|
|
61
|
+
def get_experiment_from_id(experiment_id); end
|
62
|
+
|
55
63
|
def get_experiment_key(experiment_id); end
|
56
64
|
|
57
65
|
def get_event_from_key(event_key); end
|
@@ -60,9 +68,13 @@ module Optimizely
|
|
60
68
|
|
61
69
|
def get_variation_from_id(experiment_key, variation_id); end
|
62
70
|
|
71
|
+
def get_variation_from_id_by_experiment_id(experiment_id, variation_id); end
|
72
|
+
|
73
|
+
def get_variation_id_from_key_by_experiment_id(experiment_id, variation_key); end
|
74
|
+
|
63
75
|
def get_variation_id_from_key(experiment_key, variation_key); end
|
64
76
|
|
65
|
-
def get_whitelisted_variations(
|
77
|
+
def get_whitelisted_variations(experiment_id); end
|
66
78
|
|
67
79
|
def get_attribute_id(attribute_key); end
|
68
80
|
|
data/lib/optimizely/version.rb
CHANGED
data/lib/optimizely.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#
|
4
|
-
# Copyright 2016-
|
4
|
+
# Copyright 2016-2021, Optimizely and contributors
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
@@ -19,6 +19,9 @@ require_relative 'optimizely/audience'
|
|
19
19
|
require_relative 'optimizely/config/datafile_project_config'
|
20
20
|
require_relative 'optimizely/config_manager/http_project_config_manager'
|
21
21
|
require_relative 'optimizely/config_manager/static_project_config_manager'
|
22
|
+
require_relative 'optimizely/decide/optimizely_decide_option'
|
23
|
+
require_relative 'optimizely/decide/optimizely_decision'
|
24
|
+
require_relative 'optimizely/decide/optimizely_decision_message'
|
22
25
|
require_relative 'optimizely/decision_service'
|
23
26
|
require_relative 'optimizely/error_handler'
|
24
27
|
require_relative 'optimizely/event_builder'
|
@@ -34,9 +37,12 @@ require_relative 'optimizely/helpers/variable_type'
|
|
34
37
|
require_relative 'optimizely/logger'
|
35
38
|
require_relative 'optimizely/notification_center'
|
36
39
|
require_relative 'optimizely/optimizely_config'
|
40
|
+
require_relative 'optimizely/optimizely_user_context'
|
37
41
|
|
38
42
|
module Optimizely
|
39
43
|
class Project
|
44
|
+
include Optimizely::Decide
|
45
|
+
|
40
46
|
attr_reader :notification_center
|
41
47
|
# @api no-doc
|
42
48
|
attr_reader :config_manager, :decision_service, :error_handler, :event_dispatcher,
|
@@ -67,12 +73,21 @@ module Optimizely
|
|
67
73
|
sdk_key = nil,
|
68
74
|
config_manager = nil,
|
69
75
|
notification_center = nil,
|
70
|
-
event_processor = nil
|
76
|
+
event_processor = nil,
|
77
|
+
default_decide_options = []
|
71
78
|
)
|
72
79
|
@logger = logger || NoOpLogger.new
|
73
80
|
@error_handler = error_handler || NoOpErrorHandler.new
|
74
81
|
@event_dispatcher = event_dispatcher || EventDispatcher.new(logger: @logger, error_handler: @error_handler)
|
75
82
|
@user_profile_service = user_profile_service
|
83
|
+
@default_decide_options = []
|
84
|
+
|
85
|
+
if default_decide_options.is_a? Array
|
86
|
+
@default_decide_options = default_decide_options.clone
|
87
|
+
else
|
88
|
+
@logger.log(Logger::DEBUG, 'Provided default decide options is not an array.')
|
89
|
+
@default_decide_options = []
|
90
|
+
end
|
76
91
|
|
77
92
|
begin
|
78
93
|
validate_instantiation_options
|
@@ -107,6 +122,175 @@ module Optimizely
|
|
107
122
|
end
|
108
123
|
end
|
109
124
|
|
125
|
+
# Create a context of the user for which decision APIs will be called.
|
126
|
+
#
|
127
|
+
# A user context will be created successfully even when the SDK is not fully configured yet.
|
128
|
+
#
|
129
|
+
# @param user_id - The user ID to be used for bucketing.
|
130
|
+
# @param attributes - A Hash representing user attribute names and values.
|
131
|
+
#
|
132
|
+
# @return [OptimizelyUserContext] An OptimizelyUserContext associated with this OptimizelyClient.
|
133
|
+
# @return [nil] If user attributes are not in valid format.
|
134
|
+
|
135
|
+
def create_user_context(user_id, attributes = nil)
|
136
|
+
# We do not check for is_valid here as a user context can be created successfully
|
137
|
+
# even when the SDK is not fully configured.
|
138
|
+
|
139
|
+
# validate user_id
|
140
|
+
return nil unless Optimizely::Helpers::Validator.inputs_valid?(
|
141
|
+
{
|
142
|
+
user_id: user_id
|
143
|
+
}, @logger, Logger::ERROR
|
144
|
+
)
|
145
|
+
|
146
|
+
# validate attributes
|
147
|
+
return nil unless user_inputs_valid?(attributes)
|
148
|
+
|
149
|
+
user_context = OptimizelyUserContext.new(self, user_id, attributes)
|
150
|
+
user_context
|
151
|
+
end
|
152
|
+
|
153
|
+
def decide(user_context, key, decide_options = [])
|
154
|
+
# raising on user context as it is internal and not provided directly by the user.
|
155
|
+
raise if user_context.class != OptimizelyUserContext
|
156
|
+
|
157
|
+
reasons = []
|
158
|
+
|
159
|
+
# check if SDK is ready
|
160
|
+
unless is_valid
|
161
|
+
@logger.log(Logger::ERROR, InvalidProjectConfigError.new('decide').message)
|
162
|
+
reasons.push(OptimizelyDecisionMessage::SDK_NOT_READY)
|
163
|
+
return OptimizelyDecision.new(flag_key: key, user_context: user_context, reasons: reasons)
|
164
|
+
end
|
165
|
+
|
166
|
+
# validate that key is a string
|
167
|
+
unless key.is_a?(String)
|
168
|
+
@logger.log(Logger::ERROR, 'Provided key is invalid')
|
169
|
+
reasons.push(format(OptimizelyDecisionMessage::FLAG_KEY_INVALID, key))
|
170
|
+
return OptimizelyDecision.new(flag_key: key, user_context: user_context, reasons: reasons)
|
171
|
+
end
|
172
|
+
|
173
|
+
# validate that key maps to a feature flag
|
174
|
+
config = project_config
|
175
|
+
feature_flag = config.get_feature_flag_from_key(key)
|
176
|
+
unless feature_flag
|
177
|
+
@logger.log(Logger::ERROR, "No feature flag was found for key '#{key}'.")
|
178
|
+
reasons.push(format(OptimizelyDecisionMessage::FLAG_KEY_INVALID, key))
|
179
|
+
return OptimizelyDecision.new(flag_key: key, user_context: user_context, reasons: reasons)
|
180
|
+
end
|
181
|
+
|
182
|
+
# merge decide_options and default_decide_options
|
183
|
+
if decide_options.is_a? Array
|
184
|
+
decide_options += @default_decide_options
|
185
|
+
else
|
186
|
+
@logger.log(Logger::DEBUG, 'Provided decide options is not an array. Using default decide options.')
|
187
|
+
decide_options = @default_decide_options
|
188
|
+
end
|
189
|
+
|
190
|
+
# Create Optimizely Decision Result.
|
191
|
+
user_id = user_context.user_id
|
192
|
+
attributes = user_context.user_attributes
|
193
|
+
variation_key = nil
|
194
|
+
feature_enabled = false
|
195
|
+
rule_key = nil
|
196
|
+
flag_key = key
|
197
|
+
all_variables = {}
|
198
|
+
decision_event_dispatched = false
|
199
|
+
experiment = nil
|
200
|
+
decision_source = Optimizely::DecisionService::DECISION_SOURCES['ROLLOUT']
|
201
|
+
|
202
|
+
decision, reasons_received = @decision_service.get_variation_for_feature(config, feature_flag, user_id, attributes, decide_options)
|
203
|
+
reasons.push(*reasons_received)
|
204
|
+
|
205
|
+
# Send impression event if Decision came from a feature test and decide options doesn't include disableDecisionEvent
|
206
|
+
if decision.is_a?(Optimizely::DecisionService::Decision)
|
207
|
+
experiment = decision.experiment
|
208
|
+
rule_key = experiment['key']
|
209
|
+
variation = decision['variation']
|
210
|
+
variation_key = variation['key']
|
211
|
+
feature_enabled = variation['featureEnabled']
|
212
|
+
decision_source = decision.source
|
213
|
+
end
|
214
|
+
|
215
|
+
unless decide_options.include? OptimizelyDecideOption::DISABLE_DECISION_EVENT
|
216
|
+
if decision_source == Optimizely::DecisionService::DECISION_SOURCES['FEATURE_TEST'] || config.send_flag_decisions
|
217
|
+
send_impression(config, experiment, variation_key || '', flag_key, rule_key || '', feature_enabled, decision_source, user_id, attributes)
|
218
|
+
decision_event_dispatched = true
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# Generate all variables map if decide options doesn't include excludeVariables
|
223
|
+
unless decide_options.include? OptimizelyDecideOption::EXCLUDE_VARIABLES
|
224
|
+
feature_flag['variables'].each do |variable|
|
225
|
+
variable_value = get_feature_variable_for_variation(key, feature_enabled, variation, variable, user_id)
|
226
|
+
all_variables[variable['key']] = Helpers::VariableType.cast_value_to_type(variable_value, variable['type'], @logger)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
should_include_reasons = decide_options.include? OptimizelyDecideOption::INCLUDE_REASONS
|
231
|
+
|
232
|
+
# Send notification
|
233
|
+
@notification_center.send_notifications(
|
234
|
+
NotificationCenter::NOTIFICATION_TYPES[:DECISION],
|
235
|
+
Helpers::Constants::DECISION_NOTIFICATION_TYPES['FLAG'],
|
236
|
+
user_id, (attributes || {}),
|
237
|
+
flag_key: flag_key,
|
238
|
+
enabled: feature_enabled,
|
239
|
+
variables: all_variables,
|
240
|
+
variation_key: variation_key,
|
241
|
+
rule_key: rule_key,
|
242
|
+
reasons: should_include_reasons ? reasons : [],
|
243
|
+
decision_event_dispatched: decision_event_dispatched
|
244
|
+
)
|
245
|
+
|
246
|
+
OptimizelyDecision.new(
|
247
|
+
variation_key: variation_key,
|
248
|
+
enabled: feature_enabled,
|
249
|
+
variables: all_variables,
|
250
|
+
rule_key: rule_key,
|
251
|
+
flag_key: flag_key,
|
252
|
+
user_context: user_context,
|
253
|
+
reasons: should_include_reasons ? reasons : []
|
254
|
+
)
|
255
|
+
end
|
256
|
+
|
257
|
+
def decide_all(user_context, decide_options = [])
|
258
|
+
# raising on user context as it is internal and not provided directly by the user.
|
259
|
+
raise if user_context.class != OptimizelyUserContext
|
260
|
+
|
261
|
+
# check if SDK is ready
|
262
|
+
unless is_valid
|
263
|
+
@logger.log(Logger::ERROR, InvalidProjectConfigError.new('decide_all').message)
|
264
|
+
return {}
|
265
|
+
end
|
266
|
+
|
267
|
+
keys = []
|
268
|
+
project_config.feature_flags.each do |feature_flag|
|
269
|
+
keys.push(feature_flag['key'])
|
270
|
+
end
|
271
|
+
decide_for_keys(user_context, keys, decide_options)
|
272
|
+
end
|
273
|
+
|
274
|
+
def decide_for_keys(user_context, keys, decide_options = [])
|
275
|
+
# raising on user context as it is internal and not provided directly by the user.
|
276
|
+
raise if user_context.class != OptimizelyUserContext
|
277
|
+
|
278
|
+
# check if SDK is ready
|
279
|
+
unless is_valid
|
280
|
+
@logger.log(Logger::ERROR, InvalidProjectConfigError.new('decide_for_keys').message)
|
281
|
+
return {}
|
282
|
+
end
|
283
|
+
|
284
|
+
enabled_flags_only = (!decide_options.nil? && (decide_options.include? OptimizelyDecideOption::ENABLED_FLAGS_ONLY)) || (@default_decide_options.include? OptimizelyDecideOption::ENABLED_FLAGS_ONLY)
|
285
|
+
|
286
|
+
decisions = {}
|
287
|
+
keys.each do |key|
|
288
|
+
decision = decide(user_context, key, decide_options)
|
289
|
+
decisions[key] = decision unless enabled_flags_only && !decision.enabled
|
290
|
+
end
|
291
|
+
decisions
|
292
|
+
end
|
293
|
+
|
110
294
|
# Buckets visitor and sends impression event to Optimizely.
|
111
295
|
#
|
112
296
|
# @param experiment_key - Experiment which needs to be activated.
|
@@ -140,7 +324,10 @@ module Optimizely
|
|
140
324
|
|
141
325
|
# Create and dispatch impression event
|
142
326
|
experiment = config.get_experiment_from_key(experiment_key)
|
143
|
-
send_impression(
|
327
|
+
send_impression(
|
328
|
+
config, experiment, variation_key, '', experiment_key, true,
|
329
|
+
Optimizely::DecisionService::DECISION_SOURCES['EXPERIMENT'], user_id, attributes
|
330
|
+
)
|
144
331
|
|
145
332
|
variation_key
|
146
333
|
end
|
@@ -219,7 +406,7 @@ module Optimizely
|
|
219
406
|
config = project_config
|
220
407
|
|
221
408
|
forced_variation_key = nil
|
222
|
-
forced_variation = @decision_service.get_forced_variation(config, experiment_key, user_id)
|
409
|
+
forced_variation, = @decision_service.get_forced_variation(config, experiment_key, user_id)
|
223
410
|
forced_variation_key = forced_variation['key'] if forced_variation
|
224
411
|
|
225
412
|
forced_variation_key
|
@@ -303,7 +490,7 @@ module Optimizely
|
|
303
490
|
return false
|
304
491
|
end
|
305
492
|
|
306
|
-
decision = @decision_service.get_variation_for_feature(config, feature_flag, user_id, attributes)
|
493
|
+
decision, = @decision_service.get_variation_for_feature(config, feature_flag, user_id, attributes)
|
307
494
|
|
308
495
|
feature_enabled = false
|
309
496
|
source_string = Optimizely::DecisionService::DECISION_SOURCES['ROLLOUT']
|
@@ -316,14 +503,23 @@ module Optimizely
|
|
316
503
|
experiment_key: decision.experiment['key'],
|
317
504
|
variation_key: variation['key']
|
318
505
|
}
|
319
|
-
# Send event if Decision came from
|
320
|
-
send_impression(
|
321
|
-
|
322
|
-
|
323
|
-
|
506
|
+
# Send event if Decision came from a feature test.
|
507
|
+
send_impression(
|
508
|
+
config, decision.experiment, variation['key'], feature_flag_key, decision.experiment['key'], feature_enabled, source_string, user_id, attributes
|
509
|
+
)
|
510
|
+
elsif decision.source == Optimizely::DecisionService::DECISION_SOURCES['ROLLOUT'] && config.send_flag_decisions
|
511
|
+
send_impression(
|
512
|
+
config, decision.experiment, variation['key'], feature_flag_key, decision.experiment['key'], feature_enabled, source_string, user_id, attributes
|
513
|
+
)
|
324
514
|
end
|
325
515
|
end
|
326
516
|
|
517
|
+
if decision.nil? && config.send_flag_decisions
|
518
|
+
send_impression(
|
519
|
+
config, nil, '', feature_flag_key, '', feature_enabled, source_string, user_id, attributes
|
520
|
+
)
|
521
|
+
end
|
522
|
+
|
327
523
|
@notification_center.send_notifications(
|
328
524
|
NotificationCenter::NOTIFICATION_TYPES[:DECISION],
|
329
525
|
Helpers::Constants::DECISION_NOTIFICATION_TYPES['FEATURE'],
|
@@ -543,7 +739,7 @@ module Optimizely
|
|
543
739
|
return nil
|
544
740
|
end
|
545
741
|
|
546
|
-
decision = @decision_service.get_variation_for_feature(config, feature_flag, user_id, attributes)
|
742
|
+
decision, = @decision_service.get_variation_for_feature(config, feature_flag, user_id, attributes)
|
547
743
|
variation = decision ? decision['variation'] : nil
|
548
744
|
feature_enabled = variation ? variation['featureEnabled'] : false
|
549
745
|
all_variables = {}
|
@@ -681,12 +877,14 @@ module Optimizely
|
|
681
877
|
experiment = config.get_experiment_from_key(experiment_key)
|
682
878
|
return nil if experiment.nil?
|
683
879
|
|
880
|
+
experiment_id = experiment['id']
|
881
|
+
|
684
882
|
return nil unless user_inputs_valid?(attributes)
|
685
883
|
|
686
|
-
variation_id = @decision_service.get_variation(config,
|
884
|
+
variation_id, = @decision_service.get_variation(config, experiment_id, user_id, attributes)
|
687
885
|
variation = config.get_variation_from_id(experiment_key, variation_id) unless variation_id.nil?
|
688
886
|
variation_key = variation['key'] if variation
|
689
|
-
decision_notification_type = if config.feature_experiment?(
|
887
|
+
decision_notification_type = if config.feature_experiment?(experiment_id)
|
690
888
|
Helpers::Constants::DECISION_NOTIFICATION_TYPES['FEATURE_TEST']
|
691
889
|
else
|
692
890
|
Helpers::Constants::DECISION_NOTIFICATION_TYPES['AB_TEST']
|
@@ -749,7 +947,7 @@ module Optimizely
|
|
749
947
|
return nil
|
750
948
|
end
|
751
949
|
|
752
|
-
decision = @decision_service.get_variation_for_feature(config, feature_flag, user_id, attributes)
|
950
|
+
decision, = @decision_service.get_variation_for_feature(config, feature_flag, user_id, attributes)
|
753
951
|
variation = decision ? decision['variation'] : nil
|
754
952
|
feature_enabled = variation ? variation['featureEnabled'] : false
|
755
953
|
|
@@ -867,15 +1065,44 @@ module Optimizely
|
|
867
1065
|
raise InvalidInputError, 'event_dispatcher'
|
868
1066
|
end
|
869
1067
|
|
870
|
-
def send_impression(config, experiment, variation_key, user_id, attributes = nil)
|
1068
|
+
def send_impression(config, experiment, variation_key, flag_key, rule_key, enabled, rule_type, user_id, attributes = nil)
|
1069
|
+
if experiment.nil?
|
1070
|
+
experiment = {
|
1071
|
+
'id' => '',
|
1072
|
+
'key' => '',
|
1073
|
+
'layerId' => '',
|
1074
|
+
'status' => '',
|
1075
|
+
'variations' => [],
|
1076
|
+
'trafficAllocation' => [],
|
1077
|
+
'audienceIds' => [],
|
1078
|
+
'audienceConditions' => [],
|
1079
|
+
'forcedVariations' => {}
|
1080
|
+
}
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
experiment_id = experiment['id']
|
871
1084
|
experiment_key = experiment['key']
|
872
|
-
|
873
|
-
|
1085
|
+
|
1086
|
+
variation_id = ''
|
1087
|
+
variation_id = config.get_variation_id_from_key_by_experiment_id(experiment_id, variation_key) if experiment_id != ''
|
1088
|
+
|
1089
|
+
metadata = {
|
1090
|
+
flag_key: flag_key,
|
1091
|
+
rule_key: rule_key,
|
1092
|
+
rule_type: rule_type,
|
1093
|
+
variation_key: variation_key,
|
1094
|
+
enabled: enabled
|
1095
|
+
}
|
1096
|
+
|
1097
|
+
user_event = UserEventFactory.create_impression_event(config, experiment, variation_id, metadata, user_id, attributes)
|
874
1098
|
@event_processor.process(user_event)
|
875
1099
|
return unless @notification_center.notification_count(NotificationCenter::NOTIFICATION_TYPES[:ACTIVATE]).positive?
|
876
1100
|
|
877
1101
|
@logger.log(Logger::INFO, "Activating user '#{user_id}' in experiment '#{experiment_key}'.")
|
878
|
-
|
1102
|
+
|
1103
|
+
experiment = nil if experiment_id == ''
|
1104
|
+
variation = nil
|
1105
|
+
variation = config.get_variation_from_id_by_experiment_id(experiment_id, variation_id) unless experiment.nil?
|
879
1106
|
log_event = EventFactory.create_log_event(user_event, @logger)
|
880
1107
|
@notification_center.send_notifications(
|
881
1108
|
NotificationCenter::NOTIFICATION_TYPES[:ACTIVATE],
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: optimizely-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Optimizely
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -141,6 +141,9 @@ files:
|
|
141
141
|
- lib/optimizely/config_manager/project_config_manager.rb
|
142
142
|
- lib/optimizely/config_manager/static_project_config_manager.rb
|
143
143
|
- lib/optimizely/custom_attribute_condition_evaluator.rb
|
144
|
+
- lib/optimizely/decide/optimizely_decide_option.rb
|
145
|
+
- lib/optimizely/decide/optimizely_decision.rb
|
146
|
+
- lib/optimizely/decide/optimizely_decision_message.rb
|
144
147
|
- lib/optimizely/decision_service.rb
|
145
148
|
- lib/optimizely/error_handler.rb
|
146
149
|
- lib/optimizely/event/batch_event_processor.rb
|
@@ -172,6 +175,7 @@ files:
|
|
172
175
|
- lib/optimizely/notification_center.rb
|
173
176
|
- lib/optimizely/optimizely_config.rb
|
174
177
|
- lib/optimizely/optimizely_factory.rb
|
178
|
+
- lib/optimizely/optimizely_user_context.rb
|
175
179
|
- lib/optimizely/params.rb
|
176
180
|
- lib/optimizely/project_config.rb
|
177
181
|
- lib/optimizely/semantic_version.rb
|
@@ -196,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
196
200
|
- !ruby/object:Gem::Version
|
197
201
|
version: '0'
|
198
202
|
requirements: []
|
199
|
-
rubygems_version: 3.0.
|
203
|
+
rubygems_version: 3.0.1
|
200
204
|
signing_key:
|
201
205
|
specification_version: 4
|
202
206
|
summary: Ruby SDK for Optimizely's testing framework
|