optimizely-sdk 5.0.0.pre.beta → 5.0.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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +202 -202
  3. data/lib/optimizely/audience.rb +127 -127
  4. data/lib/optimizely/bucketer.rb +156 -156
  5. data/lib/optimizely/condition_tree_evaluator.rb +123 -123
  6. data/lib/optimizely/config/datafile_project_config.rb +48 -32
  7. data/lib/optimizely/config/proxy_config.rb +34 -34
  8. data/lib/optimizely/config_manager/async_scheduler.rb +95 -95
  9. data/lib/optimizely/config_manager/http_project_config_manager.rb +340 -338
  10. data/lib/optimizely/config_manager/project_config_manager.rb +25 -25
  11. data/lib/optimizely/config_manager/static_project_config_manager.rb +55 -54
  12. data/lib/optimizely/decide/optimizely_decide_option.rb +28 -28
  13. data/lib/optimizely/decide/optimizely_decision.rb +60 -60
  14. data/lib/optimizely/decide/optimizely_decision_message.rb +26 -26
  15. data/lib/optimizely/decision_service.rb +563 -563
  16. data/lib/optimizely/error_handler.rb +39 -39
  17. data/lib/optimizely/event/batch_event_processor.rb +235 -235
  18. data/lib/optimizely/event/entity/conversion_event.rb +44 -44
  19. data/lib/optimizely/event/entity/decision.rb +38 -38
  20. data/lib/optimizely/event/entity/event_batch.rb +86 -86
  21. data/lib/optimizely/event/entity/event_context.rb +50 -50
  22. data/lib/optimizely/event/entity/impression_event.rb +48 -48
  23. data/lib/optimizely/event/entity/snapshot.rb +33 -33
  24. data/lib/optimizely/event/entity/snapshot_event.rb +48 -48
  25. data/lib/optimizely/event/entity/user_event.rb +22 -22
  26. data/lib/optimizely/event/entity/visitor.rb +36 -36
  27. data/lib/optimizely/event/entity/visitor_attribute.rb +38 -38
  28. data/lib/optimizely/event/event_factory.rb +156 -156
  29. data/lib/optimizely/event/event_processor.rb +25 -25
  30. data/lib/optimizely/event/forwarding_event_processor.rb +44 -44
  31. data/lib/optimizely/event/user_event_factory.rb +88 -88
  32. data/lib/optimizely/event_builder.rb +221 -221
  33. data/lib/optimizely/event_dispatcher.rb +69 -69
  34. data/lib/optimizely/exceptions.rb +193 -149
  35. data/lib/optimizely/helpers/constants.rb +459 -459
  36. data/lib/optimizely/helpers/date_time_utils.rb +30 -30
  37. data/lib/optimizely/helpers/event_tag_utils.rb +132 -132
  38. data/lib/optimizely/helpers/group.rb +31 -31
  39. data/lib/optimizely/helpers/http_utils.rb +68 -68
  40. data/lib/optimizely/helpers/sdk_settings.rb +61 -61
  41. data/lib/optimizely/helpers/validator.rb +236 -238
  42. data/lib/optimizely/helpers/variable_type.rb +67 -67
  43. data/lib/optimizely/logger.rb +46 -46
  44. data/lib/optimizely/notification_center.rb +174 -174
  45. data/lib/optimizely/notification_center_registry.rb +71 -71
  46. data/lib/optimizely/odp/lru_cache.rb +114 -114
  47. data/lib/optimizely/odp/odp_config.rb +102 -102
  48. data/lib/optimizely/odp/odp_event.rb +75 -75
  49. data/lib/optimizely/odp/odp_event_api_manager.rb +70 -70
  50. data/lib/optimizely/odp/odp_event_manager.rb +286 -286
  51. data/lib/optimizely/odp/odp_manager.rb +159 -159
  52. data/lib/optimizely/odp/odp_segment_api_manager.rb +122 -122
  53. data/lib/optimizely/odp/odp_segment_manager.rb +97 -97
  54. data/lib/optimizely/optimizely_config.rb +273 -271
  55. data/lib/optimizely/optimizely_factory.rb +184 -186
  56. data/lib/optimizely/optimizely_user_context.rb +238 -238
  57. data/lib/optimizely/params.rb +31 -31
  58. data/lib/optimizely/project_config.rb +99 -99
  59. data/lib/optimizely/semantic_version.rb +166 -166
  60. data/lib/optimizely/user_condition_evaluator.rb +391 -391
  61. data/lib/optimizely/user_profile_service.rb +35 -35
  62. data/lib/optimizely/version.rb +21 -21
  63. data/lib/optimizely.rb +1262 -1262
  64. metadata +12 -10
@@ -1,271 +1,273 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright 2019-2022, Optimizely and contributors
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
- module Optimizely
19
- require 'json'
20
- class OptimizelyConfig
21
- include Optimizely::ConditionTreeEvaluator
22
- def initialize(project_config)
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
46
- end
47
-
48
- def config
49
- experiments_map_object = experiments_map
50
- features_map = get_features_map(experiments_id_map)
51
- {
52
- 'sdkKey' => @project_config.sdk_key,
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.
58
- 'experimentsMap' => experiments_map_object,
59
- 'featuresMap' => features_map,
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
65
- }
66
- end
67
-
68
- private
69
-
70
- def experiments_id_map
71
- feature_variables_map = feature_variable_map
72
- audiences_id_map = audiences_map
73
- @project_config.experiments.reduce({}) do |experiments_map, experiment|
74
- feature_id = @project_config.experiment_feature_map.fetch(experiment['id'], []).first
75
- experiments_map.update(
76
- experiment['id'] => {
77
- 'id' => experiment['id'],
78
- 'key' => experiment['key'],
79
- 'variationsMap' => get_variation_map(feature_id, experiment, feature_variables_map),
80
- 'audiences' => replace_ids_with_names(experiment.fetch('audienceConditions', []), audiences_id_map) || ''
81
- }
82
- )
83
- end
84
- end
85
-
86
- def audiences_map
87
- @audiences.reduce({}) do |audiences_map, optly_audience|
88
- audiences_map.update(optly_audience['id'] => optly_audience['name'])
89
- end
90
- end
91
-
92
- def experiments_map
93
- experiments_id_map.values.reduce({}) do |experiments_key_map, experiment|
94
- experiments_key_map.update(experiment['key'] => experiment)
95
- end
96
- end
97
-
98
- def feature_variable_map
99
- @project_config.feature_flags.reduce({}) do |result_map, feature|
100
- result_map.update(feature['id'] => feature['variables'])
101
- end
102
- end
103
-
104
- def get_variation_map(feature_id, experiment, feature_variables_map)
105
- experiment['variations'].reduce({}) do |variations_map, variation|
106
- variation_object = {
107
- 'id' => variation['id'],
108
- 'key' => variation['key'],
109
- 'featureEnabled' => variation['featureEnabled'],
110
- 'variablesMap' => get_merged_variables_map(variation, feature_id, feature_variables_map)
111
- }
112
- variations_map.update(variation['key'] => variation_object)
113
- end
114
- end
115
-
116
- # Merges feature key and type from feature variables to variation variables.
117
- def get_merged_variables_map(variation, feature_id, feature_variables_map)
118
- return {} unless feature_id
119
-
120
- feature_variables = feature_variables_map[feature_id]
121
- # temporary variation variables map to get values to merge.
122
- temp_variables_id_map = {}
123
- if variation['variables']
124
- temp_variables_id_map = variation['variables'].reduce({}) do |variables_map, variable|
125
- variables_map.update(
126
- variable['id'] => {
127
- 'id' => variable['id'],
128
- 'value' => variable['value']
129
- }
130
- )
131
- end
132
- end
133
- feature_variables.reduce({}) do |variables_map, feature_variable|
134
- variation_variable = temp_variables_id_map[feature_variable['id']]
135
- variable_value = variation['featureEnabled'] && variation_variable ? variation_variable['value'] : feature_variable['defaultValue']
136
- variables_map.update(
137
- feature_variable['key'] => {
138
- 'id' => feature_variable['id'],
139
- 'key' => feature_variable['key'],
140
- 'type' => feature_variable['type'],
141
- 'value' => variable_value
142
- }
143
- )
144
- end
145
- end
146
-
147
- def get_features_map(all_experiments_map)
148
- @project_config.feature_flags.reduce({}) do |features_map, feature|
149
- delivery_rules = get_delivery_rules(@rollouts, feature['rolloutId'], feature['id'])
150
- features_map.update(
151
- feature['key'] => {
152
- 'id' => feature['id'],
153
- 'key' => feature['key'],
154
- # This experimentsMap is deprecated. Use experimentRules and deliveryRules instead.
155
- 'experimentsMap' => feature['experimentIds'].reduce({}) do |experiments_map, experiment_id|
156
- experiment_key = @project_config.experiment_id_map[experiment_id]['key']
157
- experiments_map.update(experiment_key => experiments_id_map[experiment_id])
158
- end,
159
- 'variablesMap' => feature['variables'].reduce({}) do |variables, variable|
160
- variables.update(
161
- variable['key'] => {
162
- 'id' => variable['id'],
163
- 'key' => variable['key'],
164
- 'type' => variable['type'],
165
- 'value' => variable['defaultValue']
166
- }
167
- )
168
- end,
169
- 'experimentRules' => feature['experimentIds'].reduce([]) do |experiments_map, experiment_id|
170
- experiments_map.push(all_experiments_map[experiment_id])
171
- end,
172
- 'deliveryRules' => delivery_rules
173
- }
174
- )
175
- end
176
- end
177
-
178
- def get_attributes_list(attributes)
179
- attributes.map do |attribute|
180
- {
181
- 'id' => attribute['id'],
182
- 'key' => attribute['key']
183
- }
184
- end
185
- end
186
-
187
- def get_events_list(events)
188
- events.map do |event|
189
- {
190
- 'id' => event['id'],
191
- 'key' => event['key'],
192
- 'experimentIds' => event['experimentIds']
193
- }
194
- end
195
- end
196
-
197
- def lookup_name_from_id(audience_id, audiences_map)
198
- audiences_map[audience_id] || audience_id
199
- end
200
-
201
- def stringify_conditions(conditions, audiences_map)
202
- operand = 'OR'
203
- conditions_str = ''
204
- length = conditions.length
205
- return '' if length.zero?
206
- return "\"#{lookup_name_from_id(conditions[0], audiences_map)}\"" if length == 1 && !OPERATORS.include?(conditions[0])
207
-
208
- # Edge cases for lengths 0, 1 or 2
209
- if length == 2 && OPERATORS.include?(conditions[0]) && !conditions[1].is_a?(Array) && !OPERATORS.include?(conditions[1])
210
- return "\"#{lookup_name_from_id(conditions[1], audiences_map)}\"" if conditions[0] != 'not'
211
-
212
- return "#{conditions[0].upcase} \"#{lookup_name_from_id(conditions[1], audiences_map)}\""
213
-
214
- end
215
- if length > 1
216
- (0..length - 1).each do |n|
217
- # Operand is handled here and made Upper Case
218
- if OPERATORS.include?(conditions[n])
219
- operand = conditions[n].upcase
220
- # Check if element is a list or not
221
- elsif conditions[n].is_a?(Array)
222
- # Check if at the end or not to determine where to add the operand
223
- # Recursive call to call stringify on embedded list
224
- conditions_str += if n + 1 < length
225
- "(#{stringify_conditions(conditions[n], audiences_map)}) "
226
- else
227
- "#{operand} (#{stringify_conditions(conditions[n], audiences_map)})"
228
- end
229
- # If the item is not a list, we process as an audience ID and retrieve the name
230
- else
231
- audience_name = lookup_name_from_id(conditions[n], audiences_map)
232
- unless audience_name.nil?
233
- # Below handles all cases for one ID or greater
234
- conditions_str += if n + 1 < length - 1
235
- "\"#{audience_name}\" #{operand} "
236
- elsif n + 1 == length
237
- "#{operand} \"#{audience_name}\""
238
- else
239
- "\"#{audience_name}\" "
240
- end
241
- end
242
- end
243
- end
244
- end
245
- conditions_str || ''
246
- end
247
-
248
- def replace_ids_with_names(conditions, audiences_map)
249
- !conditions.empty? ? stringify_conditions(conditions, audiences_map) : ''
250
- end
251
-
252
- def get_delivery_rules(rollouts, rollout_id, feature_id)
253
- audiences_id_map = audiences_map
254
- feature_variables_map = feature_variable_map
255
- rollout = rollouts.select { |selected_rollout| selected_rollout['id'] == rollout_id }
256
- if rollout.any?
257
- rollout = rollout[0]
258
- experiments = rollout['experiments']
259
- return experiments.map do |experiment|
260
- {
261
- 'id' => experiment['id'],
262
- 'key' => experiment['key'],
263
- 'variationsMap' => get_variation_map(feature_id, experiment, feature_variables_map),
264
- 'audiences' => replace_ids_with_names(experiment.fetch('audienceConditions', []), audiences_id_map) || ''
265
- }
266
- end
267
- end
268
- []
269
- end
270
- end
271
- end
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2019-2022, Optimizely and contributors
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ module Optimizely
19
+ require 'json'
20
+ class OptimizelyConfig
21
+ include Optimizely::ConditionTreeEvaluator
22
+ def initialize(project_config, logger = nil)
23
+ @project_config = project_config
24
+ @logger = logger || NoOpLogger.new
25
+ @rollouts = @project_config.rollouts
26
+ @audiences = []
27
+ audience_id_lookup_dict = {}
28
+
29
+ @project_config.typed_audiences.each do |typed_audience|
30
+ @audiences.push(
31
+ 'id' => typed_audience['id'],
32
+ 'name' => typed_audience['name'],
33
+ 'conditions' => typed_audience['conditions'].to_json
34
+ )
35
+ audience_id_lookup_dict[typed_audience['id']] = typed_audience['id']
36
+ end
37
+
38
+ @project_config.audiences.each do |audience|
39
+ next unless !audience_id_lookup_dict.key?(audience['id']) && (audience['id'] != '$opt_dummy_audience')
40
+
41
+ @audiences.push(
42
+ 'id' => audience['id'],
43
+ 'name' => audience['name'],
44
+ 'conditions' => audience['conditions']
45
+ )
46
+ end
47
+ end
48
+
49
+ def config
50
+ experiments_map_object = experiments_map
51
+ features_map = get_features_map(experiments_id_map)
52
+ {
53
+ 'sdkKey' => @project_config.sdk_key,
54
+ 'datafile' => @project_config.datafile,
55
+ # This experimentsMap is for experiments of legacy projects only.
56
+ # For flag projects, experiment keys are not guaranteed to be unique
57
+ # across multiple flags, so this map may not include all experiments
58
+ # when keys conflict. Use experimentRules and deliveryRules instead.
59
+ 'experimentsMap' => experiments_map_object,
60
+ 'featuresMap' => features_map,
61
+ 'revision' => @project_config.revision,
62
+ 'attributes' => get_attributes_list(@project_config.attributes),
63
+ 'audiences' => @audiences,
64
+ 'events' => get_events_list(@project_config.events),
65
+ 'environmentKey' => @project_config.environment_key
66
+ }
67
+ end
68
+
69
+ private
70
+
71
+ def experiments_id_map
72
+ feature_variables_map = feature_variable_map
73
+ audiences_id_map = audiences_map
74
+ @project_config.experiments.reduce({}) do |experiments_map, experiment|
75
+ feature_id = @project_config.experiment_feature_map.fetch(experiment['id'], []).first
76
+ experiments_map.update(
77
+ experiment['id'] => {
78
+ 'id' => experiment['id'],
79
+ 'key' => experiment['key'],
80
+ 'variationsMap' => get_variation_map(feature_id, experiment, feature_variables_map),
81
+ 'audiences' => replace_ids_with_names(experiment.fetch('audienceConditions', []), audiences_id_map) || ''
82
+ }
83
+ )
84
+ end
85
+ end
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
+ @logger.log(Logger::WARN, "Duplicate experiment keys found in datafile: #{experiment['key']}") if experiments_key_map.key? experiment['key']
96
+ experiments_key_map.update(experiment['key'] => experiment)
97
+ end
98
+ end
99
+
100
+ def feature_variable_map
101
+ @project_config.feature_flags.reduce({}) do |result_map, feature|
102
+ result_map.update(feature['id'] => feature['variables'])
103
+ end
104
+ end
105
+
106
+ def get_variation_map(feature_id, experiment, feature_variables_map)
107
+ experiment['variations'].reduce({}) do |variations_map, variation|
108
+ variation_object = {
109
+ 'id' => variation['id'],
110
+ 'key' => variation['key'],
111
+ 'featureEnabled' => variation['featureEnabled'],
112
+ 'variablesMap' => get_merged_variables_map(variation, feature_id, feature_variables_map)
113
+ }
114
+ variations_map.update(variation['key'] => variation_object)
115
+ end
116
+ end
117
+
118
+ # Merges feature key and type from feature variables to variation variables.
119
+ def get_merged_variables_map(variation, feature_id, feature_variables_map)
120
+ return {} unless feature_id
121
+
122
+ feature_variables = feature_variables_map[feature_id]
123
+ # temporary variation variables map to get values to merge.
124
+ temp_variables_id_map = {}
125
+ if variation['variables']
126
+ temp_variables_id_map = variation['variables'].reduce({}) do |variables_map, variable|
127
+ variables_map.update(
128
+ variable['id'] => {
129
+ 'id' => variable['id'],
130
+ 'value' => variable['value']
131
+ }
132
+ )
133
+ end
134
+ end
135
+ feature_variables.reduce({}) do |variables_map, feature_variable|
136
+ variation_variable = temp_variables_id_map[feature_variable['id']]
137
+ variable_value = variation['featureEnabled'] && variation_variable ? variation_variable['value'] : feature_variable['defaultValue']
138
+ variables_map.update(
139
+ feature_variable['key'] => {
140
+ 'id' => feature_variable['id'],
141
+ 'key' => feature_variable['key'],
142
+ 'type' => feature_variable['type'],
143
+ 'value' => variable_value
144
+ }
145
+ )
146
+ end
147
+ end
148
+
149
+ def get_features_map(all_experiments_map)
150
+ @project_config.feature_flags.reduce({}) do |features_map, feature|
151
+ delivery_rules = get_delivery_rules(@rollouts, feature['rolloutId'], feature['id'])
152
+ features_map.update(
153
+ feature['key'] => {
154
+ 'id' => feature['id'],
155
+ 'key' => feature['key'],
156
+ # This experimentsMap is deprecated. Use experimentRules and deliveryRules instead.
157
+ 'experimentsMap' => feature['experimentIds'].reduce({}) do |experiments_map, experiment_id|
158
+ experiment_key = @project_config.experiment_id_map[experiment_id]['key']
159
+ experiments_map.update(experiment_key => experiments_id_map[experiment_id])
160
+ end,
161
+ 'variablesMap' => feature['variables'].reduce({}) do |variables, variable|
162
+ variables.update(
163
+ variable['key'] => {
164
+ 'id' => variable['id'],
165
+ 'key' => variable['key'],
166
+ 'type' => variable['type'],
167
+ 'value' => variable['defaultValue']
168
+ }
169
+ )
170
+ end,
171
+ 'experimentRules' => feature['experimentIds'].reduce([]) do |experiments_map, experiment_id|
172
+ experiments_map.push(all_experiments_map[experiment_id])
173
+ end,
174
+ 'deliveryRules' => delivery_rules
175
+ }
176
+ )
177
+ end
178
+ end
179
+
180
+ def get_attributes_list(attributes)
181
+ attributes.map do |attribute|
182
+ {
183
+ 'id' => attribute['id'],
184
+ 'key' => attribute['key']
185
+ }
186
+ end
187
+ end
188
+
189
+ def get_events_list(events)
190
+ events.map do |event|
191
+ {
192
+ 'id' => event['id'],
193
+ 'key' => event['key'],
194
+ 'experimentIds' => event['experimentIds']
195
+ }
196
+ end
197
+ end
198
+
199
+ def lookup_name_from_id(audience_id, audiences_map)
200
+ audiences_map[audience_id] || audience_id
201
+ end
202
+
203
+ def stringify_conditions(conditions, audiences_map)
204
+ operand = 'OR'
205
+ conditions_str = ''
206
+ length = conditions.length
207
+ return '' if length.zero?
208
+ return "\"#{lookup_name_from_id(conditions[0], audiences_map)}\"" if length == 1 && !OPERATORS.include?(conditions[0])
209
+
210
+ # Edge cases for lengths 0, 1 or 2
211
+ if length == 2 && OPERATORS.include?(conditions[0]) && !conditions[1].is_a?(Array) && !OPERATORS.include?(conditions[1])
212
+ return "\"#{lookup_name_from_id(conditions[1], audiences_map)}\"" if conditions[0] != 'not'
213
+
214
+ return "#{conditions[0].upcase} \"#{lookup_name_from_id(conditions[1], audiences_map)}\""
215
+
216
+ end
217
+ if length > 1
218
+ (0..length - 1).each do |n|
219
+ # Operand is handled here and made Upper Case
220
+ if OPERATORS.include?(conditions[n])
221
+ operand = conditions[n].upcase
222
+ # Check if element is a list or not
223
+ elsif conditions[n].is_a?(Array)
224
+ # Check if at the end or not to determine where to add the operand
225
+ # Recursive call to call stringify on embedded list
226
+ conditions_str += if n + 1 < length
227
+ "(#{stringify_conditions(conditions[n], audiences_map)}) "
228
+ else
229
+ "#{operand} (#{stringify_conditions(conditions[n], audiences_map)})"
230
+ end
231
+ # If the item is not a list, we process as an audience ID and retrieve the name
232
+ else
233
+ audience_name = lookup_name_from_id(conditions[n], audiences_map)
234
+ unless audience_name.nil?
235
+ # Below handles all cases for one ID or greater
236
+ conditions_str += if n + 1 < length - 1
237
+ "\"#{audience_name}\" #{operand} "
238
+ elsif n + 1 == length
239
+ "#{operand} \"#{audience_name}\""
240
+ else
241
+ "\"#{audience_name}\" "
242
+ end
243
+ end
244
+ end
245
+ end
246
+ end
247
+ conditions_str || ''
248
+ end
249
+
250
+ def replace_ids_with_names(conditions, audiences_map)
251
+ !conditions.empty? ? stringify_conditions(conditions, audiences_map) : ''
252
+ end
253
+
254
+ def get_delivery_rules(rollouts, rollout_id, feature_id)
255
+ audiences_id_map = audiences_map
256
+ feature_variables_map = feature_variable_map
257
+ rollout = rollouts.select { |selected_rollout| selected_rollout['id'] == rollout_id }
258
+ if rollout.any?
259
+ rollout = rollout[0]
260
+ experiments = rollout['experiments']
261
+ return experiments.map do |experiment|
262
+ {
263
+ 'id' => experiment['id'],
264
+ 'key' => experiment['key'],
265
+ 'variationsMap' => get_variation_map(feature_id, experiment, feature_variables_map),
266
+ 'audiences' => replace_ids_with_names(experiment.fetch('audienceConditions', []), audiences_id_map) || ''
267
+ }
268
+ end
269
+ end
270
+ []
271
+ end
272
+ end
273
+ end