optimizely-sdk 3.3.1 → 3.3.2.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/lib/optimizely.rb +2 -2
- data/lib/optimizely/config_manager/async_scheduler.rb +2 -2
- data/lib/optimizely/config_manager/http_project_config_manager.rb +5 -3
- data/lib/optimizely/event/batch_event_processor.rb +40 -39
- data/lib/optimizely/event_dispatcher.rb +38 -14
- data/lib/optimizely/exceptions.rb +7 -0
- data/lib/optimizely/notification_center.rb +13 -5
- data/lib/optimizely/version.rb +1 -1
- metadata +5 -5
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: 4b941180fbc22ae8f59eff475967cb6f130c4845e2a47324c3e18252b4a35685
         | 
| 4 | 
            +
              data.tar.gz: 560e8ce82a288fb98c6d088264b0df6ff1cd4b0d3aba162d72ab1541a9fe76ee
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 66dbbf2dcbfe72ba85201b552f5d8a1e10c33eb109c18e51a56e46582754fcc21ad86d7d0ce487e032e872e135c2671269451c788447c527d8a2b8498fd1421e
         | 
| 7 | 
            +
              data.tar.gz: 3ca3f728b5c3c20355e192f26a50913194cebf4fe3a446cddd94a72daecc9c0f50d74af7c36863cfcde5dd02e93baea2d14fb0137a6b0e5e3481d135ff323ae0
         | 
    
        data/lib/optimizely.rb
    CHANGED
    
    | @@ -70,7 +70,7 @@ module Optimizely | |
| 70 70 | 
             
                )
         | 
| 71 71 | 
             
                  @logger = logger || NoOpLogger.new
         | 
| 72 72 | 
             
                  @error_handler = error_handler || NoOpErrorHandler.new
         | 
| 73 | 
            -
                  @event_dispatcher = event_dispatcher || EventDispatcher.new
         | 
| 73 | 
            +
                  @event_dispatcher = event_dispatcher || EventDispatcher.new(logger: @logger, error_handler: @error_handler)
         | 
| 74 74 | 
             
                  @user_profile_service = user_profile_service
         | 
| 75 75 |  | 
| 76 76 | 
             
                  begin
         | 
| @@ -701,7 +701,7 @@ module Optimizely | |
| 701 701 |  | 
| 702 702 | 
             
                  return if Helpers::Validator.event_dispatcher_valid?(@event_dispatcher)
         | 
| 703 703 |  | 
| 704 | 
            -
                  @event_dispatcher = EventDispatcher.new
         | 
| 704 | 
            +
                  @event_dispatcher = EventDispatcher.new(logger: @logger, error_handler: @error_handler)
         | 
| 705 705 | 
             
                  raise InvalidInputError, 'event_dispatcher'
         | 
| 706 706 | 
             
                end
         | 
| 707 707 |  | 
| @@ -75,10 +75,10 @@ module Optimizely | |
| 75 75 | 
             
                  loop do
         | 
| 76 76 | 
             
                    begin
         | 
| 77 77 | 
             
                      callback.call
         | 
| 78 | 
            -
                    rescue
         | 
| 78 | 
            +
                    rescue StandardError => e
         | 
| 79 79 | 
             
                      @logger.log(
         | 
| 80 80 | 
             
                        Logger::ERROR,
         | 
| 81 | 
            -
                         | 
| 81 | 
            +
                        "Something went wrong when executing passed callback. #{e.message}"
         | 
| 82 82 | 
             
                      )
         | 
| 83 83 | 
             
                      stop!
         | 
| 84 84 | 
             
                    end
         | 
| @@ -70,14 +70,16 @@ module Optimizely | |
| 70 70 | 
             
                  @blocking_timeout = nil
         | 
| 71 71 | 
             
                  blocking_timeout(blocking_timeout)
         | 
| 72 72 | 
             
                  @last_modified = nil
         | 
| 73 | 
            -
                  @async_scheduler = AsyncScheduler.new(method(:fetch_datafile_config), @polling_interval, auto_update, @logger)
         | 
| 74 | 
            -
                  @async_scheduler.start! if start_by_default == true
         | 
| 75 | 
            -
                  @stopped = false
         | 
| 76 73 | 
             
                  @skip_json_validation = skip_json_validation
         | 
| 77 74 | 
             
                  @notification_center = notification_center.is_a?(Optimizely::NotificationCenter) ? notification_center : NotificationCenter.new(@logger, @error_handler)
         | 
| 78 75 | 
             
                  @config = datafile.nil? ? nil : DatafileProjectConfig.create(datafile, @logger, @error_handler, @skip_json_validation)
         | 
| 79 76 | 
             
                  @mutex = Mutex.new
         | 
| 80 77 | 
             
                  @resource = ConditionVariable.new
         | 
| 78 | 
            +
                  @async_scheduler = AsyncScheduler.new(method(:fetch_datafile_config), @polling_interval, auto_update, @logger)
         | 
| 79 | 
            +
                  # Start async scheduler in the end to avoid race condition where scheduler executes
         | 
| 80 | 
            +
                  # callback which makes use of variables not yet initialized by the main thread.
         | 
| 81 | 
            +
                  @async_scheduler.start! if start_by_default == true
         | 
| 82 | 
            +
                  @stopped = false
         | 
| 81 83 | 
             
                end
         | 
| 82 84 |  | 
| 83 85 | 
             
                def ready?
         | 
| @@ -20,7 +20,7 @@ require_relative '../helpers/validator' | |
| 20 20 | 
             
            module Optimizely
         | 
| 21 21 | 
             
              class BatchEventProcessor < EventProcessor
         | 
| 22 22 | 
             
                # BatchEventProcessor is a batched implementation of the Interface EventProcessor.
         | 
| 23 | 
            -
                # Events passed to the BatchEventProcessor are immediately added to  | 
| 23 | 
            +
                # Events passed to the BatchEventProcessor are immediately added to an EventQueue.
         | 
| 24 24 | 
             
                # The BatchEventProcessor maintains a single consumer thread that pulls events off of
         | 
| 25 25 | 
             
                # the BlockingQueue and buffers them for either a configured batch size or for a
         | 
| 26 26 | 
             
                # maximum duration before the resulting LogEvent is sent to the NotificationCenter.
         | 
| @@ -30,13 +30,15 @@ module Optimizely | |
| 30 30 | 
             
                DEFAULT_BATCH_SIZE = 10
         | 
| 31 31 | 
             
                DEFAULT_BATCH_INTERVAL = 30_000 # interval in milliseconds
         | 
| 32 32 | 
             
                DEFAULT_QUEUE_CAPACITY = 1000
         | 
| 33 | 
            +
                DEFAULT_TIMEOUT_INTERVAL = 5 # interval in seconds
         | 
| 34 | 
            +
                MAX_NIL_COUNT = 3
         | 
| 33 35 |  | 
| 34 36 | 
             
                FLUSH_SIGNAL = 'FLUSH_SIGNAL'
         | 
| 35 37 | 
             
                SHUTDOWN_SIGNAL = 'SHUTDOWN_SIGNAL'
         | 
| 36 38 |  | 
| 37 39 | 
             
                def initialize(
         | 
| 38 40 | 
             
                  event_queue: SizedQueue.new(DEFAULT_QUEUE_CAPACITY),
         | 
| 39 | 
            -
                  event_dispatcher:  | 
| 41 | 
            +
                  event_dispatcher: nil,
         | 
| 40 42 | 
             
                  batch_size: DEFAULT_BATCH_SIZE,
         | 
| 41 43 | 
             
                  flush_interval: DEFAULT_BATCH_INTERVAL,
         | 
| 42 44 | 
             
                  logger: NoOpLogger.new,
         | 
| @@ -44,7 +46,7 @@ module Optimizely | |
| 44 46 | 
             
                )
         | 
| 45 47 | 
             
                  @event_queue = event_queue
         | 
| 46 48 | 
             
                  @logger = logger
         | 
| 47 | 
            -
                  @event_dispatcher = event_dispatcher
         | 
| 49 | 
            +
                  @event_dispatcher = event_dispatcher || EventDispatcher.new(logger: @logger)
         | 
| 48 50 | 
             
                  @batch_size = if (batch_size.is_a? Integer) && positive_number?(batch_size)
         | 
| 49 51 | 
             
                                  batch_size
         | 
| 50 52 | 
             
                                else
         | 
| @@ -58,8 +60,6 @@ module Optimizely | |
| 58 60 | 
             
                                      DEFAULT_BATCH_INTERVAL
         | 
| 59 61 | 
             
                                    end
         | 
| 60 62 | 
             
                  @notification_center = notification_center
         | 
| 61 | 
            -
                  @mutex = Mutex.new
         | 
| 62 | 
            -
                  @received = ConditionVariable.new
         | 
| 63 63 | 
             
                  @current_batch = []
         | 
| 64 64 | 
             
                  @started = false
         | 
| 65 65 | 
             
                  start!
         | 
| @@ -71,15 +71,13 @@ module Optimizely | |
| 71 71 | 
             
                    return
         | 
| 72 72 | 
             
                  end
         | 
| 73 73 | 
             
                  @flushing_interval_deadline = Helpers::DateTimeUtils.create_timestamp + @flush_interval
         | 
| 74 | 
            +
                  @logger.log(Logger::INFO, 'Starting scheduler.')
         | 
| 74 75 | 
             
                  @thread = Thread.new { run }
         | 
| 75 76 | 
             
                  @started = true
         | 
| 76 77 | 
             
                end
         | 
| 77 78 |  | 
| 78 79 | 
             
                def flush
         | 
| 79 | 
            -
                  @ | 
| 80 | 
            -
                    @event_queue << FLUSH_SIGNAL
         | 
| 81 | 
            -
                    @received.signal
         | 
| 82 | 
            -
                  end
         | 
| 80 | 
            +
                  @event_queue << FLUSH_SIGNAL
         | 
| 83 81 | 
             
                end
         | 
| 84 82 |  | 
| 85 83 | 
             
                def process(user_event)
         | 
| @@ -90,56 +88,54 @@ module Optimizely | |
| 90 88 | 
             
                    return
         | 
| 91 89 | 
             
                  end
         | 
| 92 90 |  | 
| 93 | 
            -
                   | 
| 94 | 
            -
                     | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
                     | 
| 98 | 
            -
                      @logger.log(Logger::WARN, 'Payload not accepted by the queue.')
         | 
| 99 | 
            -
                      return
         | 
| 100 | 
            -
                    end
         | 
| 91 | 
            +
                  begin
         | 
| 92 | 
            +
                    @event_queue.push(user_event, true)
         | 
| 93 | 
            +
                  rescue Exception
         | 
| 94 | 
            +
                    @logger.log(Logger::WARN, 'Payload not accepted by the queue.')
         | 
| 95 | 
            +
                    return
         | 
| 101 96 | 
             
                  end
         | 
| 102 97 | 
             
                end
         | 
| 103 98 |  | 
| 104 99 | 
             
                def stop!
         | 
| 105 100 | 
             
                  return unless @started
         | 
| 106 101 |  | 
| 107 | 
            -
                  @ | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 110 | 
            -
                  end
         | 
| 111 | 
            -
             | 
| 102 | 
            +
                  @logger.log(Logger::INFO, 'Stopping scheduler.')
         | 
| 103 | 
            +
                  @event_queue << SHUTDOWN_SIGNAL
         | 
| 104 | 
            +
                  @thread.join(DEFAULT_TIMEOUT_INTERVAL)
         | 
| 112 105 | 
             
                  @started = false
         | 
| 113 | 
            -
                  @logger.log(Logger::WARN, 'Stopping scheduler.')
         | 
| 114 | 
            -
                  @thread.exit
         | 
| 115 106 | 
             
                end
         | 
| 116 107 |  | 
| 117 108 | 
             
                private
         | 
| 118 109 |  | 
| 119 110 | 
             
                def run
         | 
| 111 | 
            +
                  # if we receive a number of item nils that reach MAX_NIL_COUNT,
         | 
| 112 | 
            +
                  # then we hang on the pop via setting use_pop to false
         | 
| 113 | 
            +
                  @nil_count = 0
         | 
| 114 | 
            +
                  # hang on pop if true
         | 
| 115 | 
            +
                  @use_pop = false
         | 
| 120 116 | 
             
                  loop do
         | 
| 121 | 
            -
                    if Helpers::DateTimeUtils.create_timestamp  | 
| 122 | 
            -
                      @logger.log(
         | 
| 123 | 
            -
                        Logger::DEBUG,
         | 
| 124 | 
            -
                        'Deadline exceeded flushing current batch.'
         | 
| 125 | 
            -
                      )
         | 
| 117 | 
            +
                    if Helpers::DateTimeUtils.create_timestamp >= @flushing_interval_deadline
         | 
| 118 | 
            +
                      @logger.log(Logger::DEBUG, 'Deadline exceeded flushing current batch.')
         | 
| 126 119 | 
             
                      flush_queue!
         | 
| 120 | 
            +
                      @flushing_interval_deadline = Helpers::DateTimeUtils.create_timestamp + @flush_interval
         | 
| 121 | 
            +
                      @use_pop = true if @nil_count > MAX_NIL_COUNT
         | 
| 127 122 | 
             
                    end
         | 
| 128 123 |  | 
| 129 | 
            -
                    item =  | 
| 130 | 
            -
             | 
| 131 | 
            -
                    @mutex.synchronize do
         | 
| 132 | 
            -
                      @received.wait(@mutex, 0.05)
         | 
| 133 | 
            -
                      item = @event_queue.pop if @event_queue.length.positive?
         | 
| 134 | 
            -
                    end
         | 
| 124 | 
            +
                    item = @event_queue.pop if @event_queue.length.positive? || @use_pop
         | 
| 135 125 |  | 
| 136 126 | 
             
                    if item.nil?
         | 
| 137 | 
            -
                       | 
| 127 | 
            +
                      # when nil count is greater than MAX_NIL_COUNT, we hang on the pop until there is an item available.
         | 
| 128 | 
            +
                      # this avoids to much spinning of the loop.
         | 
| 129 | 
            +
                      @nil_count += 1
         | 
| 138 130 | 
             
                      next
         | 
| 139 131 | 
             
                    end
         | 
| 140 132 |  | 
| 133 | 
            +
                    # reset nil_count and use_pop if we have received an item.
         | 
| 134 | 
            +
                    @nil_count = 0
         | 
| 135 | 
            +
                    @use_pop = false
         | 
| 136 | 
            +
             | 
| 141 137 | 
             
                    if item == SHUTDOWN_SIGNAL
         | 
| 142 | 
            -
                      @logger.log(Logger:: | 
| 138 | 
            +
                      @logger.log(Logger::DEBUG, 'Received shutdown signal.')
         | 
| 143 139 | 
             
                      break
         | 
| 144 140 | 
             
                    end
         | 
| 145 141 |  | 
| @@ -152,7 +148,7 @@ module Optimizely | |
| 152 148 | 
             
                    add_to_batch(item) if item.is_a? Optimizely::UserEvent
         | 
| 153 149 | 
             
                  end
         | 
| 154 150 | 
             
                rescue SignalException
         | 
| 155 | 
            -
                  @logger.log(Logger:: | 
| 151 | 
            +
                  @logger.log(Logger::ERROR, 'Interrupted while processing buffer.')
         | 
| 156 152 | 
             
                rescue Exception => e
         | 
| 157 153 | 
             
                  @logger.log(Logger::ERROR, "Uncaught exception processing buffer. #{e.message}")
         | 
| 158 154 | 
             
                ensure
         | 
| @@ -168,6 +164,11 @@ module Optimizely | |
| 168 164 |  | 
| 169 165 | 
             
                  log_event = Optimizely::EventFactory.create_log_event(@current_batch, @logger)
         | 
| 170 166 | 
             
                  begin
         | 
| 167 | 
            +
                    @logger.log(
         | 
| 168 | 
            +
                      Logger::INFO,
         | 
| 169 | 
            +
                      'Flushing Queue.'
         | 
| 170 | 
            +
                    )
         | 
| 171 | 
            +
             | 
| 171 172 | 
             
                    @event_dispatcher.dispatch_event(log_event)
         | 
| 172 173 | 
             
                    @notification_center&.send_notifications(
         | 
| 173 174 | 
             
                      NotificationCenter::NOTIFICATION_TYPES[:LOG_EVENT],
         | 
| @@ -192,7 +193,7 @@ module Optimizely | |
| 192 193 | 
             
                  @current_batch << user_event
         | 
| 193 194 | 
             
                  return unless @current_batch.length >= @batch_size
         | 
| 194 195 |  | 
| 195 | 
            -
                  @logger.log(Logger::DEBUG, 'Flushing on max batch size | 
| 196 | 
            +
                  @logger.log(Logger::DEBUG, 'Flushing on max batch size.')
         | 
| 196 197 | 
             
                  flush_queue!
         | 
| 197 198 | 
             
                end
         | 
| 198 199 |  | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            #
         | 
| 4 | 
            -
            #    Copyright 2016-2017, Optimizely and contributors
         | 
| 4 | 
            +
            #    Copyright 2016-2017, 2019, 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.
         | 
| @@ -15,6 +15,8 @@ | |
| 15 15 | 
             
            #    See the License for the specific language governing permissions and
         | 
| 16 16 | 
             
            #    limitations under the License.
         | 
| 17 17 | 
             
            #
         | 
| 18 | 
            +
            require_relative 'exceptions'
         | 
| 19 | 
            +
             | 
| 18 20 | 
             
            require 'httparty'
         | 
| 19 21 |  | 
| 20 22 | 
             
            module Optimizely
         | 
| @@ -28,26 +30,48 @@ module Optimizely | |
| 28 30 | 
             
                # @api constants
         | 
| 29 31 | 
             
                REQUEST_TIMEOUT = 10
         | 
| 30 32 |  | 
| 33 | 
            +
                def initialize(logger: nil, error_handler: nil)
         | 
| 34 | 
            +
                  @logger = logger || NoOpLogger.new
         | 
| 35 | 
            +
                  @error_handler = error_handler || NoOpErrorHandler.new
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 31 38 | 
             
                # Dispatch the event being represented by the Event object.
         | 
| 32 39 | 
             
                #
         | 
| 33 40 | 
             
                # @param event - Event object
         | 
| 34 41 | 
             
                def dispatch_event(event)
         | 
| 35 42 | 
             
                  if event.http_verb == :get
         | 
| 36 | 
            -
                     | 
| 37 | 
            -
             | 
| 38 | 
            -
                    rescue Timeout::Error => e
         | 
| 39 | 
            -
                      return e
         | 
| 40 | 
            -
                    end
         | 
| 43 | 
            +
                    response = HTTParty.get(event.url, headers: event.headers, query: event.params, timeout: REQUEST_TIMEOUT)
         | 
| 44 | 
            +
             | 
| 41 45 | 
             
                  elsif event.http_verb == :post
         | 
| 42 | 
            -
                     | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
                                    timeout: REQUEST_TIMEOUT)
         | 
| 47 | 
            -
                    rescue Timeout::Error => e
         | 
| 48 | 
            -
                      return e
         | 
| 49 | 
            -
                    end
         | 
| 46 | 
            +
                    response = HTTParty.post(event.url,
         | 
| 47 | 
            +
                                             body: event.params.to_json,
         | 
| 48 | 
            +
                                             headers: event.headers,
         | 
| 49 | 
            +
                                             timeout: REQUEST_TIMEOUT)
         | 
| 50 50 | 
             
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  error_msg = "Event failed to dispatch with response code: #{response.code}"
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  case response.code
         | 
| 55 | 
            +
                  when 400...500
         | 
| 56 | 
            +
                    @logger.log(Logger::ERROR, error_msg)
         | 
| 57 | 
            +
                    @error_handler.handle_error(HTTPCallError.new("HTTP Client Error: #{response.code}"))
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  when 500...600
         | 
| 60 | 
            +
                    @logger.log(Logger::ERROR, error_msg)
         | 
| 61 | 
            +
                    @error_handler.handle_error(HTTPCallError.new("HTTP Server Error: #{response.code}"))
         | 
| 62 | 
            +
                  else
         | 
| 63 | 
            +
                    @logger.log(Logger::DEBUG, 'event successfully sent with response code ' + response.code.to_s)
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
                rescue Timeout::Error => e
         | 
| 66 | 
            +
                  @logger.log(Logger::ERROR, "Request Timed out. Error: #{e}")
         | 
| 67 | 
            +
                  @error_handler.handle_error(e)
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  # Returning Timeout error to retain existing behavior.
         | 
| 70 | 
            +
                  e
         | 
| 71 | 
            +
                rescue StandardError => e
         | 
| 72 | 
            +
                  @logger.log(Logger::ERROR, "Event failed to dispatch. Error: #{e}")
         | 
| 73 | 
            +
                  @error_handler.handle_error(e)
         | 
| 74 | 
            +
                  nil
         | 
| 51 75 | 
             
                end
         | 
| 52 76 | 
             
              end
         | 
| 53 77 | 
             
            end
         | 
| @@ -18,6 +18,13 @@ | |
| 18 18 | 
             
            module Optimizely
         | 
| 19 19 | 
             
              class Error < StandardError; end
         | 
| 20 20 |  | 
| 21 | 
            +
              class HTTPCallError < Error
         | 
| 22 | 
            +
                # Raised when a 4xx or 5xx response code is recieved.
         | 
| 23 | 
            +
                def initialize(msg = 'HTTP call resulted in a response with an error code.')
         | 
| 24 | 
            +
                  super
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 21 28 | 
             
              class InvalidAudienceError < Error
         | 
| 22 29 | 
             
                # Raised when an invalid audience is provided
         | 
| 23 30 |  | 
| @@ -39,20 +39,28 @@ module Optimizely | |
| 39 39 |  | 
| 40 40 | 
             
                # Adds notification callback to the notification center
         | 
| 41 41 | 
             
                #
         | 
| 42 | 
            -
                # @param notification_type - | 
| 43 | 
            -
                # @param notification_callback - | 
| 42 | 
            +
                # @param notification_type - One of the constants in NOTIFICATION_TYPES
         | 
| 43 | 
            +
                # @param notification_callback [lambda, Method, Callable] (default: block) - Called when the event is sent
         | 
| 44 | 
            +
                # @yield Block to be used as callback if callback omitted.
         | 
| 44 45 | 
             
                #
         | 
| 45 46 | 
             
                # @return [notification ID] Used to remove the notification
         | 
| 46 47 |  | 
| 47 | 
            -
                def add_notification_listener(notification_type, notification_callback)
         | 
| 48 | 
            +
                def add_notification_listener(notification_type, notification_callback = nil, &block)
         | 
| 48 49 | 
             
                  return nil unless notification_type_valid?(notification_type)
         | 
| 49 50 |  | 
| 51 | 
            +
                  if notification_callback && block_given?
         | 
| 52 | 
            +
                    @logger.log Logger::ERROR, 'Callback and block are mutually exclusive.'
         | 
| 53 | 
            +
                    return nil
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  notification_callback ||= block
         | 
| 57 | 
            +
             | 
| 50 58 | 
             
                  unless notification_callback
         | 
| 51 59 | 
             
                    @logger.log Logger::ERROR, 'Callback can not be empty.'
         | 
| 52 60 | 
             
                    return nil
         | 
| 53 61 | 
             
                  end
         | 
| 54 62 |  | 
| 55 | 
            -
                  unless notification_callback. | 
| 63 | 
            +
                  unless notification_callback.respond_to? :call
         | 
| 56 64 | 
             
                    @logger.log Logger::ERROR, 'Invalid notification callback given.'
         | 
| 57 65 | 
             
                    return nil
         | 
| 58 66 | 
             
                  end
         | 
| @@ -70,7 +78,7 @@ module Optimizely | |
| 70 78 | 
             
                #
         | 
| 71 79 | 
             
                # @param notification_id
         | 
| 72 80 | 
             
                #
         | 
| 73 | 
            -
                # @return [Boolean]  | 
| 81 | 
            +
                # @return [Boolean] true if found and removed, false otherwise
         | 
| 74 82 |  | 
| 75 83 | 
             
                def remove_notification_listener(notification_id)
         | 
| 76 84 | 
             
                  unless notification_id
         | 
    
        data/lib/optimizely/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: optimizely-sdk
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 3.3. | 
| 4 | 
            +
              version: 3.3.2.rc1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Optimizely
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2019- | 
| 11 | 
            +
            date: 2019-12-05 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -202,12 +202,12 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 202 202 | 
             
                  version: '0'
         | 
| 203 203 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 204 204 | 
             
              requirements:
         | 
| 205 | 
            -
              - - " | 
| 205 | 
            +
              - - ">"
         | 
| 206 206 | 
             
                - !ruby/object:Gem::Version
         | 
| 207 | 
            -
                  version:  | 
| 207 | 
            +
                  version: 1.3.1
         | 
| 208 208 | 
             
            requirements: []
         | 
| 209 209 | 
             
            rubyforge_project: 
         | 
| 210 | 
            -
            rubygems_version: 2. | 
| 210 | 
            +
            rubygems_version: 2.7.6.2
         | 
| 211 211 | 
             
            signing_key: 
         | 
| 212 212 | 
             
            specification_version: 4
         | 
| 213 213 | 
             
            summary: Ruby SDK for Optimizely's testing framework
         |