optimizely-sdk 3.8.0 → 3.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 +4 -4
- data/lib/optimizely.rb +9 -6
- data/lib/optimizely/bucketer.rb +2 -2
- data/lib/optimizely/config/datafile_project_config.rb +80 -13
- data/lib/optimizely/decision_service.rb +20 -20
- data/lib/optimizely/project_config.rb +7 -1
- data/lib/optimizely/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5751701cecb265d27a62c72b268fcb01bb5a37f8696f97a6f56ad29776b226cc
|
4
|
+
data.tar.gz: 32533f70bdd2861e2250b3c1b8e274d61f04395dd4ff5cf7ff0776d5f49c2a90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f7258d91de18c854b91f1d938c4624bf227307a2f01aec82aa23d1f2978ca8510209171f4dc62a3d2dcc606784a741dd9f6572d7c6a81475e2b791e70b7e45be
|
7
|
+
data.tar.gz: 1471cf812fbebc51fe2207e599f44b60597c3e6e15209af400d4ecabe0333bcd285269b3b421ad80f043c33012aecc54d3d41e59c53dffe64b09b93039b36254
|
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.
|
@@ -877,12 +877,14 @@ module Optimizely
|
|
877
877
|
experiment = config.get_experiment_from_key(experiment_key)
|
878
878
|
return nil if experiment.nil?
|
879
879
|
|
880
|
+
experiment_id = experiment['id']
|
881
|
+
|
880
882
|
return nil unless user_inputs_valid?(attributes)
|
881
883
|
|
882
|
-
variation_id, = @decision_service.get_variation(config,
|
884
|
+
variation_id, = @decision_service.get_variation(config, experiment_id, user_id, attributes)
|
883
885
|
variation = config.get_variation_from_id(experiment_key, variation_id) unless variation_id.nil?
|
884
886
|
variation_key = variation['key'] if variation
|
885
|
-
decision_notification_type = if config.feature_experiment?(
|
887
|
+
decision_notification_type = if config.feature_experiment?(experiment_id)
|
886
888
|
Helpers::Constants::DECISION_NOTIFICATION_TYPES['FEATURE_TEST']
|
887
889
|
else
|
888
890
|
Helpers::Constants::DECISION_NOTIFICATION_TYPES['AB_TEST']
|
@@ -1078,10 +1080,11 @@ module Optimizely
|
|
1078
1080
|
}
|
1079
1081
|
end
|
1080
1082
|
|
1083
|
+
experiment_id = experiment['id']
|
1081
1084
|
experiment_key = experiment['key']
|
1082
1085
|
|
1083
1086
|
variation_id = ''
|
1084
|
-
variation_id = config.
|
1087
|
+
variation_id = config.get_variation_id_from_key_by_experiment_id(experiment_id, variation_key) if experiment_id != ''
|
1085
1088
|
|
1086
1089
|
metadata = {
|
1087
1090
|
flag_key: flag_key,
|
@@ -1097,9 +1100,9 @@ module Optimizely
|
|
1097
1100
|
|
1098
1101
|
@logger.log(Logger::INFO, "Activating user '#{user_id}' in experiment '#{experiment_key}'.")
|
1099
1102
|
|
1100
|
-
experiment = nil if
|
1103
|
+
experiment = nil if experiment_id == ''
|
1101
1104
|
variation = nil
|
1102
|
-
variation = config.
|
1105
|
+
variation = config.get_variation_from_id_by_experiment_id(experiment_id, variation_id) unless experiment.nil?
|
1103
1106
|
log_event = EventFactory.create_log_event(user_event, @logger)
|
1104
1107
|
@notification_center.send_notifications(
|
1105
1108
|
NotificationCenter::NOTIFICATION_TYPES[:ACTIVATE],
|
data/lib/optimizely/bucketer.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#
|
4
|
-
# Copyright 2016-2017, 2019-
|
4
|
+
# Copyright 2016-2017, 2019-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.
|
@@ -88,7 +88,7 @@ module Optimizely
|
|
88
88
|
decide_reasons.push(*find_bucket_reasons)
|
89
89
|
|
90
90
|
if variation_id && variation_id != ''
|
91
|
-
variation = project_config.
|
91
|
+
variation = project_config.get_variation_from_id_by_experiment_id(experiment_id, variation_id)
|
92
92
|
return variation, decide_reasons
|
93
93
|
end
|
94
94
|
|
@@ -52,10 +52,12 @@ module Optimizely
|
|
52
52
|
attr_reader :feature_variable_key_map
|
53
53
|
attr_reader :group_id_map
|
54
54
|
attr_reader :rollout_id_map
|
55
|
-
attr_reader :
|
55
|
+
attr_reader :rollout_experiment_id_map
|
56
56
|
attr_reader :variation_id_map
|
57
57
|
attr_reader :variation_id_to_variable_usage_map
|
58
58
|
attr_reader :variation_key_map
|
59
|
+
attr_reader :variation_id_map_by_experiment_id
|
60
|
+
attr_reader :variation_key_map_by_experiment_id
|
59
61
|
|
60
62
|
def initialize(datafile, logger, error_handler)
|
61
63
|
# ProjectConfig init method to fetch and set project config data
|
@@ -113,9 +115,11 @@ module Optimizely
|
|
113
115
|
@audience_id_map = @audience_id_map.merge(generate_key_map(@typed_audiences, 'id')) unless @typed_audiences.empty?
|
114
116
|
@variation_id_map = {}
|
115
117
|
@variation_key_map = {}
|
118
|
+
@variation_id_map_by_experiment_id = {}
|
119
|
+
@variation_key_map_by_experiment_id = {}
|
116
120
|
@variation_id_to_variable_usage_map = {}
|
117
121
|
@variation_id_to_experiment_map = {}
|
118
|
-
@
|
122
|
+
@experiment_id_map.each_value do |exp|
|
119
123
|
# Excludes experiments from rollouts
|
120
124
|
variations = exp.fetch('variations')
|
121
125
|
variations.each do |variation|
|
@@ -125,13 +129,13 @@ module Optimizely
|
|
125
129
|
end
|
126
130
|
@rollout_id_map = generate_key_map(@rollouts, 'id')
|
127
131
|
# split out the experiment key map for rollouts
|
128
|
-
@
|
132
|
+
@rollout_experiment_id_map = {}
|
129
133
|
@rollout_id_map.each_value do |rollout|
|
130
134
|
exps = rollout.fetch('experiments')
|
131
|
-
@
|
135
|
+
@rollout_experiment_id_map = @rollout_experiment_id_map.merge(generate_key_map(exps, 'id'))
|
132
136
|
end
|
133
|
-
@all_experiments = @
|
134
|
-
@all_experiments.each do |
|
137
|
+
@all_experiments = @experiment_id_map.merge(@rollout_experiment_id_map)
|
138
|
+
@all_experiments.each do |id, exp|
|
135
139
|
variations = exp.fetch('variations')
|
136
140
|
variations.each do |variation|
|
137
141
|
variation_id = variation['id']
|
@@ -141,8 +145,10 @@ module Optimizely
|
|
141
145
|
|
142
146
|
@variation_id_to_variable_usage_map[variation_id] = generate_key_map(variation_variables, 'id')
|
143
147
|
end
|
144
|
-
@variation_id_map[key] = generate_key_map(variations, 'id')
|
145
|
-
@variation_key_map[key] = generate_key_map(variations, 'key')
|
148
|
+
@variation_id_map[exp['key']] = generate_key_map(variations, 'id')
|
149
|
+
@variation_key_map[exp['key']] = generate_key_map(variations, 'key')
|
150
|
+
@variation_id_map_by_experiment_id[id] = generate_key_map(variations, 'id')
|
151
|
+
@variation_key_map_by_experiment_id[id] = generate_key_map(variations, 'key')
|
146
152
|
end
|
147
153
|
@feature_flag_key_map = generate_key_map(@feature_flags, 'key')
|
148
154
|
@experiment_feature_map = {}
|
@@ -209,6 +215,21 @@ module Optimizely
|
|
209
215
|
nil
|
210
216
|
end
|
211
217
|
|
218
|
+
def get_experiment_from_id(experiment_id)
|
219
|
+
# Retrieves experiment ID for a given key
|
220
|
+
#
|
221
|
+
# experiment_id - String id representing the experiment
|
222
|
+
#
|
223
|
+
# Returns Experiment or nil if not found
|
224
|
+
|
225
|
+
experiment = @experiment_id_map[experiment_id]
|
226
|
+
return experiment if experiment
|
227
|
+
|
228
|
+
@logger.log Logger::ERROR, "Experiment id '#{experiment_id}' is not in datafile."
|
229
|
+
@error_handler.handle_error InvalidExperimentError
|
230
|
+
nil
|
231
|
+
end
|
232
|
+
|
212
233
|
def get_experiment_key(experiment_id)
|
213
234
|
# Retrieves experiment key for a given ID.
|
214
235
|
#
|
@@ -277,6 +298,52 @@ module Optimizely
|
|
277
298
|
nil
|
278
299
|
end
|
279
300
|
|
301
|
+
def get_variation_from_id_by_experiment_id(experiment_id, variation_id)
|
302
|
+
# Get variation given experiment ID and variation ID
|
303
|
+
#
|
304
|
+
# experiment_id - ID representing parent experiment of variation
|
305
|
+
# variation_id - ID of the variation
|
306
|
+
#
|
307
|
+
# Returns the variation or nil if not found
|
308
|
+
|
309
|
+
variation_id_map_by_experiment_id = @variation_id_map_by_experiment_id[experiment_id]
|
310
|
+
if variation_id_map_by_experiment_id
|
311
|
+
variation = variation_id_map_by_experiment_id[variation_id]
|
312
|
+
return variation if variation
|
313
|
+
|
314
|
+
@logger.log Logger::ERROR, "Variation id '#{variation_id}' is not in datafile."
|
315
|
+
@error_handler.handle_error InvalidVariationError
|
316
|
+
return nil
|
317
|
+
end
|
318
|
+
|
319
|
+
@logger.log Logger::ERROR, "Experiment id '#{experiment_id}' is not in datafile."
|
320
|
+
@error_handler.handle_error InvalidExperimentError
|
321
|
+
nil
|
322
|
+
end
|
323
|
+
|
324
|
+
def get_variation_id_from_key_by_experiment_id(experiment_id, variation_key)
|
325
|
+
# Get variation given experiment ID and variation key
|
326
|
+
#
|
327
|
+
# experiment_id - ID representing parent experiment of variation
|
328
|
+
# variation_key - Key of the variation
|
329
|
+
#
|
330
|
+
# Returns the variation or nil if not found
|
331
|
+
|
332
|
+
variation_key_map = @variation_key_map_by_experiment_id[experiment_id]
|
333
|
+
if variation_key_map
|
334
|
+
variation = variation_key_map[variation_key]
|
335
|
+
return variation['id'] if variation
|
336
|
+
|
337
|
+
@logger.log Logger::ERROR, "Variation key '#{variation_key}' is not in datafile."
|
338
|
+
@error_handler.handle_error InvalidVariationError
|
339
|
+
return nil
|
340
|
+
end
|
341
|
+
|
342
|
+
@logger.log Logger::ERROR, "Experiment id '#{experiment_id}' is not in datafile."
|
343
|
+
@error_handler.handle_error InvalidExperimentError
|
344
|
+
nil
|
345
|
+
end
|
346
|
+
|
280
347
|
def get_variation_id_from_key(experiment_key, variation_key)
|
281
348
|
# Get variation ID given experiment key and variation key
|
282
349
|
#
|
@@ -300,17 +367,17 @@ module Optimizely
|
|
300
367
|
nil
|
301
368
|
end
|
302
369
|
|
303
|
-
def get_whitelisted_variations(
|
304
|
-
# Retrieves whitelisted variations for a given experiment
|
370
|
+
def get_whitelisted_variations(experiment_id)
|
371
|
+
# Retrieves whitelisted variations for a given experiment id
|
305
372
|
#
|
306
|
-
#
|
373
|
+
# experiment_id - String id representing the experiment
|
307
374
|
#
|
308
375
|
# Returns whitelisted variations for the experiment or nil
|
309
376
|
|
310
|
-
experiment = @
|
377
|
+
experiment = @experiment_id_map[experiment_id]
|
311
378
|
return experiment['forcedVariations'] if experiment
|
312
379
|
|
313
|
-
@logger.log Logger::ERROR, "Experiment
|
380
|
+
@logger.log Logger::ERROR, "Experiment ID '#{experiment_id}' is not in datafile."
|
314
381
|
@error_handler.handle_error InvalidExperimentError
|
315
382
|
end
|
316
383
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#
|
4
|
-
# Copyright 2017-
|
4
|
+
# Copyright 2017-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.
|
@@ -52,11 +52,11 @@ module Optimizely
|
|
52
52
|
@forced_variation_map = {}
|
53
53
|
end
|
54
54
|
|
55
|
-
def get_variation(project_config,
|
55
|
+
def get_variation(project_config, experiment_id, user_id, attributes = nil, decide_options = [])
|
56
56
|
# Determines variation into which user will be bucketed.
|
57
57
|
#
|
58
58
|
# project_config - project_config - Instance of ProjectConfig
|
59
|
-
#
|
59
|
+
# experiment_id - Experiment for which visitor variation needs to be determined
|
60
60
|
# user_id - String ID for user
|
61
61
|
# attributes - Hash representing user attributes
|
62
62
|
#
|
@@ -68,10 +68,10 @@ module Optimizely
|
|
68
68
|
bucketing_id, bucketing_id_reasons = get_bucketing_id(user_id, attributes)
|
69
69
|
decide_reasons.push(*bucketing_id_reasons)
|
70
70
|
# Check to make sure experiment is active
|
71
|
-
experiment = project_config.
|
71
|
+
experiment = project_config.get_experiment_from_id(experiment_id)
|
72
72
|
return nil, decide_reasons if experiment.nil?
|
73
73
|
|
74
|
-
|
74
|
+
experiment_key = experiment['key']
|
75
75
|
unless project_config.experiment_running?(experiment)
|
76
76
|
message = "Experiment '#{experiment_key}' is not running."
|
77
77
|
@logger.log(Logger::INFO, message)
|
@@ -80,12 +80,12 @@ module Optimizely
|
|
80
80
|
end
|
81
81
|
|
82
82
|
# Check if a forced variation is set for the user
|
83
|
-
forced_variation, reasons_received = get_forced_variation(project_config,
|
83
|
+
forced_variation, reasons_received = get_forced_variation(project_config, experiment['key'], user_id)
|
84
84
|
decide_reasons.push(*reasons_received)
|
85
85
|
return forced_variation['id'], decide_reasons if forced_variation
|
86
86
|
|
87
87
|
# Check if user is in a white-listed variation
|
88
|
-
whitelisted_variation_id, reasons_received = get_whitelisted_variation_id(project_config,
|
88
|
+
whitelisted_variation_id, reasons_received = get_whitelisted_variation_id(project_config, experiment_id, user_id)
|
89
89
|
decide_reasons.push(*reasons_received)
|
90
90
|
return whitelisted_variation_id, decide_reasons if whitelisted_variation_id
|
91
91
|
|
@@ -122,7 +122,7 @@ module Optimizely
|
|
122
122
|
message = ''
|
123
123
|
if variation_id
|
124
124
|
variation_key = variation['key']
|
125
|
-
message = "User '#{user_id}' is in variation '#{variation_key}' of experiment '#{
|
125
|
+
message = "User '#{user_id}' is in variation '#{variation_key}' of experiment '#{experiment_id}'."
|
126
126
|
else
|
127
127
|
message = "User '#{user_id}' is in no variation."
|
128
128
|
end
|
@@ -186,13 +186,13 @@ module Optimizely
|
|
186
186
|
return nil, decide_reasons
|
187
187
|
end
|
188
188
|
|
189
|
-
|
190
|
-
variation_id, reasons_received = get_variation(project_config,
|
189
|
+
experiment_id = experiment['id']
|
190
|
+
variation_id, reasons_received = get_variation(project_config, experiment_id, user_id, attributes, decide_options)
|
191
191
|
decide_reasons.push(*reasons_received)
|
192
192
|
|
193
193
|
next unless variation_id
|
194
194
|
|
195
|
-
variation = project_config.
|
195
|
+
variation = project_config.get_variation_from_id_by_experiment_id(experiment_id, variation_id)
|
196
196
|
|
197
197
|
return Decision.new(experiment, variation, DECISION_SOURCES['FEATURE_TEST']), decide_reasons
|
198
198
|
end
|
@@ -315,7 +315,7 @@ module Optimizely
|
|
315
315
|
return true
|
316
316
|
end
|
317
317
|
|
318
|
-
variation_id = project_config.
|
318
|
+
variation_id = project_config.get_variation_id_from_key_by_experiment_id(experiment_id, variation_key)
|
319
319
|
|
320
320
|
# check if the variation exists in the datafile
|
321
321
|
unless variation_id
|
@@ -334,7 +334,7 @@ module Optimizely
|
|
334
334
|
# Gets the forced variation for the given user and experiment.
|
335
335
|
#
|
336
336
|
# project_config - Instance of ProjectConfig
|
337
|
-
# experiment_key - String
|
337
|
+
# experiment_key - String key for experiment
|
338
338
|
# user_id - String ID for user
|
339
339
|
#
|
340
340
|
# Returns Variation The variation which the given user and experiment should be forced into
|
@@ -354,7 +354,7 @@ module Optimizely
|
|
354
354
|
return nil, decide_reasons if experiment_id.nil? || experiment_id.empty?
|
355
355
|
|
356
356
|
unless experiment_to_variation_map.key? experiment_id
|
357
|
-
message = "No experiment '#{
|
357
|
+
message = "No experiment '#{experiment_id}' mapped to user '#{user_id}' in the forced variation map."
|
358
358
|
@logger.log(Logger::DEBUG, message)
|
359
359
|
decide_reasons.push(message)
|
360
360
|
return nil, decide_reasons
|
@@ -362,14 +362,14 @@ module Optimizely
|
|
362
362
|
|
363
363
|
variation_id = experiment_to_variation_map[experiment_id]
|
364
364
|
variation_key = ''
|
365
|
-
variation = project_config.
|
365
|
+
variation = project_config.get_variation_from_id_by_experiment_id(experiment_id, variation_id)
|
366
366
|
variation_key = variation['key'] if variation
|
367
367
|
|
368
368
|
# check if the variation exists in the datafile
|
369
369
|
# this case is logged in get_variation_from_id
|
370
370
|
return nil, decide_reasons if variation_key.empty?
|
371
371
|
|
372
|
-
message = "Variation '#{variation_key}' is mapped to experiment '#{
|
372
|
+
message = "Variation '#{variation_key}' is mapped to experiment '#{experiment_id}' and user '#{user_id}' in the forced variation map"
|
373
373
|
@logger.log(Logger::DEBUG, message)
|
374
374
|
decide_reasons.push(message)
|
375
375
|
|
@@ -378,7 +378,7 @@ module Optimizely
|
|
378
378
|
|
379
379
|
private
|
380
380
|
|
381
|
-
def get_whitelisted_variation_id(project_config,
|
381
|
+
def get_whitelisted_variation_id(project_config, experiment_id, user_id)
|
382
382
|
# Determine if a user is whitelisted into a variation for the given experiment and return the ID of that variation
|
383
383
|
#
|
384
384
|
# project_config - project_config - Instance of ProjectConfig
|
@@ -387,7 +387,7 @@ module Optimizely
|
|
387
387
|
#
|
388
388
|
# Returns variation ID into which user_id is whitelisted (nil if no variation)
|
389
389
|
|
390
|
-
whitelisted_variations = project_config.get_whitelisted_variations(
|
390
|
+
whitelisted_variations = project_config.get_whitelisted_variations(experiment_id)
|
391
391
|
|
392
392
|
return nil, nil unless whitelisted_variations
|
393
393
|
|
@@ -395,7 +395,7 @@ module Optimizely
|
|
395
395
|
|
396
396
|
return nil, nil unless whitelisted_variation_key
|
397
397
|
|
398
|
-
whitelisted_variation_id = project_config.
|
398
|
+
whitelisted_variation_id = project_config.get_variation_id_from_key_by_experiment_id(experiment_id, whitelisted_variation_key)
|
399
399
|
|
400
400
|
unless whitelisted_variation_id
|
401
401
|
message = "User '#{user_id}' is whitelisted into variation '#{whitelisted_variation_key}', which is not in the datafile."
|
@@ -403,7 +403,7 @@ module Optimizely
|
|
403
403
|
return nil, message
|
404
404
|
end
|
405
405
|
|
406
|
-
message = "User '#{user_id}' is whitelisted into variation '#{whitelisted_variation_key}' of experiment '#{
|
406
|
+
message = "User '#{user_id}' is whitelisted into variation '#{whitelisted_variation_key}' of experiment '#{experiment_id}'."
|
407
407
|
@logger.log(Logger::INFO, message)
|
408
408
|
|
409
409
|
[whitelisted_variation_id, message]
|
@@ -54,6 +54,8 @@ module Optimizely
|
|
54
54
|
|
55
55
|
def get_experiment_from_key(experiment_key); end
|
56
56
|
|
57
|
+
def get_experiment_from_id(experiment_id); end
|
58
|
+
|
57
59
|
def get_experiment_key(experiment_id); end
|
58
60
|
|
59
61
|
def get_event_from_key(event_key); end
|
@@ -62,9 +64,13 @@ module Optimizely
|
|
62
64
|
|
63
65
|
def get_variation_from_id(experiment_key, variation_id); end
|
64
66
|
|
67
|
+
def get_variation_from_id_by_experiment_id(experiment_id, variation_id); end
|
68
|
+
|
69
|
+
def get_variation_id_from_key_by_experiment_id(experiment_id, variation_key); end
|
70
|
+
|
65
71
|
def get_variation_id_from_key(experiment_key, variation_key); end
|
66
72
|
|
67
|
-
def get_whitelisted_variations(
|
73
|
+
def get_whitelisted_variations(experiment_id); end
|
68
74
|
|
69
75
|
def get_attribute_id(attribute_key); end
|
70
76
|
|
data/lib/optimizely/version.rb
CHANGED
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.8.
|
4
|
+
version: 3.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Optimizely
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-02
|
11
|
+
date: 2021-08-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -200,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
200
200
|
- !ruby/object:Gem::Version
|
201
201
|
version: '0'
|
202
202
|
requirements: []
|
203
|
-
rubygems_version: 3.0.
|
203
|
+
rubygems_version: 3.0.1
|
204
204
|
signing_key:
|
205
205
|
specification_version: 4
|
206
206
|
summary: Ruby SDK for Optimizely's testing framework
|