optimizely-sdk 5.0.0.pre.beta → 5.0.1

Sign up to get free protection for your applications and to get access to all the features.
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