optimizely-sdk 3.8.1 → 3.9.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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3502b43c8fae064fda3e1b237786a0285103d4ce9383a9d64cfc7b34f3f8c849
|
4
|
+
data.tar.gz: 9b843fc3a7999e640f329812aeeb8e26474b5b85f29d27c0647ba7c3685cb73f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a244307de60cf4a7e9b4e90bd0282e071e310701c09b4314a5f011f9f97a1f638205dc9e3de59611c247315314bfd58a0521690bbc3fa876575f3ef8fa917306
|
7
|
+
data.tar.gz: b68df42eef86c3a4e1fd22f2b1b4cd3060df4ade0c9125862443164735778a16415af958a4002fba7adcdf078d1552a5ffef446bac22e7a269a5984445d1fd50
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019-
|
3
|
+
# Copyright 2019-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.
|
@@ -38,6 +38,8 @@ module Optimizely
|
|
38
38
|
attr_reader :anonymize_ip
|
39
39
|
attr_reader :bot_filtering
|
40
40
|
attr_reader :revision
|
41
|
+
attr_reader :sdk_key
|
42
|
+
attr_reader :environment_key
|
41
43
|
attr_reader :rollouts
|
42
44
|
attr_reader :version
|
43
45
|
attr_reader :send_flag_decisions
|
@@ -85,6 +87,8 @@ module Optimizely
|
|
85
87
|
@anonymize_ip = config.key?('anonymizeIP') ? config['anonymizeIP'] : false
|
86
88
|
@bot_filtering = config['botFiltering']
|
87
89
|
@revision = config['revision']
|
90
|
+
@sdk_key = config.fetch('sdkKey', '')
|
91
|
+
@environment_key = config.fetch('environmentKey', '')
|
88
92
|
@rollouts = config.fetch('rollouts', [])
|
89
93
|
@send_flag_decisions = config.fetch('sendFlagDecisions', false)
|
90
94
|
|
@@ -478,6 +482,16 @@ module Optimizely
|
|
478
482
|
@experiment_feature_map.key?(experiment_id)
|
479
483
|
end
|
480
484
|
|
485
|
+
def rollout_experiment?(experiment_id)
|
486
|
+
# Determines if given experiment is a rollout test.
|
487
|
+
#
|
488
|
+
# experiment_id - String experiment ID
|
489
|
+
#
|
490
|
+
# Returns true if experiment belongs to any rollout,
|
491
|
+
# false otherwise.
|
492
|
+
@rollout_experiment_id_map.key?(experiment_id)
|
493
|
+
end
|
494
|
+
|
481
495
|
private
|
482
496
|
|
483
497
|
def generate_key_map(array, key)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019-
|
3
|
+
# Copyright 2019-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.
|
@@ -16,53 +16,109 @@
|
|
16
16
|
#
|
17
17
|
|
18
18
|
module Optimizely
|
19
|
+
require 'json'
|
19
20
|
class OptimizelyConfig
|
21
|
+
include Optimizely::ConditionTreeEvaluator
|
20
22
|
def initialize(project_config)
|
21
23
|
@project_config = project_config
|
24
|
+
@rollouts = @project_config.rollouts
|
25
|
+
@audiences = []
|
26
|
+
audience_id_lookup_dict = {}
|
27
|
+
|
28
|
+
@project_config.typed_audiences.each do |typed_audience|
|
29
|
+
@audiences.push(
|
30
|
+
'id' => typed_audience['id'],
|
31
|
+
'name' => typed_audience['name'],
|
32
|
+
'conditions' => typed_audience['conditions'].to_json
|
33
|
+
)
|
34
|
+
audience_id_lookup_dict[typed_audience['id']] = typed_audience['id']
|
35
|
+
end
|
36
|
+
|
37
|
+
@project_config.audiences.each do |audience|
|
38
|
+
next unless !audience_id_lookup_dict.key?(audience['id']) && (audience['id'] != '$opt_dummy_audience')
|
39
|
+
|
40
|
+
@audiences.push(
|
41
|
+
'id' => audience['id'],
|
42
|
+
'name' => audience['name'],
|
43
|
+
'conditions' => audience['conditions']
|
44
|
+
)
|
45
|
+
end
|
22
46
|
end
|
23
47
|
|
24
48
|
def config
|
25
49
|
experiments_map_object = experiments_map
|
26
|
-
features_map = get_features_map(
|
27
|
-
{
|
50
|
+
features_map = get_features_map(experiments_id_map)
|
51
|
+
config = {
|
52
|
+
'sdkKey' => @project_config.sdk_key,
|
28
53
|
'datafile' => @project_config.datafile,
|
54
|
+
# This experimentsMap is for experiments of legacy projects only.
|
55
|
+
# For flag projects, experiment keys are not guaranteed to be unique
|
56
|
+
# across multiple flags, so this map may not include all experiments
|
57
|
+
# when keys conflict. Use experimentRules and deliveryRules instead.
|
29
58
|
'experimentsMap' => experiments_map_object,
|
30
59
|
'featuresMap' => features_map,
|
31
|
-
'revision' => @project_config.revision
|
60
|
+
'revision' => @project_config.revision,
|
61
|
+
'attributes' => get_attributes_list(@project_config.attributes),
|
62
|
+
'audiences' => @audiences,
|
63
|
+
'events' => get_events_list(@project_config.events),
|
64
|
+
'environmentKey' => @project_config.environment_key
|
32
65
|
}
|
66
|
+
config
|
33
67
|
end
|
34
68
|
|
35
69
|
private
|
36
70
|
|
37
|
-
def
|
38
|
-
feature_variables_map =
|
39
|
-
|
40
|
-
end
|
71
|
+
def experiments_id_map
|
72
|
+
feature_variables_map = feature_variable_map
|
73
|
+
audiences_id_map = audiences_map
|
41
74
|
@project_config.experiments.reduce({}) do |experiments_map, experiment|
|
75
|
+
feature_id = @project_config.experiment_feature_map.fetch(experiment['id'], []).first
|
42
76
|
experiments_map.update(
|
43
|
-
experiment['
|
77
|
+
experiment['id'] => {
|
44
78
|
'id' => experiment['id'],
|
45
79
|
'key' => experiment['key'],
|
46
|
-
'variationsMap' =>
|
47
|
-
|
48
|
-
'id' => variation['id'],
|
49
|
-
'key' => variation['key'],
|
50
|
-
'variablesMap' => get_merged_variables_map(variation, experiment['id'], feature_variables_map)
|
51
|
-
}
|
52
|
-
variation_object['featureEnabled'] = variation['featureEnabled'] if @project_config.feature_experiment?(experiment['id'])
|
53
|
-
variations_map.update(variation['key'] => variation_object)
|
54
|
-
end
|
80
|
+
'variationsMap' => get_variation_map(feature_id, experiment, feature_variables_map),
|
81
|
+
'audiences' => replace_ids_with_names(experiment.fetch('audienceConditions', []), audiences_id_map) || ''
|
55
82
|
}
|
56
83
|
)
|
57
84
|
end
|
58
85
|
end
|
59
86
|
|
87
|
+
def audiences_map
|
88
|
+
@audiences.reduce({}) do |audiences_map, optly_audience|
|
89
|
+
audiences_map.update(optly_audience['id'] => optly_audience['name'])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def experiments_map
|
94
|
+
experiments_id_map.values.reduce({}) do |experiments_key_map, experiment|
|
95
|
+
experiments_key_map.update(experiment['key'] => experiment)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def feature_variable_map
|
100
|
+
@project_config.feature_flags.reduce({}) do |result_map, feature|
|
101
|
+
result_map.update(feature['id'] => feature['variables'])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def get_variation_map(feature_id, experiment, feature_variables_map)
|
106
|
+
experiment['variations'].reduce({}) do |variations_map, variation|
|
107
|
+
variation_object = {
|
108
|
+
'id' => variation['id'],
|
109
|
+
'key' => variation['key'],
|
110
|
+
'featureEnabled' => variation['featureEnabled'],
|
111
|
+
'variablesMap' => get_merged_variables_map(variation, feature_id, feature_variables_map)
|
112
|
+
}
|
113
|
+
variations_map.update(variation['key'] => variation_object)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
60
117
|
# Merges feature key and type from feature variables to variation variables.
|
61
|
-
def get_merged_variables_map(variation,
|
62
|
-
|
63
|
-
return {} unless feature_ids
|
118
|
+
def get_merged_variables_map(variation, feature_id, feature_variables_map)
|
119
|
+
return {} unless feature_id
|
64
120
|
|
65
|
-
|
121
|
+
feature_variables = feature_variables_map[feature_id]
|
66
122
|
# temporary variation variables map to get values to merge.
|
67
123
|
temp_variables_id_map = {}
|
68
124
|
if variation['variables']
|
@@ -75,7 +131,7 @@ module Optimizely
|
|
75
131
|
)
|
76
132
|
end
|
77
133
|
end
|
78
|
-
|
134
|
+
feature_variables.reduce({}) do |variables_map, feature_variable|
|
79
135
|
variation_variable = temp_variables_id_map[feature_variable['id']]
|
80
136
|
variable_value = variation['featureEnabled'] && variation_variable ? variation_variable['value'] : feature_variable['defaultValue']
|
81
137
|
variables_map.update(
|
@@ -91,13 +147,15 @@ module Optimizely
|
|
91
147
|
|
92
148
|
def get_features_map(all_experiments_map)
|
93
149
|
@project_config.feature_flags.reduce({}) do |features_map, feature|
|
150
|
+
delivery_rules = get_delivery_rules(@rollouts, feature['rolloutId'], feature['id'])
|
94
151
|
features_map.update(
|
95
152
|
feature['key'] => {
|
96
153
|
'id' => feature['id'],
|
97
154
|
'key' => feature['key'],
|
155
|
+
# This experimentsMap is deprecated. Use experimentRules and deliveryRules instead.
|
98
156
|
'experimentsMap' => feature['experimentIds'].reduce({}) do |experiments_map, experiment_id|
|
99
157
|
experiment_key = @project_config.experiment_id_map[experiment_id]['key']
|
100
|
-
experiments_map.update(experiment_key =>
|
158
|
+
experiments_map.update(experiment_key => experiments_id_map[experiment_id])
|
101
159
|
end,
|
102
160
|
'variablesMap' => feature['variables'].reduce({}) do |variables, variable|
|
103
161
|
variables.update(
|
@@ -108,10 +166,107 @@ module Optimizely
|
|
108
166
|
'value' => variable['defaultValue']
|
109
167
|
}
|
110
168
|
)
|
111
|
-
end
|
169
|
+
end,
|
170
|
+
'experimentRules' => feature['experimentIds'].reduce([]) do |experiments_map, experiment_id|
|
171
|
+
experiments_map.push(all_experiments_map[experiment_id])
|
172
|
+
end,
|
173
|
+
'deliveryRules' => delivery_rules
|
112
174
|
}
|
113
175
|
)
|
114
176
|
end
|
115
177
|
end
|
178
|
+
|
179
|
+
def get_attributes_list(attributes)
|
180
|
+
attributes.map do |attribute|
|
181
|
+
{
|
182
|
+
'id' => attribute['id'],
|
183
|
+
'key' => attribute['key']
|
184
|
+
}
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def get_events_list(events)
|
189
|
+
events.map do |event|
|
190
|
+
{
|
191
|
+
'id' => event['id'],
|
192
|
+
'key' => event['key'],
|
193
|
+
'experimentIds' => event['experimentIds']
|
194
|
+
}
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def lookup_name_from_id(audience_id, audiences_map)
|
199
|
+
audiences_map[audience_id] || audience_id
|
200
|
+
end
|
201
|
+
|
202
|
+
def stringify_conditions(conditions, audiences_map)
|
203
|
+
operand = 'OR'
|
204
|
+
conditions_str = ''
|
205
|
+
length = conditions.length()
|
206
|
+
return '' if length.zero?
|
207
|
+
return '"' + lookup_name_from_id(conditions[0], audiences_map) + '"' if length == 1 && !OPERATORS.include?(conditions[0])
|
208
|
+
|
209
|
+
# Edge cases for lengths 0, 1 or 2
|
210
|
+
if length == 2 && OPERATORS.include?(conditions[0]) && !conditions[1].is_a?(Array) && !OPERATORS.include?(conditions[1])
|
211
|
+
return '"' + lookup_name_from_id(conditions[1], audiences_map) + '"' if conditions[0] != 'not'
|
212
|
+
|
213
|
+
return conditions[0].upcase + ' "' + lookup_name_from_id(conditions[1], audiences_map) + '"'
|
214
|
+
|
215
|
+
end
|
216
|
+
if length > 1
|
217
|
+
(0..length - 1).each do |n|
|
218
|
+
# Operand is handled here and made Upper Case
|
219
|
+
if OPERATORS.include?(conditions[n])
|
220
|
+
operand = conditions[n].upcase
|
221
|
+
# Check if element is a list or not
|
222
|
+
elsif conditions[n].is_a?(Array)
|
223
|
+
# Check if at the end or not to determine where to add the operand
|
224
|
+
# Recursive call to call stringify on embedded list
|
225
|
+
conditions_str += if n + 1 < length
|
226
|
+
'(' + stringify_conditions(conditions[n], audiences_map) + ') '
|
227
|
+
else
|
228
|
+
operand + ' (' + stringify_conditions(conditions[n], audiences_map) + ')'
|
229
|
+
end
|
230
|
+
# If the item is not a list, we process as an audience ID and retrieve the name
|
231
|
+
else
|
232
|
+
audience_name = lookup_name_from_id(conditions[n], audiences_map)
|
233
|
+
unless audience_name.nil?
|
234
|
+
# Below handles all cases for one ID or greater
|
235
|
+
conditions_str += if n + 1 < length - 1
|
236
|
+
'"' + audience_name + '" ' + operand + ' '
|
237
|
+
elsif n + 1 == length
|
238
|
+
operand + ' "' + audience_name + '"'
|
239
|
+
else
|
240
|
+
'"' + audience_name + '" '
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
conditions_str || ''
|
247
|
+
end
|
248
|
+
|
249
|
+
def replace_ids_with_names(conditions, audiences_map)
|
250
|
+
!conditions.empty? ? stringify_conditions(conditions, audiences_map) : ''
|
251
|
+
end
|
252
|
+
|
253
|
+
def get_delivery_rules(rollouts, rollout_id, feature_id)
|
254
|
+
audiences_id_map = audiences_map
|
255
|
+
feature_variables_map = feature_variable_map
|
256
|
+
rollout = rollouts.select { |selected_rollout| selected_rollout['id'] == rollout_id }
|
257
|
+
if rollout.any?
|
258
|
+
rollout = rollout[0]
|
259
|
+
experiments = rollout['experiments']
|
260
|
+
return experiments.map do |experiment|
|
261
|
+
{
|
262
|
+
'id' => experiment['id'],
|
263
|
+
'key' => experiment['key'],
|
264
|
+
'variationsMap' => get_variation_map(feature_id, experiment, feature_variables_map),
|
265
|
+
'audiences' => replace_ids_with_names(experiment.fetch('audienceConditions', []), audiences_id_map) || ''
|
266
|
+
}
|
267
|
+
end
|
268
|
+
end
|
269
|
+
[]
|
270
|
+
end
|
116
271
|
end
|
117
272
|
end
|
@@ -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,6 +46,10 @@ module Optimizely
|
|
46
46
|
|
47
47
|
def revision; end
|
48
48
|
|
49
|
+
def sdk_key; end
|
50
|
+
|
51
|
+
def environment_key; end
|
52
|
+
|
49
53
|
def send_flag_decisions; end
|
50
54
|
|
51
55
|
def rollouts; end
|
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.
|
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: 2021-
|
11
|
+
date: 2021-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|