optimizely-sdk 4.0.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/lib/optimizely/audience.rb +7 -7
  4. data/lib/optimizely/bucketer.rb +2 -2
  5. data/lib/optimizely/config/datafile_project_config.rb +58 -39
  6. data/lib/optimizely/config_manager/http_project_config_manager.rb +20 -10
  7. data/lib/optimizely/config_manager/project_config_manager.rb +2 -1
  8. data/lib/optimizely/config_manager/static_project_config_manager.rb +5 -3
  9. data/lib/optimizely/event/event_factory.rb +2 -2
  10. data/lib/optimizely/event_builder.rb +13 -13
  11. data/lib/optimizely/event_dispatcher.rb +2 -4
  12. data/lib/optimizely/exceptions.rb +69 -11
  13. data/lib/optimizely/helpers/constants.rb +45 -1
  14. data/lib/optimizely/helpers/http_utils.rb +3 -0
  15. data/lib/optimizely/helpers/sdk_settings.rb +61 -0
  16. data/lib/optimizely/helpers/validator.rb +54 -1
  17. data/lib/optimizely/notification_center_registry.rb +71 -0
  18. data/lib/optimizely/odp/lru_cache.rb +114 -0
  19. data/lib/optimizely/odp/odp_config.rb +102 -0
  20. data/lib/optimizely/odp/odp_event.rb +75 -0
  21. data/lib/optimizely/odp/odp_event_api_manager.rb +70 -0
  22. data/lib/optimizely/odp/odp_event_manager.rb +286 -0
  23. data/lib/optimizely/odp/odp_manager.rb +159 -0
  24. data/lib/optimizely/odp/odp_segment_api_manager.rb +122 -0
  25. data/lib/optimizely/odp/odp_segment_manager.rb +97 -0
  26. data/lib/optimizely/optimizely_config.rb +4 -2
  27. data/lib/optimizely/optimizely_factory.rb +17 -14
  28. data/lib/optimizely/optimizely_user_context.rb +40 -6
  29. data/lib/optimizely/user_condition_evaluator.rb +1 -1
  30. data/lib/optimizely/version.rb +2 -2
  31. data/lib/optimizely.rb +155 -23
  32. metadata +15 -5
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #
4
- # Copyright 2019, 2022, Optimizely and contributors
4
+ # Copyright 2019, 2022-2023, 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.
@@ -103,7 +103,7 @@ module Optimizely
103
103
  )
104
104
 
105
105
  Optimizely::Project.new(
106
- datafile, nil, logger, error_handler, nil, nil, sdk_key, config_manager, notification_center
106
+ datafile: datafile, logger: logger, error_handler: error_handler, sdk_key: sdk_key, config_manager: config_manager, notification_center: notification_center
107
107
  )
108
108
  end
109
109
 
@@ -111,7 +111,7 @@ module Optimizely
111
111
  #
112
112
  # @param config_manager - Required ConfigManagerInterface Responds to 'config' method.
113
113
  def self.default_instance_with_config_manager(config_manager)
114
- Optimizely::Project.new(nil, nil, nil, nil, nil, nil, nil, config_manager)
114
+ Optimizely::Project.new(config_manager: config_manager)
115
115
  end
116
116
 
117
117
  # Returns a new optimizely instance.
@@ -126,6 +126,7 @@ module Optimizely
126
126
  # @param user_profile_service - Optional UserProfileServiceInterface Provides methods to store and retreive user profiles.
127
127
  # @param config_manager - Optional ConfigManagerInterface Responds to 'config' method.
128
128
  # @param notification_center - Optional Instance of NotificationCenter.
129
+ # @param settings: Optional instance of OptimizelySdkSettings for sdk configuration.
129
130
  #
130
131
  # if @max_event_batch_size and @max_event_flush_interval are nil then default batchsize and flush_interval
131
132
  # will be used to setup batchEventProcessor.
@@ -138,7 +139,8 @@ module Optimizely
138
139
  skip_json_validation = false, # rubocop:disable Style/OptionalBooleanParameter
139
140
  user_profile_service = nil,
140
141
  config_manager = nil,
141
- notification_center = nil
142
+ notification_center = nil,
143
+ settings = nil
142
144
  )
143
145
 
144
146
  error_handler ||= NoOpErrorHandler.new
@@ -165,16 +167,17 @@ module Optimizely
165
167
  )
166
168
 
167
169
  Optimizely::Project.new(
168
- datafile,
169
- event_dispatcher,
170
- logger,
171
- error_handler,
172
- skip_json_validation,
173
- user_profile_service,
174
- sdk_key,
175
- config_manager,
176
- notification_center,
177
- event_processor
170
+ datafile: datafile,
171
+ event_dispatcher: event_dispatcher,
172
+ logger: logger,
173
+ error_handler: error_handler,
174
+ skip_json_validation: skip_json_validation,
175
+ user_profile_service: user_profile_service,
176
+ sdk_key: sdk_key,
177
+ config_manager: config_manager,
178
+ notification_center: notification_center,
179
+ event_processor: event_processor,
180
+ settings: settings
178
181
  )
179
182
  end
180
183
  end
@@ -26,7 +26,7 @@ module Optimizely
26
26
 
27
27
  OptimizelyDecisionContext = Struct.new(:flag_key, :rule_key)
28
28
  OptimizelyForcedDecision = Struct.new(:variation_key)
29
- def initialize(optimizely_client, user_id, user_attributes)
29
+ def initialize(optimizely_client, user_id, user_attributes, identify: true)
30
30
  @attr_mutex = Mutex.new
31
31
  @forced_decision_mutex = Mutex.new
32
32
  @qualified_segment_mutex = Mutex.new
@@ -34,13 +34,15 @@ module Optimizely
34
34
  @user_id = user_id
35
35
  @user_attributes = user_attributes.nil? ? {} : user_attributes.clone
36
36
  @forced_decisions = {}
37
- @qualified_segments = []
37
+ @qualified_segments = nil
38
+
39
+ @optimizely_client&.identify_user(user_id: user_id) if identify
38
40
  end
39
41
 
40
42
  def clone
41
- user_context = OptimizelyUserContext.new(@optimizely_client, @user_id, user_attributes)
43
+ user_context = OptimizelyUserContext.new(@optimizely_client, @user_id, user_attributes, identify: false)
42
44
  @forced_decision_mutex.synchronize { user_context.instance_variable_set('@forced_decisions', @forced_decisions.dup) unless @forced_decisions.empty? }
43
- @qualified_segment_mutex.synchronize { user_context.instance_variable_set('@qualified_segments', @qualified_segments.dup) unless @qualified_segments.empty? }
45
+ @qualified_segment_mutex.synchronize { user_context.instance_variable_set('@qualified_segments', @qualified_segments.dup) unless @qualified_segments.nil? }
44
46
  user_context
45
47
  end
46
48
 
@@ -194,11 +196,43 @@ module Optimizely
194
196
  # Checks if user is qualified for the provided segment.
195
197
  #
196
198
  # @param segment - A segment name
199
+ # @return true if qualified.
197
200
 
198
201
  def qualified_for?(segment)
199
- return false if @qualified_segments.empty?
202
+ qualified = false
203
+ @qualified_segment_mutex.synchronize do
204
+ break if @qualified_segments.nil? || @qualified_segments.empty?
205
+
206
+ qualified = @qualified_segments.include?(segment)
207
+ end
208
+ qualified
209
+ end
210
+
211
+ # Fetch all qualified segments for the user context.
212
+ #
213
+ # The segments fetched will be saved in `@qualified_segments` and can be accessed any time.
214
+ #
215
+ # @param options - A set of options for fetching qualified segments (optional).
216
+ # @param block - An optional block to call after segments have been fetched.
217
+ # If a block is provided, segments will be fetched on a separate thread.
218
+ # Block will be called with a boolean indicating if the fetch succeeded.
219
+ # @return If no block is provided, a boolean indicating whether the fetch was successful.
220
+ # Otherwise, returns a thread handle and the status boolean is passed to the block.
200
221
 
201
- @qualified_segment_mutex.synchronize { @qualified_segments.include?(segment) }
222
+ def fetch_qualified_segments(options: [], &block)
223
+ fetch_segments = lambda do |opts, callback|
224
+ segments = @optimizely_client&.fetch_qualified_segments(user_id: @user_id, options: opts)
225
+ self.qualified_segments = segments
226
+ success = !segments.nil?
227
+ callback&.call(success)
228
+ success
229
+ end
230
+
231
+ if block_given?
232
+ Thread.new(options, block, &fetch_segments)
233
+ else
234
+ fetch_segments.call(options, nil)
235
+ end
202
236
  end
203
237
  end
204
238
  end
@@ -331,7 +331,7 @@ module Optimizely
331
331
  end
332
332
 
333
333
  def qualified_evaluator(condition)
334
- # Evaluate the given match condition for the given user qaulified segments.
334
+ # Evaluate the given match condition for the given user qualified segments.
335
335
  # Returns boolean true if condition value is in the user's qualified segments,
336
336
  # false if the condition value is not in the user's qualified segments,
337
337
  # nil if the condition value isn't a string.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #
4
- # Copyright 2016-2019, Optimizely and contributors
4
+ # Copyright 2016-2023, 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.
@@ -17,5 +17,5 @@
17
17
  #
18
18
  module Optimizely
19
19
  CLIENT_ENGINE = 'ruby-sdk'
20
- VERSION = '4.0.1'
20
+ VERSION = '5.0.0'
21
21
  end
data/lib/optimizely.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #
4
- # Copyright 2016-2022, Optimizely and contributors
4
+ # Copyright 2016-2023, 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.
@@ -25,7 +25,7 @@ require_relative 'optimizely/decide/optimizely_decision_message'
25
25
  require_relative 'optimizely/decision_service'
26
26
  require_relative 'optimizely/error_handler'
27
27
  require_relative 'optimizely/event_builder'
28
- require_relative 'optimizely/event/forwarding_event_processor'
28
+ require_relative 'optimizely/event/batch_event_processor'
29
29
  require_relative 'optimizely/event/event_factory'
30
30
  require_relative 'optimizely/event/user_event_factory'
31
31
  require_relative 'optimizely/event_dispatcher'
@@ -36,8 +36,12 @@ require_relative 'optimizely/helpers/validator'
36
36
  require_relative 'optimizely/helpers/variable_type'
37
37
  require_relative 'optimizely/logger'
38
38
  require_relative 'optimizely/notification_center'
39
+ require_relative 'optimizely/notification_center_registry'
39
40
  require_relative 'optimizely/optimizely_config'
40
41
  require_relative 'optimizely/optimizely_user_context'
42
+ require_relative 'optimizely/odp/lru_cache'
43
+ require_relative 'optimizely/odp/odp_manager'
44
+ require_relative 'optimizely/helpers/sdk_settings'
41
45
 
42
46
  module Optimizely
43
47
  class Project
@@ -46,7 +50,7 @@ module Optimizely
46
50
  attr_reader :notification_center
47
51
  # @api no-doc
48
52
  attr_reader :config_manager, :decision_service, :error_handler, :event_dispatcher,
49
- :event_processor, :logger, :stopped
53
+ :event_processor, :logger, :odp_manager, :stopped
50
54
 
51
55
  # Constructor for Projects.
52
56
  #
@@ -62,25 +66,31 @@ module Optimizely
62
66
  # @param config_manager - Optional Responds to 'config' method.
63
67
  # @param notification_center - Optional Instance of NotificationCenter.
64
68
  # @param event_processor - Optional Responds to process.
65
-
66
- def initialize( # rubocop:disable Metrics/ParameterLists
67
- datafile = nil,
68
- event_dispatcher = nil,
69
- logger = nil,
70
- error_handler = nil,
71
- skip_json_validation = false, # rubocop:disable Style/OptionalBooleanParameter
72
- user_profile_service = nil,
73
- sdk_key = nil,
74
- config_manager = nil,
75
- notification_center = nil,
76
- event_processor = nil,
77
- default_decide_options = []
69
+ # @param default_decide_options: Optional default decision options.
70
+ # @param event_processor_options: Optional hash of options to be passed to the default batch event processor.
71
+ # @param settings: Optional instance of OptimizelySdkSettings for sdk configuration.
72
+
73
+ def initialize(
74
+ datafile: nil,
75
+ event_dispatcher: nil,
76
+ logger: nil,
77
+ error_handler: nil,
78
+ skip_json_validation: false,
79
+ user_profile_service: nil,
80
+ sdk_key: nil,
81
+ config_manager: nil,
82
+ notification_center: nil,
83
+ event_processor: nil,
84
+ default_decide_options: [],
85
+ event_processor_options: {},
86
+ settings: nil
78
87
  )
79
88
  @logger = logger || NoOpLogger.new
80
89
  @error_handler = error_handler || NoOpErrorHandler.new
81
90
  @event_dispatcher = event_dispatcher || EventDispatcher.new(logger: @logger, error_handler: @error_handler)
82
91
  @user_profile_service = user_profile_service
83
92
  @default_decide_options = []
93
+ @sdk_settings = settings
84
94
 
85
95
  if default_decide_options.is_a? Array
86
96
  @default_decide_options = default_decide_options.clone
@@ -89,6 +99,11 @@ module Optimizely
89
99
  @default_decide_options = []
90
100
  end
91
101
 
102
+ unless event_processor_options.is_a? Hash
103
+ @logger.log(Logger::DEBUG, 'Provided event processor options is not a hash.')
104
+ event_processor_options = {}
105
+ end
106
+
92
107
  begin
93
108
  validate_instantiation_options
94
109
  rescue InvalidInputError => e
@@ -98,7 +113,7 @@ module Optimizely
98
113
 
99
114
  @notification_center = notification_center.is_a?(Optimizely::NotificationCenter) ? notification_center : NotificationCenter.new(@logger, @error_handler)
100
115
 
101
- @config_manager = if config_manager.respond_to?(:config)
116
+ @config_manager = if config_manager.respond_to?(:config) && config_manager.respond_to?(:sdk_key)
102
117
  config_manager
103
118
  elsif sdk_key
104
119
  HTTPProjectConfigManager.new(
@@ -113,12 +128,20 @@ module Optimizely
113
128
  StaticProjectConfigManager.new(datafile, @logger, @error_handler, skip_json_validation)
114
129
  end
115
130
 
131
+ setup_odp!(@config_manager.sdk_key)
132
+
116
133
  @decision_service = DecisionService.new(@logger, @user_profile_service)
117
134
 
118
135
  @event_processor = if event_processor.respond_to?(:process)
119
136
  event_processor
120
137
  else
121
- ForwardingEventProcessor.new(@event_dispatcher, @logger, @notification_center)
138
+ BatchEventProcessor.new(
139
+ event_dispatcher: @event_dispatcher,
140
+ logger: @logger,
141
+ notification_center: @notification_center,
142
+ batch_size: event_processor_options[:batch_size] || BatchEventProcessor::DEFAULT_BATCH_SIZE,
143
+ flush_interval: event_processor_options[:flush_interval] || BatchEventProcessor::DEFAULT_BATCH_INTERVAL
144
+ )
122
145
  end
123
146
  end
124
147
 
@@ -507,7 +530,7 @@ module Optimizely
507
530
  return false
508
531
  end
509
532
 
510
- user_context = create_user_context(user_id, attributes)
533
+ user_context = OptimizelyUserContext.new(self, user_id, attributes, identify: false)
511
534
  decision, = @decision_service.get_variation_for_feature(config, feature_flag, user_context)
512
535
 
513
536
  feature_enabled = false
@@ -747,7 +770,7 @@ module Optimizely
747
770
  return nil
748
771
  end
749
772
 
750
- user_context = create_user_context(user_id, attributes)
773
+ user_context = OptimizelyUserContext.new(self, user_id, attributes, identify: false)
751
774
  decision, = @decision_service.get_variation_for_feature(config, feature_flag, user_context)
752
775
  variation = decision ? decision['variation'] : nil
753
776
  feature_enabled = variation ? variation['featureEnabled'] : false
@@ -816,6 +839,7 @@ module Optimizely
816
839
  @stopped = true
817
840
  @config_manager.stop! if @config_manager.respond_to?(:stop!)
818
841
  @event_processor.stop! if @event_processor.respond_to?(:stop!)
842
+ @odp_manager.stop!
819
843
  end
820
844
 
821
845
  def get_optimizely_config
@@ -865,8 +889,54 @@ module Optimizely
865
889
  if @config_manager.respond_to?(:optimizely_config)
866
890
  @config_manager.optimizely_config
867
891
  else
868
- OptimizelyConfig.new(project_config).config
892
+ OptimizelyConfig.new(project_config, @logger).config
893
+ end
894
+ end
895
+
896
+ # Send an event to the ODP server.
897
+ #
898
+ # @param action - the event action name. Cannot be nil or empty string.
899
+ # @param identifiers - a hash for identifiers. The caller must provide at least one key-value pair.
900
+ # @param type - the event type (default = "fullstack").
901
+ # @param data - a hash for associated data. The default event data will be added to this data before sending to the ODP server.
902
+
903
+ def send_odp_event(action:, identifiers:, type: Helpers::Constants::ODP_MANAGER_CONFIG[:EVENT_TYPE], data: {})
904
+ unless identifiers.is_a?(Hash) && !identifiers.empty?
905
+ @logger.log(Logger::ERROR, 'ODP events must have at least one key-value pair in identifiers.')
906
+ return
907
+ end
908
+
909
+ unless is_valid
910
+ @logger.log(Logger::ERROR, InvalidProjectConfigError.new('send_odp_event').message)
911
+ return
912
+ end
913
+
914
+ if action.nil? || action.empty?
915
+ @logger.log(Logger::ERROR, Helpers::Constants::ODP_LOGS[:ODP_INVALID_ACTION])
916
+ return
917
+ end
918
+
919
+ type = Helpers::Constants::ODP_MANAGER_CONFIG[:EVENT_TYPE] if type.nil? || type.empty?
920
+
921
+ @odp_manager.send_event(type: type, action: action, identifiers: identifiers, data: data)
922
+ end
923
+
924
+ def identify_user(user_id:)
925
+ unless is_valid
926
+ @logger.log(Logger::ERROR, InvalidProjectConfigError.new('identify_user').message)
927
+ return
869
928
  end
929
+
930
+ @odp_manager.identify_user(user_id: user_id)
931
+ end
932
+
933
+ def fetch_qualified_segments(user_id:, options: [])
934
+ unless is_valid
935
+ @logger.log(Logger::ERROR, InvalidProjectConfigError.new('fetch_qualified_segments').message)
936
+ return
937
+ end
938
+
939
+ @odp_manager.fetch_qualified_segments(user_id: user_id, options: options)
870
940
  end
871
941
 
872
942
  private
@@ -888,7 +958,7 @@ module Optimizely
888
958
 
889
959
  return nil unless user_inputs_valid?(attributes)
890
960
 
891
- user_context = create_user_context(user_id, attributes)
961
+ user_context = OptimizelyUserContext.new(self, user_id, attributes, identify: false)
892
962
  variation_id, = @decision_service.get_variation(config, experiment_id, user_context)
893
963
  variation = config.get_variation_from_id(experiment_key, variation_id) unless variation_id.nil?
894
964
  variation_key = variation['key'] if variation
@@ -955,7 +1025,7 @@ module Optimizely
955
1025
  return nil
956
1026
  end
957
1027
 
958
- user_context = create_user_context(user_id, attributes)
1028
+ user_context = OptimizelyUserContext.new(self, user_id, attributes, identify: false)
959
1029
  decision, = @decision_service.get_variation_for_feature(config, feature_flag, user_context)
960
1030
  variation = decision ? decision['variation'] : nil
961
1031
  feature_enabled = variation ? variation['featureEnabled'] : false
@@ -1126,5 +1196,67 @@ module Optimizely
1126
1196
  def project_config
1127
1197
  @config_manager.config
1128
1198
  end
1199
+
1200
+ def update_odp_config_on_datafile_update
1201
+ # if datafile isn't ready, expects to be called again by the internal notification_center
1202
+ return if @config_manager.respond_to?(:ready?) && !@config_manager.ready?
1203
+
1204
+ config = @config_manager&.config
1205
+ return unless config
1206
+
1207
+ @odp_manager.update_odp_config(config.public_key_for_odp, config.host_for_odp, config.all_segments)
1208
+ end
1209
+
1210
+ def setup_odp!(sdk_key)
1211
+ unless @sdk_settings.is_a? Optimizely::Helpers::OptimizelySdkSettings
1212
+ @logger.log(Logger::DEBUG, 'Provided sdk_settings is not an OptimizelySdkSettings instance.') unless @sdk_settings.nil?
1213
+ @sdk_settings = Optimizely::Helpers::OptimizelySdkSettings.new
1214
+ end
1215
+
1216
+ if !@sdk_settings.odp_segment_manager.nil? && !Helpers::Validator.segment_manager_valid?(@sdk_settings.odp_segment_manager)
1217
+ @logger.log(Logger::ERROR, 'Invalid ODP segment manager, reverting to default.')
1218
+ @sdk_settings.odp_segment_manager = nil
1219
+ end
1220
+
1221
+ if !@sdk_settings.odp_event_manager.nil? && !Helpers::Validator.event_manager_valid?(@sdk_settings.odp_event_manager)
1222
+ @logger.log(Logger::ERROR, 'Invalid ODP event manager, reverting to default.')
1223
+ @sdk_settings.odp_event_manager = nil
1224
+ end
1225
+
1226
+ if !@sdk_settings.odp_segments_cache.nil? && !Helpers::Validator.segments_cache_valid?(@sdk_settings.odp_segments_cache)
1227
+ @logger.log(Logger::ERROR, 'Invalid ODP segments cache, reverting to default.')
1228
+ @sdk_settings.odp_segments_cache = nil
1229
+ end
1230
+
1231
+ # no need to instantiate a cache if a custom cache or segment manager is provided.
1232
+ if !@sdk_settings.odp_disabled && @sdk_settings.odp_segment_manager.nil?
1233
+ @sdk_settings.odp_segments_cache ||= LRUCache.new(
1234
+ @sdk_settings.segments_cache_size,
1235
+ @sdk_settings.segments_cache_timeout_in_secs
1236
+ )
1237
+ end
1238
+
1239
+ @odp_manager = OdpManager.new(
1240
+ disable: @sdk_settings.odp_disabled,
1241
+ segment_manager: @sdk_settings.odp_segment_manager,
1242
+ event_manager: @sdk_settings.odp_event_manager,
1243
+ segments_cache: @sdk_settings.odp_segments_cache,
1244
+ fetch_segments_timeout: @sdk_settings.fetch_segments_timeout,
1245
+ odp_event_timeout: @sdk_settings.odp_event_timeout,
1246
+ odp_flush_interval: @sdk_settings.odp_flush_interval,
1247
+ logger: @logger
1248
+ )
1249
+
1250
+ return if @sdk_settings.odp_disabled
1251
+
1252
+ Optimizely::NotificationCenterRegistry
1253
+ .get_notification_center(sdk_key, @logger)
1254
+ &.add_notification_listener(
1255
+ NotificationCenter::NOTIFICATION_TYPES[:OPTIMIZELY_CONFIG_UPDATE],
1256
+ method(:update_odp_config_on_datafile_update)
1257
+ )
1258
+
1259
+ update_odp_config_on_datafile_update
1260
+ end
1129
1261
  end
1130
1262
  end
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: 4.0.1
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Optimizely
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-13 00:00:00.000000000 Z
11
+ date: 2024-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -98,14 +98,14 @@ dependencies:
98
98
  name: json-schema
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - "~>"
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
103
  version: '2.6'
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - "~>"
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '2.6'
111
111
  - !ruby/object:Gem::Dependency
@@ -169,10 +169,20 @@ files:
169
169
  - lib/optimizely/helpers/event_tag_utils.rb
170
170
  - lib/optimizely/helpers/group.rb
171
171
  - lib/optimizely/helpers/http_utils.rb
172
+ - lib/optimizely/helpers/sdk_settings.rb
172
173
  - lib/optimizely/helpers/validator.rb
173
174
  - lib/optimizely/helpers/variable_type.rb
174
175
  - lib/optimizely/logger.rb
175
176
  - lib/optimizely/notification_center.rb
177
+ - lib/optimizely/notification_center_registry.rb
178
+ - lib/optimizely/odp/lru_cache.rb
179
+ - lib/optimizely/odp/odp_config.rb
180
+ - lib/optimizely/odp/odp_event.rb
181
+ - lib/optimizely/odp/odp_event_api_manager.rb
182
+ - lib/optimizely/odp/odp_event_manager.rb
183
+ - lib/optimizely/odp/odp_manager.rb
184
+ - lib/optimizely/odp/odp_segment_api_manager.rb
185
+ - lib/optimizely/odp/odp_segment_manager.rb
176
186
  - lib/optimizely/optimizely_config.rb
177
187
  - lib/optimizely/optimizely_factory.rb
178
188
  - lib/optimizely/optimizely_user_context.rb
@@ -194,7 +204,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
194
204
  requirements:
195
205
  - - ">="
196
206
  - !ruby/object:Gem::Version
197
- version: '2.7'
207
+ version: '3.0'
198
208
  required_rubygems_version: !ruby/object:Gem::Requirement
199
209
  requirements:
200
210
  - - ">="