optimizely-sdk 5.0.1 → 5.2.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/optimizely/audience.rb +15 -1
- data/lib/optimizely/bucketer.rb +34 -13
- data/lib/optimizely/cmab/cmab_client.rb +230 -0
- data/lib/optimizely/cmab/cmab_service.rb +218 -0
- data/lib/optimizely/config/datafile_project_config.rb +140 -2
- data/lib/optimizely/config_manager/http_project_config_manager.rb +1 -1
- data/lib/optimizely/decide/optimizely_decide_option.rb +3 -0
- data/lib/optimizely/decide/optimizely_decision.rb +19 -0
- data/lib/optimizely/decision_service.rb +280 -59
- data/lib/optimizely/event/entity/event_context.rb +5 -2
- data/lib/optimizely/event/event_factory.rb +8 -2
- data/lib/optimizely/event/user_event_factory.rb +2 -0
- data/lib/optimizely/event_builder.rb +15 -5
- data/lib/optimizely/exceptions.rb +24 -0
- data/lib/optimizely/helpers/constants.rb +46 -0
- data/lib/optimizely/helpers/sdk_settings.rb +5 -2
- data/lib/optimizely/odp/lru_cache.rb +14 -1
- data/lib/optimizely/optimizely_factory.rb +56 -2
- data/lib/optimizely/project_config.rb +6 -0
- data/lib/optimizely/user_profile_tracker.rb +64 -0
- data/lib/optimizely/version.rb +1 -1
- data/lib/optimizely.rb +173 -70
- metadata +6 -3
data/lib/optimizely.rb
CHANGED
|
@@ -42,6 +42,9 @@ require_relative 'optimizely/optimizely_user_context'
|
|
|
42
42
|
require_relative 'optimizely/odp/lru_cache'
|
|
43
43
|
require_relative 'optimizely/odp/odp_manager'
|
|
44
44
|
require_relative 'optimizely/helpers/sdk_settings'
|
|
45
|
+
require_relative 'optimizely/user_profile_tracker'
|
|
46
|
+
require_relative 'optimizely/cmab/cmab_client'
|
|
47
|
+
require_relative 'optimizely/cmab/cmab_service'
|
|
45
48
|
|
|
46
49
|
module Optimizely
|
|
47
50
|
class Project
|
|
@@ -83,7 +86,8 @@ module Optimizely
|
|
|
83
86
|
event_processor: nil,
|
|
84
87
|
default_decide_options: [],
|
|
85
88
|
event_processor_options: {},
|
|
86
|
-
settings: nil
|
|
89
|
+
settings: nil,
|
|
90
|
+
cmab_service: nil
|
|
87
91
|
)
|
|
88
92
|
@logger = logger || NoOpLogger.new
|
|
89
93
|
@error_handler = error_handler || NoOpErrorHandler.new
|
|
@@ -130,7 +134,24 @@ module Optimizely
|
|
|
130
134
|
|
|
131
135
|
setup_odp!(@config_manager.sdk_key)
|
|
132
136
|
|
|
133
|
-
|
|
137
|
+
# Initialize CMAB components if cmab service is nil
|
|
138
|
+
if cmab_service.nil?
|
|
139
|
+
@cmab_client = DefaultCmabClient.new(
|
|
140
|
+
http_client: nil,
|
|
141
|
+
retry_config: CmabRetryConfig.new,
|
|
142
|
+
logger: @logger
|
|
143
|
+
)
|
|
144
|
+
@cmab_cache = LRUCache.new(Optimizely::DefaultCmabCacheOptions::DEFAULT_CMAB_CACHE_SIZE, Optimizely::DefaultCmabCacheOptions::DEFAULT_CMAB_CACHE_TIMEOUT)
|
|
145
|
+
@cmab_service = DefaultCmabService.new(
|
|
146
|
+
@cmab_cache,
|
|
147
|
+
@cmab_client,
|
|
148
|
+
@logger
|
|
149
|
+
)
|
|
150
|
+
else
|
|
151
|
+
@cmab_service = cmab_service
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
@decision_service = DecisionService.new(@logger, @cmab_service, @user_profile_service)
|
|
134
155
|
|
|
135
156
|
@event_processor = if event_processor.respond_to?(:process)
|
|
136
157
|
event_processor
|
|
@@ -172,84 +193,42 @@ module Optimizely
|
|
|
172
193
|
OptimizelyUserContext.new(self, user_id, attributes)
|
|
173
194
|
end
|
|
174
195
|
|
|
175
|
-
def
|
|
176
|
-
# raising on user context as it is internal and not provided directly by the user.
|
|
177
|
-
raise if user_context.class != OptimizelyUserContext
|
|
178
|
-
|
|
179
|
-
reasons = []
|
|
180
|
-
|
|
181
|
-
# check if SDK is ready
|
|
182
|
-
unless is_valid
|
|
183
|
-
@logger.log(Logger::ERROR, InvalidProjectConfigError.new('decide').message)
|
|
184
|
-
reasons.push(OptimizelyDecisionMessage::SDK_NOT_READY)
|
|
185
|
-
return OptimizelyDecision.new(flag_key: key, user_context: user_context, reasons: reasons)
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
# validate that key is a string
|
|
189
|
-
unless key.is_a?(String)
|
|
190
|
-
@logger.log(Logger::ERROR, 'Provided key is invalid')
|
|
191
|
-
reasons.push(format(OptimizelyDecisionMessage::FLAG_KEY_INVALID, key))
|
|
192
|
-
return OptimizelyDecision.new(flag_key: key, user_context: user_context, reasons: reasons)
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
# validate that key maps to a feature flag
|
|
196
|
-
config = project_config
|
|
197
|
-
feature_flag = config.get_feature_flag_from_key(key)
|
|
198
|
-
unless feature_flag
|
|
199
|
-
@logger.log(Logger::ERROR, "No feature flag was found for key '#{key}'.")
|
|
200
|
-
reasons.push(format(OptimizelyDecisionMessage::FLAG_KEY_INVALID, key))
|
|
201
|
-
return OptimizelyDecision.new(flag_key: key, user_context: user_context, reasons: reasons)
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
# merge decide_options and default_decide_options
|
|
205
|
-
if decide_options.is_a? Array
|
|
206
|
-
decide_options += @default_decide_options
|
|
207
|
-
else
|
|
208
|
-
@logger.log(Logger::DEBUG, 'Provided decide options is not an array. Using default decide options.')
|
|
209
|
-
decide_options = @default_decide_options
|
|
210
|
-
end
|
|
211
|
-
|
|
196
|
+
def create_optimizely_decision(user_context, flag_key, decision, reasons, decide_options, config)
|
|
212
197
|
# Create Optimizely Decision Result.
|
|
213
198
|
user_id = user_context.user_id
|
|
214
199
|
attributes = user_context.user_attributes
|
|
215
200
|
variation_key = nil
|
|
216
201
|
feature_enabled = false
|
|
217
202
|
rule_key = nil
|
|
218
|
-
flag_key = key
|
|
219
203
|
all_variables = {}
|
|
220
204
|
decision_event_dispatched = false
|
|
205
|
+
feature_flag = config.get_feature_flag_from_key(flag_key)
|
|
221
206
|
experiment = nil
|
|
222
207
|
decision_source = Optimizely::DecisionService::DECISION_SOURCES['ROLLOUT']
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
reasons.push(*reasons_received)
|
|
226
|
-
|
|
227
|
-
if variation
|
|
228
|
-
decision = Optimizely::DecisionService::Decision.new(nil, variation, Optimizely::DecisionService::DECISION_SOURCES['FEATURE_TEST'])
|
|
229
|
-
else
|
|
230
|
-
decision, reasons_received = @decision_service.get_variation_for_feature(config, feature_flag, user_context, decide_options)
|
|
231
|
-
reasons.push(*reasons_received)
|
|
232
|
-
end
|
|
208
|
+
experiment_id = nil
|
|
209
|
+
variation_id = nil
|
|
233
210
|
|
|
234
211
|
# Send impression event if Decision came from a feature test and decide options doesn't include disableDecisionEvent
|
|
235
212
|
if decision.is_a?(Optimizely::DecisionService::Decision)
|
|
236
213
|
experiment = decision.experiment
|
|
237
214
|
rule_key = experiment ? experiment['key'] : nil
|
|
238
|
-
|
|
215
|
+
experiment_id = experiment ? experiment['id'] : nil
|
|
216
|
+
variation = decision.variation
|
|
239
217
|
variation_key = variation ? variation['key'] : nil
|
|
218
|
+
variation_id = variation ? variation['id'] : nil
|
|
240
219
|
feature_enabled = variation ? variation['featureEnabled'] : false
|
|
241
220
|
decision_source = decision.source
|
|
242
221
|
end
|
|
243
222
|
|
|
244
223
|
if !decide_options.include?(OptimizelyDecideOption::DISABLE_DECISION_EVENT) && (decision_source == Optimizely::DecisionService::DECISION_SOURCES['FEATURE_TEST'] || config.send_flag_decisions)
|
|
245
|
-
send_impression(config, experiment, variation_key || '', flag_key, rule_key || '', feature_enabled, decision_source, user_id, attributes)
|
|
224
|
+
send_impression(config, experiment, variation_key || '', flag_key, rule_key || '', feature_enabled, decision_source, user_id, attributes, decision&.cmab_uuid)
|
|
246
225
|
decision_event_dispatched = true
|
|
247
226
|
end
|
|
248
227
|
|
|
249
228
|
# Generate all variables map if decide options doesn't include excludeVariables
|
|
250
229
|
unless decide_options.include? OptimizelyDecideOption::EXCLUDE_VARIABLES
|
|
251
230
|
feature_flag['variables'].each do |variable|
|
|
252
|
-
variable_value = get_feature_variable_for_variation(
|
|
231
|
+
variable_value = get_feature_variable_for_variation(flag_key, feature_enabled, variation, variable, user_id)
|
|
253
232
|
all_variables[variable['key']] = Helpers::VariableType.cast_value_to_type(variable_value, variable['type'], @logger)
|
|
254
233
|
end
|
|
255
234
|
end
|
|
@@ -260,14 +239,16 @@ module Optimizely
|
|
|
260
239
|
@notification_center.send_notifications(
|
|
261
240
|
NotificationCenter::NOTIFICATION_TYPES[:DECISION],
|
|
262
241
|
Helpers::Constants::DECISION_NOTIFICATION_TYPES['FLAG'],
|
|
263
|
-
user_id,
|
|
242
|
+
user_id, attributes || {},
|
|
264
243
|
flag_key: flag_key,
|
|
265
244
|
enabled: feature_enabled,
|
|
266
245
|
variables: all_variables,
|
|
267
246
|
variation_key: variation_key,
|
|
268
247
|
rule_key: rule_key,
|
|
269
248
|
reasons: should_include_reasons ? reasons : [],
|
|
270
|
-
decision_event_dispatched: decision_event_dispatched
|
|
249
|
+
decision_event_dispatched: decision_event_dispatched,
|
|
250
|
+
experiment_id: experiment_id,
|
|
251
|
+
variation_id: variation_id
|
|
271
252
|
)
|
|
272
253
|
|
|
273
254
|
OptimizelyDecision.new(
|
|
@@ -281,6 +262,47 @@ module Optimizely
|
|
|
281
262
|
)
|
|
282
263
|
end
|
|
283
264
|
|
|
265
|
+
def decide(user_context, key, decide_options = [])
|
|
266
|
+
# raising on user context as it is internal and not provided directly by the user.
|
|
267
|
+
raise if user_context.class != OptimizelyUserContext
|
|
268
|
+
|
|
269
|
+
reasons = []
|
|
270
|
+
|
|
271
|
+
# check if SDK is ready
|
|
272
|
+
unless is_valid
|
|
273
|
+
@logger.log(Logger::ERROR, InvalidProjectConfigError.new('decide').message)
|
|
274
|
+
reasons.push(OptimizelyDecisionMessage::SDK_NOT_READY)
|
|
275
|
+
return OptimizelyDecision.new(flag_key: key, user_context: user_context, reasons: reasons)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# validate that key is a string
|
|
279
|
+
unless key.is_a?(String)
|
|
280
|
+
@logger.log(Logger::ERROR, 'Provided key is invalid')
|
|
281
|
+
reasons.push(format(OptimizelyDecisionMessage::FLAG_KEY_INVALID, key))
|
|
282
|
+
return OptimizelyDecision.new(flag_key: key, user_context: user_context, reasons: reasons)
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# validate that key maps to a feature flag
|
|
286
|
+
config = project_config
|
|
287
|
+
feature_flag = config.get_feature_flag_from_key(key)
|
|
288
|
+
unless feature_flag
|
|
289
|
+
@logger.log(Logger::ERROR, "No feature flag was found for key '#{key}'.")
|
|
290
|
+
reasons.push(format(OptimizelyDecisionMessage::FLAG_KEY_INVALID, key))
|
|
291
|
+
return OptimizelyDecision.new(flag_key: key, user_context: user_context, reasons: reasons)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# merge decide_options and default_decide_options
|
|
295
|
+
if decide_options.is_a? Array
|
|
296
|
+
decide_options += @default_decide_options
|
|
297
|
+
else
|
|
298
|
+
@logger.log(Logger::DEBUG, 'Provided decide options is not an array. Using default decide options.')
|
|
299
|
+
decide_options = @default_decide_options
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
decide_options.delete(OptimizelyDecideOption::ENABLED_FLAGS_ONLY) if decide_options.include?(OptimizelyDecideOption::ENABLED_FLAGS_ONLY)
|
|
303
|
+
decide_for_keys(user_context, [key], decide_options, true)[key]
|
|
304
|
+
end
|
|
305
|
+
|
|
284
306
|
def decide_all(user_context, decide_options = [])
|
|
285
307
|
# raising on user context as it is internal and not provided directly by the user.
|
|
286
308
|
raise if user_context.class != OptimizelyUserContext
|
|
@@ -298,7 +320,7 @@ module Optimizely
|
|
|
298
320
|
decide_for_keys(user_context, keys, decide_options)
|
|
299
321
|
end
|
|
300
322
|
|
|
301
|
-
def decide_for_keys(user_context, keys, decide_options = [])
|
|
323
|
+
def decide_for_keys(user_context, keys, decide_options = [], ignore_default_options = false) # rubocop:disable Style/OptionalBooleanParameter
|
|
302
324
|
# raising on user context as it is internal and not provided directly by the user.
|
|
303
325
|
raise if user_context.class != OptimizelyUserContext
|
|
304
326
|
|
|
@@ -308,13 +330,87 @@ module Optimizely
|
|
|
308
330
|
return {}
|
|
309
331
|
end
|
|
310
332
|
|
|
311
|
-
|
|
333
|
+
# merge decide_options and default_decide_options
|
|
334
|
+
unless ignore_default_options
|
|
335
|
+
if decide_options.is_a?(Array)
|
|
336
|
+
decide_options += @default_decide_options
|
|
337
|
+
else
|
|
338
|
+
@logger.log(Logger::DEBUG, 'Provided decide options is not an array. Using default decide options.')
|
|
339
|
+
decide_options = @default_decide_options
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# enabled_flags_only = (!decide_options.nil? && (decide_options.include? OptimizelyDecideOption::ENABLED_FLAGS_ONLY)) || (@default_decide_options.include? OptimizelyDecideOption::ENABLED_FLAGS_ONLY)
|
|
312
344
|
|
|
313
345
|
decisions = {}
|
|
346
|
+
valid_keys = []
|
|
347
|
+
decision_reasons_dict = {}
|
|
348
|
+
config = project_config
|
|
349
|
+
return decisions unless config
|
|
350
|
+
|
|
351
|
+
flags_without_forced_decision = []
|
|
352
|
+
flag_decisions = {}
|
|
353
|
+
|
|
314
354
|
keys.each do |key|
|
|
315
|
-
|
|
316
|
-
|
|
355
|
+
# Retrieve the feature flag from the project's feature flag key map
|
|
356
|
+
feature_flag = config.feature_flag_key_map[key]
|
|
357
|
+
|
|
358
|
+
# If the feature flag is nil, create a default OptimizelyDecision and move to the next key
|
|
359
|
+
if feature_flag.nil?
|
|
360
|
+
decisions[key] = OptimizelyDecision.new(variation_key: nil, enabled: false, variables: nil, rule_key: nil, flag_key: key, user_context: user_context, reasons: [])
|
|
361
|
+
next
|
|
362
|
+
end
|
|
363
|
+
valid_keys.push(key)
|
|
364
|
+
decision_reasons = []
|
|
365
|
+
decision_reasons_dict[key] = decision_reasons
|
|
366
|
+
|
|
367
|
+
config = project_config
|
|
368
|
+
context = Optimizely::OptimizelyUserContext::OptimizelyDecisionContext.new(key, nil)
|
|
369
|
+
variation, reasons_received = @decision_service.validated_forced_decision(config, context, user_context)
|
|
370
|
+
decision_reasons_dict[key].push(*reasons_received)
|
|
371
|
+
if variation
|
|
372
|
+
decision = Optimizely::DecisionService::Decision.new(nil, variation, Optimizely::DecisionService::DECISION_SOURCES['FEATURE_TEST'])
|
|
373
|
+
flag_decisions[key] = decision
|
|
374
|
+
else
|
|
375
|
+
flags_without_forced_decision.push(feature_flag)
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
decision_list = @decision_service.get_variations_for_feature_list(config, flags_without_forced_decision, user_context, decide_options)
|
|
379
|
+
|
|
380
|
+
flags_without_forced_decision.each_with_index do |flag, i|
|
|
381
|
+
decision = decision_list[i].decision
|
|
382
|
+
reasons = decision_list[i].reasons
|
|
383
|
+
error = decision_list[i].error
|
|
384
|
+
flag_key = flag['key']
|
|
385
|
+
# store error decision against key and remove key from valid keys
|
|
386
|
+
if error
|
|
387
|
+
optimizely_decision = OptimizelyDecision.new_error_decision(flag_key, user_context, reasons)
|
|
388
|
+
decisions[flag_key] = optimizely_decision
|
|
389
|
+
valid_keys.delete(flag_key) if valid_keys.include?(flag_key)
|
|
390
|
+
next
|
|
391
|
+
end
|
|
392
|
+
flag_decisions[flag_key] = decision
|
|
393
|
+
decision_reasons_dict[flag_key] ||= []
|
|
394
|
+
decision_reasons_dict[flag_key].push(*reasons)
|
|
317
395
|
end
|
|
396
|
+
valid_keys.each do |key|
|
|
397
|
+
flag_decision = flag_decisions[key]
|
|
398
|
+
decision_reasons = decision_reasons_dict[key]
|
|
399
|
+
optimizely_decision = create_optimizely_decision(
|
|
400
|
+
user_context,
|
|
401
|
+
key,
|
|
402
|
+
flag_decision,
|
|
403
|
+
decision_reasons,
|
|
404
|
+
decide_options,
|
|
405
|
+
config
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
enabled_flags_only_missing = !decide_options.include?(OptimizelyDecideOption::ENABLED_FLAGS_ONLY)
|
|
409
|
+
is_enabled = optimizely_decision.enabled
|
|
410
|
+
|
|
411
|
+
decisions[key] = optimizely_decision if enabled_flags_only_missing || is_enabled
|
|
412
|
+
end
|
|
413
|
+
|
|
318
414
|
decisions
|
|
319
415
|
end
|
|
320
416
|
|
|
@@ -531,14 +627,14 @@ module Optimizely
|
|
|
531
627
|
end
|
|
532
628
|
|
|
533
629
|
user_context = OptimizelyUserContext.new(self, user_id, attributes, identify: false)
|
|
534
|
-
|
|
535
|
-
|
|
630
|
+
decision_result = @decision_service.get_variation_for_feature(config, feature_flag, user_context)
|
|
631
|
+
decision = decision_result.decision
|
|
536
632
|
feature_enabled = false
|
|
537
633
|
source_string = Optimizely::DecisionService::DECISION_SOURCES['ROLLOUT']
|
|
538
634
|
if decision.is_a?(Optimizely::DecisionService::Decision)
|
|
539
635
|
variation = decision['variation']
|
|
540
636
|
feature_enabled = variation['featureEnabled']
|
|
541
|
-
if decision.source == Optimizely::DecisionService::DECISION_SOURCES['FEATURE_TEST']
|
|
637
|
+
if decision.source == Optimizely::DecisionService::DECISION_SOURCES['FEATURE_TEST'] || decision.source == Optimizely::DecisionService::DECISION_SOURCES['HOLDOUT']
|
|
542
638
|
source_string = Optimizely::DecisionService::DECISION_SOURCES['FEATURE_TEST']
|
|
543
639
|
source_info = {
|
|
544
640
|
experiment_key: decision.experiment['key'],
|
|
@@ -564,7 +660,7 @@ module Optimizely
|
|
|
564
660
|
@notification_center.send_notifications(
|
|
565
661
|
NotificationCenter::NOTIFICATION_TYPES[:DECISION],
|
|
566
662
|
Helpers::Constants::DECISION_NOTIFICATION_TYPES['FEATURE'],
|
|
567
|
-
user_id,
|
|
663
|
+
user_id, attributes || {},
|
|
568
664
|
feature_key: feature_flag_key,
|
|
569
665
|
feature_enabled: feature_enabled,
|
|
570
666
|
source: source_string,
|
|
@@ -771,7 +867,8 @@ module Optimizely
|
|
|
771
867
|
end
|
|
772
868
|
|
|
773
869
|
user_context = OptimizelyUserContext.new(self, user_id, attributes, identify: false)
|
|
774
|
-
|
|
870
|
+
decision_result = @decision_service.get_variation_for_feature(config, feature_flag, user_context)
|
|
871
|
+
decision = decision_result.decision
|
|
775
872
|
variation = decision ? decision['variation'] : nil
|
|
776
873
|
feature_enabled = variation ? variation['featureEnabled'] : false
|
|
777
874
|
all_variables = {}
|
|
@@ -792,7 +889,7 @@ module Optimizely
|
|
|
792
889
|
|
|
793
890
|
@notification_center.send_notifications(
|
|
794
891
|
NotificationCenter::NOTIFICATION_TYPES[:DECISION],
|
|
795
|
-
Helpers::Constants::DECISION_NOTIFICATION_TYPES['ALL_FEATURE_VARIABLES'], user_id,
|
|
892
|
+
Helpers::Constants::DECISION_NOTIFICATION_TYPES['ALL_FEATURE_VARIABLES'], user_id, attributes || {},
|
|
796
893
|
feature_key: feature_flag_key,
|
|
797
894
|
feature_enabled: feature_enabled,
|
|
798
895
|
source: source_string,
|
|
@@ -959,7 +1056,11 @@ module Optimizely
|
|
|
959
1056
|
return nil unless user_inputs_valid?(attributes)
|
|
960
1057
|
|
|
961
1058
|
user_context = OptimizelyUserContext.new(self, user_id, attributes, identify: false)
|
|
962
|
-
|
|
1059
|
+
user_profile_tracker = UserProfileTracker.new(user_id, @user_profile_service, @logger)
|
|
1060
|
+
user_profile_tracker.load_user_profile
|
|
1061
|
+
variation_result = @decision_service.get_variation(config, experiment_id, user_context, user_profile_tracker)
|
|
1062
|
+
variation_id = variation_result.variation_id
|
|
1063
|
+
user_profile_tracker.save_user_profile
|
|
963
1064
|
variation = config.get_variation_from_id(experiment_key, variation_id) unless variation_id.nil?
|
|
964
1065
|
variation_key = variation['key'] if variation
|
|
965
1066
|
decision_notification_type = if config.feature_experiment?(experiment_id)
|
|
@@ -969,7 +1070,7 @@ module Optimizely
|
|
|
969
1070
|
end
|
|
970
1071
|
@notification_center.send_notifications(
|
|
971
1072
|
NotificationCenter::NOTIFICATION_TYPES[:DECISION],
|
|
972
|
-
decision_notification_type, user_id,
|
|
1073
|
+
decision_notification_type, user_id, attributes || {},
|
|
973
1074
|
experiment_key: experiment_key,
|
|
974
1075
|
variation_key: variation_key
|
|
975
1076
|
)
|
|
@@ -1026,7 +1127,8 @@ module Optimizely
|
|
|
1026
1127
|
end
|
|
1027
1128
|
|
|
1028
1129
|
user_context = OptimizelyUserContext.new(self, user_id, attributes, identify: false)
|
|
1029
|
-
|
|
1130
|
+
decision_result = @decision_service.get_variation_for_feature(config, feature_flag, user_context)
|
|
1131
|
+
decision = decision_result.decision
|
|
1030
1132
|
variation = decision ? decision['variation'] : nil
|
|
1031
1133
|
feature_enabled = variation ? variation['featureEnabled'] : false
|
|
1032
1134
|
|
|
@@ -1044,7 +1146,7 @@ module Optimizely
|
|
|
1044
1146
|
|
|
1045
1147
|
@notification_center.send_notifications(
|
|
1046
1148
|
NotificationCenter::NOTIFICATION_TYPES[:DECISION],
|
|
1047
|
-
Helpers::Constants::DECISION_NOTIFICATION_TYPES['FEATURE_VARIABLE'], user_id,
|
|
1149
|
+
Helpers::Constants::DECISION_NOTIFICATION_TYPES['FEATURE_VARIABLE'], user_id, attributes || {},
|
|
1048
1150
|
feature_key: feature_flag_key,
|
|
1049
1151
|
feature_enabled: feature_enabled,
|
|
1050
1152
|
source: source_string,
|
|
@@ -1144,7 +1246,7 @@ module Optimizely
|
|
|
1144
1246
|
raise InvalidInputError, 'event_dispatcher'
|
|
1145
1247
|
end
|
|
1146
1248
|
|
|
1147
|
-
def send_impression(config, experiment, variation_key, flag_key, rule_key, enabled, rule_type, user_id, attributes = nil)
|
|
1249
|
+
def send_impression(config, experiment, variation_key, flag_key, rule_key, enabled, rule_type, user_id, attributes = nil, cmab_uuid = nil)
|
|
1148
1250
|
if experiment.nil?
|
|
1149
1251
|
experiment = {
|
|
1150
1252
|
'id' => '',
|
|
@@ -1176,6 +1278,7 @@ module Optimizely
|
|
|
1176
1278
|
variation_key: variation_key,
|
|
1177
1279
|
enabled: enabled
|
|
1178
1280
|
}
|
|
1281
|
+
metadata[:cmab_uuid] = cmab_uuid unless cmab_uuid.nil?
|
|
1179
1282
|
|
|
1180
1283
|
user_event = UserEventFactory.create_impression_event(config, experiment, variation_id, metadata, user_id, attributes)
|
|
1181
1284
|
@event_processor.process(user_event)
|
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: 5.0
|
|
4
|
+
version: 5.2.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: 2025-11-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -134,6 +134,8 @@ files:
|
|
|
134
134
|
- lib/optimizely.rb
|
|
135
135
|
- lib/optimizely/audience.rb
|
|
136
136
|
- lib/optimizely/bucketer.rb
|
|
137
|
+
- lib/optimizely/cmab/cmab_client.rb
|
|
138
|
+
- lib/optimizely/cmab/cmab_service.rb
|
|
137
139
|
- lib/optimizely/condition_tree_evaluator.rb
|
|
138
140
|
- lib/optimizely/config/datafile_project_config.rb
|
|
139
141
|
- lib/optimizely/config/proxy_config.rb
|
|
@@ -191,6 +193,7 @@ files:
|
|
|
191
193
|
- lib/optimizely/semantic_version.rb
|
|
192
194
|
- lib/optimizely/user_condition_evaluator.rb
|
|
193
195
|
- lib/optimizely/user_profile_service.rb
|
|
196
|
+
- lib/optimizely/user_profile_tracker.rb
|
|
194
197
|
- lib/optimizely/version.rb
|
|
195
198
|
homepage: https://github.com/optimizely/ruby-sdk
|
|
196
199
|
licenses:
|
|
@@ -213,7 +216,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
213
216
|
- !ruby/object:Gem::Version
|
|
214
217
|
version: '0'
|
|
215
218
|
requirements: []
|
|
216
|
-
rubygems_version: 3.4.
|
|
219
|
+
rubygems_version: 3.4.19
|
|
217
220
|
signing_key:
|
|
218
221
|
specification_version: 4
|
|
219
222
|
summary: Ruby SDK for Optimizely's testing framework
|