optimizely-sdk 4.0.1 → 5.0.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.
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
  - - ">="