splitclient-rb 5.1.2.pre.rc21-java → 5.1.3.pre.rc1-java
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 +4 -4
- data/.gitignore +4 -1
- data/CHANGES.txt +6 -0
- data/Detailed-README.md +8 -0
- data/NEWS +8 -0
- data/lib/splitclient-rb.rb +3 -2
- data/lib/splitclient-rb/cache/adapters/cache_adapter.rb +131 -0
- data/lib/splitclient-rb/cache/repositories/segments_repository.rb +6 -1
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +7 -2
- data/lib/splitclient-rb/clients/split_client.rb +57 -50
- data/lib/splitclient-rb/engine/models/label.rb +0 -1
- data/lib/splitclient-rb/exceptions.rb +7 -0
- data/lib/splitclient-rb/managers/split_manager.rb +1 -2
- data/lib/splitclient-rb/split_config.rb +23 -0
- data/lib/splitclient-rb/validators.rb +185 -0
- data/lib/splitclient-rb/version.rb +1 -1
- data/splitclient-rb.gemspec +2 -0
- metadata +33 -4
- data/lib/splitclient-rb/exceptions/impressions_shutdown_exception.rb +0 -4
- data/lib/splitclient-rb/exceptions/sdk_blocker_timeout_expired_exception.rb +0 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 86614a077b8bb2e11605c201e8d7ce74fa53af08
         | 
| 4 | 
            +
              data.tar.gz: 5a775b16d37564ba6897dccd48d33472e7c4e1c3
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 22d0552dfae11161414e2a624ffaf8a4e7d402914541109da17f71178474b6627e6b5c5ef71622e56190cbb1b30cec8cba60c2bf39099b0019f8705ed7c4f71a
         | 
| 7 | 
            +
              data.tar.gz: 90e26ace99de500d55c05ddd9dc632b17e9d67bc8a1b5abbd1facae06110dfb8a43cb5443b9172293da7a25e1156a409b8e05406c7be5c1475ef307e33d70011
         | 
    
        data/.gitignore
    CHANGED
    
    
    
        data/CHANGES.txt
    CHANGED
    
    | @@ -1,3 +1,9 @@ | |
| 1 | 
            +
            5.1.3
         | 
| 2 | 
            +
            - Add cache wrapper to treatments and segments.
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            5.1.2 (October 26th, 2018)
         | 
| 5 | 
            +
            - Add input validation for client API methods
         | 
| 6 | 
            +
             | 
| 1 7 | 
             
            5.1.1 (October 4th, 2018)
         | 
| 2 8 | 
             
            - Change get_treatments so that it sends a single latency metric
         | 
| 3 9 | 
             
            - Removed unused call to Redis#scan when adding latencies
         | 
    
        data/Detailed-README.md
    CHANGED
    
    | @@ -301,6 +301,14 @@ _To use Redis, include `redis-rb` in your app's Gemfile._ | |
| 301 301 |  | 
| 302 302 | 
             
            *default value* = (your current hostname)
         | 
| 303 303 |  | 
| 304 | 
            +
            **cache_ttl** : Time to live in seconds for the memory cache values when using Redis.
         | 
| 305 | 
            +
             | 
| 306 | 
            +
            *default value* = `5`
         | 
| 307 | 
            +
             | 
| 308 | 
            +
            **max_cache_size** : Maximum number of items held in the memory cache values when using Redis. When cache is full an LRU strategy for pruning shall be used.
         | 
| 309 | 
            +
             | 
| 310 | 
            +
            *default value* = `500`
         | 
| 311 | 
            +
             | 
| 304 312 | 
             
            **redis_url** : Redis URL or hash with configuration for the SDK to connect to. See [Redis#initialize](https://www.rubydoc.info/github/redis/redis-rb/Redis%3Ainitialize) for detailed information.
         | 
| 305 313 |  | 
| 306 314 | 
             
            *default value* = `'redis://127.0.0.1:6379/0'`
         | 
    
        data/NEWS
    CHANGED
    
    | @@ -1,3 +1,11 @@ | |
| 1 | 
            +
            5.1.3
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Add cache wrapper to treatments and segments.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            5.1.2
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Add input validation for client API methods: get_treatment, get_treatments, track, manager
         | 
| 8 | 
            +
             | 
| 1 9 | 
             
            5.1.1
         | 
| 2 10 |  | 
| 3 11 | 
             
            Reduces the number of calls to Redis when calling #client.get_treatments using such cache adapter.
         | 
    
        data/lib/splitclient-rb.rb
    CHANGED
    
    | @@ -2,11 +2,11 @@ require 'forwardable' | |
| 2 2 |  | 
| 3 3 | 
             
            require 'splitclient-rb/version'
         | 
| 4 4 |  | 
| 5 | 
            -
            require 'splitclient-rb/exceptions | 
| 6 | 
            -
            require 'splitclient-rb/exceptions/sdk_blocker_timeout_expired_exception'
         | 
| 5 | 
            +
            require 'splitclient-rb/exceptions'
         | 
| 7 6 | 
             
            require 'splitclient-rb/cache/routers/impression_router'
         | 
| 8 7 | 
             
            require 'splitclient-rb/cache/adapters/memory_adapters/map_adapter'
         | 
| 9 8 | 
             
            require 'splitclient-rb/cache/adapters/memory_adapters/queue_adapter'
         | 
| 9 | 
            +
            require 'splitclient-rb/cache/adapters/cache_adapter'
         | 
| 10 10 | 
             
            require 'splitclient-rb/cache/adapters/memory_adapter'
         | 
| 11 11 | 
             
            require 'splitclient-rb/cache/adapters/redis_adapter'
         | 
| 12 12 | 
             
            require 'splitclient-rb/cache/repositories/repository'
         | 
| @@ -80,6 +80,7 @@ require 'splitclient-rb/engine/models/split' | |
| 80 80 | 
             
            require 'splitclient-rb/engine/models/label'
         | 
| 81 81 | 
             
            require 'splitclient-rb/engine/models/treatment'
         | 
| 82 82 | 
             
            require 'splitclient-rb/utilitites'
         | 
| 83 | 
            +
            require 'splitclient-rb/validators'
         | 
| 83 84 |  | 
| 84 85 | 
             
            # C extension
         | 
| 85 86 | 
             
            require 'murmurhash/murmurhash_mri'
         | 
| @@ -0,0 +1,131 @@ | |
| 1 | 
            +
            require 'lru_redux'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module SplitIoClient
         | 
| 4 | 
            +
              module Cache
         | 
| 5 | 
            +
                module Adapters
         | 
| 6 | 
            +
                  class CacheAdapter
         | 
| 7 | 
            +
                    extend Forwardable
         | 
| 8 | 
            +
                    def_delegators :@adapter, :initialize_set, :set_bool, :pipelined
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    def initialize(adapter)
         | 
| 11 | 
            +
                      @cache = LruRedux::TTL::ThreadSafeCache.new(SplitIoClient.configuration.max_cache_size, SplitIoClient.configuration.cache_ttl)
         | 
| 12 | 
            +
                      @adapter = adapter
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    def delete(key)
         | 
| 16 | 
            +
                      @cache.delete(key)
         | 
| 17 | 
            +
                      @adapter.delete(key)
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    def clear(namespace_key)
         | 
| 21 | 
            +
                      @cache.clear
         | 
| 22 | 
            +
                      @adapter.clear(namespace_key)
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    def string(key)
         | 
| 26 | 
            +
                      value = get(key)
         | 
| 27 | 
            +
                      return value if value
         | 
| 28 | 
            +
                      value = @adapter.string(key)
         | 
| 29 | 
            +
                      add(key, value)
         | 
| 30 | 
            +
                      value
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    def set_string(key, value)
         | 
| 34 | 
            +
                      add(key, value)
         | 
| 35 | 
            +
                      @adapter.set_string(key, value)
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    def multiple_strings(keys)
         | 
| 39 | 
            +
                      cached_values = keys.each_with_object({}) do |key, memo|
         | 
| 40 | 
            +
                         memo[key] = get(key)
         | 
| 41 | 
            +
                      end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                      non_cached_keys = []
         | 
| 44 | 
            +
                      cached_values.delete_if{ |k,v| v.nil? ? non_cached_keys << k : false }
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                      if non_cached_keys.any?
         | 
| 47 | 
            +
                        new_values = @adapter.multiple_strings(non_cached_keys)
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                        new_values.keys.each do |key, value|
         | 
| 50 | 
            +
                          add(key, value)
         | 
| 51 | 
            +
                        end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                        cached_values.merge!(new_values)
         | 
| 54 | 
            +
                      end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                      cached_values
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    def find_strings_by_prefix(prefix)
         | 
| 60 | 
            +
                      @adapter.find_strings_by_prefix(prefix)
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    def exists?(key)
         | 
| 64 | 
            +
                      cached_value = get(key)
         | 
| 65 | 
            +
                      if cached_value.nil?
         | 
| 66 | 
            +
                        @adapter.exists?(key)
         | 
| 67 | 
            +
                      else
         | 
| 68 | 
            +
                        true
         | 
| 69 | 
            +
                      end
         | 
| 70 | 
            +
                    end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                    def add_to_set(key, values)
         | 
| 73 | 
            +
                      if values.is_a? Array
         | 
| 74 | 
            +
                        values.each { |value| add_to_map(key, value, 1) }
         | 
| 75 | 
            +
                      else
         | 
| 76 | 
            +
                        add_to_map(key, values, 1)
         | 
| 77 | 
            +
                      end
         | 
| 78 | 
            +
                      @adapter.add_to_set(key, values)
         | 
| 79 | 
            +
                    end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                    def in_set?(key, field)
         | 
| 82 | 
            +
                      cached_value = get(key)
         | 
| 83 | 
            +
                      if cached_value.nil?
         | 
| 84 | 
            +
                        return @adapter.in_set?(key, field)
         | 
| 85 | 
            +
                      end
         | 
| 86 | 
            +
                      cached_value.key?(field)
         | 
| 87 | 
            +
                    end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    def get_set(key)
         | 
| 90 | 
            +
                      cached_value = get(key)
         | 
| 91 | 
            +
                      if cached_value.nil?
         | 
| 92 | 
            +
                        return @adapter.get_set(key)
         | 
| 93 | 
            +
                      end
         | 
| 94 | 
            +
                      cached_value.keys
         | 
| 95 | 
            +
                    end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                    def delete_from_set(key, fields)
         | 
| 98 | 
            +
                      cached_value = get(key)
         | 
| 99 | 
            +
                      if cached_value
         | 
| 100 | 
            +
                        if fields.is_a? Array
         | 
| 101 | 
            +
                          fields.each { |field| cached_value.delete(field) }
         | 
| 102 | 
            +
                        else
         | 
| 103 | 
            +
                          cached_value.delete(fields)
         | 
| 104 | 
            +
                        end
         | 
| 105 | 
            +
                      end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                      @adapter.delete_from_set(key, fields)
         | 
| 108 | 
            +
                    end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                    def initialize_map(key)
         | 
| 111 | 
            +
                      @cache[key] = Concurrent::Map.new
         | 
| 112 | 
            +
                    end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                    private
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                    def add_to_map(key, field, value)
         | 
| 117 | 
            +
                      initialize_map(key) unless get(key)
         | 
| 118 | 
            +
                      get(key).put(field.to_s, value.to_s)
         | 
| 119 | 
            +
                    end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                    def add(key, value)
         | 
| 122 | 
            +
                      @cache[key] = value.to_s unless value.nil?
         | 
| 123 | 
            +
                    end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                    def get(key)
         | 
| 126 | 
            +
                      @cache[key]
         | 
| 127 | 
            +
                    end
         | 
| 128 | 
            +
                  end
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
              end
         | 
| 131 | 
            +
            end
         | 
| @@ -7,7 +7,12 @@ module SplitIoClient | |
| 7 7 | 
             
                    attr_reader :adapter
         | 
| 8 8 |  | 
| 9 9 | 
             
                    def initialize(adapter)
         | 
| 10 | 
            -
                      @adapter = adapter
         | 
| 10 | 
            +
                      @adapter = case adapter.class.to_s
         | 
| 11 | 
            +
                      when 'SplitIoClient::Cache::Adapters::RedisAdapter'
         | 
| 12 | 
            +
                        SplitIoClient::Cache::Adapters::CacheAdapter.new(adapter)
         | 
| 13 | 
            +
                      else
         | 
| 14 | 
            +
                        adapter
         | 
| 15 | 
            +
                      end
         | 
| 11 16 | 
             
                      @adapter.set_bool(namespace_key('.ready'), false) unless SplitIoClient.configuration.mode == :consumer
         | 
| 12 17 | 
             
                    end
         | 
| 13 18 |  | 
| @@ -7,7 +7,12 @@ module SplitIoClient | |
| 7 7 | 
             
                    attr_reader :adapter
         | 
| 8 8 |  | 
| 9 9 | 
             
                    def initialize(adapter)
         | 
| 10 | 
            -
                      @adapter = adapter
         | 
| 10 | 
            +
                      @adapter = case adapter.class.to_s
         | 
| 11 | 
            +
                      when 'SplitIoClient::Cache::Adapters::RedisAdapter'
         | 
| 12 | 
            +
                        SplitIoClient::Cache::Adapters::CacheAdapter.new(adapter)
         | 
| 13 | 
            +
                      else
         | 
| 14 | 
            +
                        adapter
         | 
| 15 | 
            +
                      end
         | 
| 11 16 | 
             
                      unless SplitIoClient.configuration.mode == :consumer
         | 
| 12 17 | 
             
                        @adapter.set_string(namespace_key('.splits.till'), '-1')
         | 
| 13 18 | 
             
                        @adapter.initialize_map(namespace_key('.segments.registered'))
         | 
| @@ -26,7 +31,7 @@ module SplitIoClient | |
| 26 31 |  | 
| 27 32 | 
             
                    def get_splits(names)
         | 
| 28 33 | 
             
                      splits = {}
         | 
| 29 | 
            -
                      split_names = names. | 
| 34 | 
            +
                      split_names = names.map { |name| namespace_key(".split.#{name}") }
         | 
| 30 35 | 
             
                      splits.merge!(
         | 
| 31 36 | 
             
                        @adapter
         | 
| 32 37 | 
             
                          .multiple_strings(split_names)
         | 
| @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            module SplitIoClient
         | 
| 2 | 
            +
             | 
| 2 3 | 
             
              class SplitClient
         | 
| 3 4 | 
             
                #
         | 
| 4 5 | 
             
                # Creates a new split client instance that connects to split.io API.
         | 
| @@ -17,11 +18,24 @@ module SplitIoClient | |
| 17 18 | 
             
                end
         | 
| 18 19 |  | 
| 19 20 | 
             
                def get_treatments(key, split_names, attributes = {})
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  return nil unless SplitIoClient::Validators.valid_get_treatments_parameters(split_names)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  sanitized_split_names = sanitize_split_names(split_names)
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  if sanitized_split_names.empty?
         | 
| 27 | 
            +
                    SplitIoClient.configuration.logger.warn('get_treatments: split_names is an empty array or has null values')
         | 
| 28 | 
            +
                    return {}
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 20 31 | 
             
                  bucketing_key, matching_key = keys_from_key(key)
         | 
| 32 | 
            +
                  bucketing_key = bucketing_key ? bucketing_key.to_s : nil
         | 
| 33 | 
            +
                  matching_key = matching_key ? matching_key.to_s : nil
         | 
| 34 | 
            +
             | 
| 21 35 | 
             
                  evaluator = Engine::Parser::Evaluator.new(@segments_repository, @splits_repository, true)
         | 
| 22 36 | 
             
                  start = Time.now
         | 
| 23 37 | 
             
                  treatments_labels_change_numbers =
         | 
| 24 | 
            -
                    @splits_repository.get_splits( | 
| 38 | 
            +
                    @splits_repository.get_splits(sanitized_split_names).each_with_object({}) do |(name, data), memo|
         | 
| 25 39 | 
             
                      memo.merge!(name => get_treatment(key, name, attributes, data, false, true, evaluator))
         | 
| 26 40 | 
             
                    end
         | 
| 27 41 | 
             
                  latency = (Time.now - start) * 1000.0
         | 
| @@ -34,13 +48,13 @@ module SplitIoClient | |
| 34 48 | 
             
                      matching_key, bucketing_key, treatments_labels_change_numbers, time
         | 
| 35 49 | 
             
                    )
         | 
| 36 50 |  | 
| 37 | 
            -
                    route_impressions( | 
| 51 | 
            +
                    route_impressions(sanitized_split_names, matching_key, bucketing_key, time, treatments_labels_change_numbers, attributes)
         | 
| 38 52 | 
             
                  end
         | 
| 39 53 |  | 
| 40 | 
            -
                   | 
| 54 | 
            +
                  split_names_keys = treatments_labels_change_numbers.keys
         | 
| 41 55 | 
             
                  treatments = treatments_labels_change_numbers.values.map { |v| v[:treatment] }
         | 
| 42 56 |  | 
| 43 | 
            -
                  Hash[ | 
| 57 | 
            +
                  Hash[split_names_keys.zip(treatments)]
         | 
| 44 58 | 
             
                end
         | 
| 45 59 |  | 
| 46 60 | 
             
                #
         | 
| @@ -59,68 +73,43 @@ module SplitIoClient | |
| 59 73 | 
             
                    key, split_name, attributes = {}, split_data = nil, store_impressions = true,
         | 
| 60 74 | 
             
                    multiple = false, evaluator = nil
         | 
| 61 75 | 
             
                  )
         | 
| 62 | 
            -
                   | 
| 63 | 
            -
                   | 
| 64 | 
            -
                  evaluator ||= Engine::Parser::Evaluator.new(@segments_repository, @splits_repository)
         | 
| 76 | 
            +
                  control_treatment = { label: Engine::Models::Label::EXCEPTION, treatment: SplitIoClient::Engine::Models::Treatment::CONTROL }
         | 
| 77 | 
            +
                  parsed_control_treatment = parsed_treatment(multiple, control_treatment)
         | 
| 65 78 |  | 
| 66 | 
            -
                   | 
| 67 | 
            -
                    SplitIoClient.configuration.logger.warn('matching_key was null for split_name: ' + split_name.to_s)
         | 
| 68 | 
            -
                    return parsed_treatment(multiple, treatment_data)
         | 
| 69 | 
            -
                  end
         | 
| 79 | 
            +
                  bucketing_key, matching_key = keys_from_key(key)
         | 
| 70 80 |  | 
| 71 | 
            -
                   | 
| 72 | 
            -
                    SplitIoClient.configuration.logger.warn('split_name was null for key: ' + key)
         | 
| 73 | 
            -
                    return parsed_treatment(multiple, treatment_data)
         | 
| 74 | 
            -
                  end
         | 
| 81 | 
            +
                  return parsed_control_treatment unless SplitIoClient::Validators.valid_get_treatment_parameters(key, split_name, matching_key, bucketing_key)
         | 
| 75 82 |  | 
| 76 | 
            -
                   | 
| 83 | 
            +
                  bucketing_key = bucketing_key ? bucketing_key.to_s : nil
         | 
| 84 | 
            +
                  matching_key = matching_key.to_s
         | 
| 85 | 
            +
                  evaluator ||= Engine::Parser::Evaluator.new(@segments_repository, @splits_repository)
         | 
| 77 86 |  | 
| 78 87 | 
             
                  begin
         | 
| 88 | 
            +
                    start = Time.now
         | 
| 89 | 
            +
             | 
| 79 90 | 
             
                    split = multiple ? split_data : @splits_repository.get_split(split_name)
         | 
| 80 91 |  | 
| 81 92 | 
             
                    if split.nil?
         | 
| 82 | 
            -
                      SplitIoClient.configuration.logger. | 
| 83 | 
            -
                      return  | 
| 84 | 
            -
                    else
         | 
| 85 | 
            -
                      treatment_data =
         | 
| 86 | 
            -
                        evaluator.call(
         | 
| 87 | 
            -
                        { bucketing_key: bucketing_key, matching_key: matching_key }, split, attributes
         | 
| 88 | 
            -
                      )
         | 
| 93 | 
            +
                      SplitIoClient.configuration.logger.warn("split_name: #{split_name} does not exist. Returning CONTROL")
         | 
| 94 | 
            +
                      return parsed_control_treatment
         | 
| 89 95 | 
             
                    end
         | 
| 90 | 
            -
                  rescue StandardError => error
         | 
| 91 | 
            -
                    SplitIoClient.configuration.log_found_exception(__method__.to_s, error)
         | 
| 92 96 |  | 
| 93 | 
            -
                     | 
| 94 | 
            -
                       | 
| 95 | 
            -
                      {
         | 
| 96 | 
            -
                        treatment: SplitIoClient::Engine::Models::Treatment::CONTROL,
         | 
| 97 | 
            -
                        label: SplitIoClient::Engine::Models::Label::EXCEPTION
         | 
| 98 | 
            -
                      },
         | 
| 99 | 
            -
                      store_impressions, attributes
         | 
| 97 | 
            +
                    treatment_data =
         | 
| 98 | 
            +
                      evaluator.call(
         | 
| 99 | 
            +
                      { bucketing_key: bucketing_key, matching_key: matching_key }, split, attributes
         | 
| 100 100 | 
             
                    )
         | 
| 101 101 |  | 
| 102 | 
            -
                    return parsed_treatment(multiple, treatment_data)
         | 
| 103 | 
            -
                  end
         | 
| 104 | 
            -
             | 
| 105 | 
            -
                  begin
         | 
| 106 102 | 
             
                    latency = (Time.now - start) * 1000.0
         | 
| 107 | 
            -
                     | 
| 103 | 
            +
                    store_impression(split_name, matching_key, bucketing_key, treatment_data, store_impressions, attributes)
         | 
| 108 104 |  | 
| 109 105 | 
             
                    # Measure
         | 
| 110 106 | 
             
                    @adapter.metrics.time('sdk.get_treatment', latency) unless multiple
         | 
| 111 107 | 
             
                  rescue StandardError => error
         | 
| 112 108 | 
             
                    SplitIoClient.configuration.log_found_exception(__method__.to_s, error)
         | 
| 113 109 |  | 
| 114 | 
            -
                    store_impression(
         | 
| 115 | 
            -
                      split_name, matching_key, bucketing_key,
         | 
| 116 | 
            -
                      {
         | 
| 117 | 
            -
                        treatment: SplitIoClient::Engine::Models::Treatment::CONTROL,
         | 
| 118 | 
            -
                        label: SplitIoClient::Engine::Models::Label::EXCEPTION
         | 
| 119 | 
            -
                      },
         | 
| 120 | 
            -
                      store_impressions, attributes
         | 
| 121 | 
            -
                    )
         | 
| 110 | 
            +
                    store_impression(split_name, matching_key, bucketing_key, control_treatment, store_impressions, attributes)
         | 
| 122 111 |  | 
| 123 | 
            -
                    return  | 
| 112 | 
            +
                    return parsed_control_treatment
         | 
| 124 113 | 
             
                  end
         | 
| 125 114 |  | 
| 126 115 | 
             
                  parsed_treatment(multiple, treatment_data)
         | 
| @@ -188,16 +177,23 @@ module SplitIoClient | |
| 188 177 | 
             
                  @impression_router ||= SplitIoClient::ImpressionRouter.new
         | 
| 189 178 | 
             
                end
         | 
| 190 179 |  | 
| 191 | 
            -
                def track(key,  | 
| 192 | 
            -
                   | 
| 180 | 
            +
                def track(key, traffic_type_name, event_type, value = nil)
         | 
| 181 | 
            +
                  return false unless SplitIoClient::Validators.valid_track_parameters(key, traffic_type_name, event_type, value)
         | 
| 182 | 
            +
                  begin
         | 
| 183 | 
            +
                    @events_repository.add(key.to_s, traffic_type_name, event_type.to_s, (Time.now.to_f * 1000).to_i, value)
         | 
| 184 | 
            +
                    true
         | 
| 185 | 
            +
                  rescue StandardError => error
         | 
| 186 | 
            +
                    SplitIoClient.configuration.log_found_exception(__method__.to_s, error)
         | 
| 187 | 
            +
                    false
         | 
| 188 | 
            +
                  end
         | 
| 193 189 | 
             
                end
         | 
| 194 190 |  | 
| 195 191 | 
             
                def keys_from_key(key)
         | 
| 196 192 | 
             
                  case key.class.to_s
         | 
| 197 193 | 
             
                  when 'Hash'
         | 
| 198 | 
            -
                    key.values_at(:bucketing_key, :matching_key).map { |k| k.nil? ? nil : k | 
| 194 | 
            +
                    key.values_at(:bucketing_key, :matching_key).map { |k| k.nil? ? nil : k }
         | 
| 199 195 | 
             
                  else
         | 
| 200 | 
            -
                    [nil, key].map { |k| k.nil? ? nil : k | 
| 196 | 
            +
                    [nil, key].map { |k| k.nil? ? nil : k }
         | 
| 201 197 | 
             
                  end
         | 
| 202 198 | 
             
                end
         | 
| 203 199 |  | 
| @@ -212,5 +208,16 @@ module SplitIoClient | |
| 212 208 | 
             
                    treatment_data[:treatment]
         | 
| 213 209 | 
             
                  end
         | 
| 214 210 | 
             
                end
         | 
| 211 | 
            +
             | 
| 212 | 
            +
                def sanitize_split_names(split_names)
         | 
| 213 | 
            +
                  split_names.compact.uniq.select do |split_name|
         | 
| 214 | 
            +
                    if split_name.is_a?(String) && !split_name.empty?
         | 
| 215 | 
            +
                      true
         | 
| 216 | 
            +
                    else
         | 
| 217 | 
            +
                      SplitIoClient.configuration.logger.warn('get_treatments: split_name has to be a non empty string')
         | 
| 218 | 
            +
                      false
         | 
| 219 | 
            +
                    end
         | 
| 220 | 
            +
                  end
         | 
| 221 | 
            +
                end
         | 
| 215 222 | 
             
              end
         | 
| 216 223 | 
             
            end
         | 
| @@ -43,7 +43,7 @@ module SplitIoClient | |
| 43 43 | 
             
                #
         | 
| 44 44 | 
             
                # @returns a split view
         | 
| 45 45 | 
             
                def split(split_name)
         | 
| 46 | 
            -
                  return unless @splits_repository
         | 
| 46 | 
            +
                  return unless @splits_repository && SplitIoClient::Validators.valid_split_parameters(split_name)
         | 
| 47 47 |  | 
| 48 48 | 
             
                  split = @splits_repository.get_split(split_name)
         | 
| 49 49 |  | 
| @@ -63,7 +63,6 @@ module SplitIoClient | |
| 63 63 | 
             
                    treatments = []
         | 
| 64 64 | 
             
                  end
         | 
| 65 65 |  | 
| 66 | 
            -
             | 
| 67 66 | 
             
                    {
         | 
| 68 67 | 
             
                      name: name,
         | 
| 69 68 | 
             
                      traffic_type_name: split[:trafficTypeName],
         | 
| @@ -33,6 +33,8 @@ module SplitIoClient | |
| 33 33 | 
             
                # @option opts [Int] :impressions_queue_size Size of the impressions queue in the memory repository. Once reached, newer impressions will be dropped
         | 
| 34 34 | 
             
                # @option opts [Int] :impressions_bulk_size Max number of impressions to be sent to the backend on each post
         | 
| 35 35 | 
             
                # @option opts [#log] :impression_listener this object will capture all impressions and process them through `#log`
         | 
| 36 | 
            +
                # @option opts [Int] :cache_ttl Time to live in seconds for the memory cache values when using Redis.
         | 
| 37 | 
            +
                # @option opts [Int] :max_cache_size Max number of items to be held in the memory cache before prunning when using Redis.
         | 
| 36 38 | 
             
                # @return [type] SplitConfig with configuration options
         | 
| 37 39 | 
             
                def initialize(opts = {})
         | 
| 38 40 | 
             
                  @base_uri = (opts[:base_uri] || SplitConfig.default_base_uri).chomp('/')
         | 
| @@ -70,6 +72,9 @@ module SplitIoClient | |
| 70 72 | 
             
                  @machine_name = opts[:machine_name] || SplitConfig.machine_hostname
         | 
| 71 73 | 
             
                  @machine_ip = opts[:machine_ip] || SplitConfig.machine_ip
         | 
| 72 74 |  | 
| 75 | 
            +
                  @cache_ttl = opts[:cache_ttl] || SplitConfig.cache_ttl
         | 
| 76 | 
            +
                  @max_cache_size = opts[:max_cache_size] || SplitConfig.max_cache_size
         | 
| 77 | 
            +
             | 
| 73 78 | 
             
                  @language = opts[:language] || 'ruby'
         | 
| 74 79 | 
             
                  @version = opts[:version] || SplitIoClient::VERSION
         | 
| 75 80 |  | 
| @@ -176,6 +181,9 @@ module SplitIoClient | |
| 176 181 | 
             
                attr_accessor :machine_ip
         | 
| 177 182 | 
             
                attr_accessor :machine_name
         | 
| 178 183 |  | 
| 184 | 
            +
                attr_accessor :cache_ttl
         | 
| 185 | 
            +
                attr_accessor :max_cache_size
         | 
| 186 | 
            +
             | 
| 179 187 | 
             
                attr_accessor :language
         | 
| 180 188 | 
             
                attr_accessor :version
         | 
| 181 189 |  | 
| @@ -357,6 +365,21 @@ module SplitIoClient | |
| 357 365 | 
             
                  false
         | 
| 358 366 | 
             
                end
         | 
| 359 367 |  | 
| 368 | 
            +
                #
         | 
| 369 | 
            +
                # The default cache time to live
         | 
| 370 | 
            +
                #
         | 
| 371 | 
            +
                # @return [boolean]
         | 
| 372 | 
            +
                def self.cache_ttl
         | 
| 373 | 
            +
                  5
         | 
| 374 | 
            +
                end
         | 
| 375 | 
            +
             | 
| 376 | 
            +
                # The default max cache size
         | 
| 377 | 
            +
                #
         | 
| 378 | 
            +
                # @return [boolean]
         | 
| 379 | 
            +
                def self.max_cache_size
         | 
| 380 | 
            +
                  500
         | 
| 381 | 
            +
                end
         | 
| 382 | 
            +
             | 
| 360 383 | 
             
                #
         | 
| 361 384 | 
             
                # custom logger of exceptions
         | 
| 362 385 | 
             
                #
         | 
| @@ -0,0 +1,185 @@ | |
| 1 | 
            +
            module SplitIoClient
         | 
| 2 | 
            +
              module Validators
         | 
| 3 | 
            +
                extend self
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def valid_get_treatment_parameters(key, split_name, matching_key, bucketing_key)
         | 
| 6 | 
            +
                  valid_key?(key) && valid_split_name?(split_name) && valid_matching_key?(matching_key) && valid_bucketing_key?(bucketing_key)
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def valid_get_treatments_parameters(split_names)
         | 
| 10 | 
            +
                  valid_split_names?(split_names)
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def valid_track_parameters(key, traffic_type_name, event_type, value)
         | 
| 14 | 
            +
                  valid_track_key?(key) && valid_traffic_type_name?(traffic_type_name) && valid_event_type?(event_type) && valid_value?(value)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def valid_split_parameters(split_name)
         | 
| 18 | 
            +
                  valid_split_name?(split_name, :split)
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                private
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def string?(value)
         | 
| 24 | 
            +
                  value.is_a?(String) || value.is_a?(Symbol)
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def number_or_string?(value)
         | 
| 28 | 
            +
                  value.is_a?(Numeric) || string?(value)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def log_nil(key, method)
         | 
| 32 | 
            +
                  SplitIoClient.configuration.logger.error("#{method}: #{key} cannot be nil")
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def log_string(key, method)
         | 
| 36 | 
            +
                  SplitIoClient.configuration.logger.error("#{method}: #{key} must be a String or a Symbol")
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def log_number_or_string(key, method)
         | 
| 40 | 
            +
                  SplitIoClient.configuration.logger.error("#{method}: #{key} must be a String")
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def log_convert_numeric(key, method)
         | 
| 44 | 
            +
                  SplitIoClient.configuration.logger.warn("#{method}: #{key} is not of type String, converting to String")
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def valid_split_name?(split_name, method=:get_treatment)
         | 
| 48 | 
            +
                  if split_name.nil?
         | 
| 49 | 
            +
                    log_nil(:split_name, method)
         | 
| 50 | 
            +
                    return false
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  unless string?(split_name)
         | 
| 54 | 
            +
                    log_string(:split_name, method)
         | 
| 55 | 
            +
                    return false
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  return true
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                def valid_key?(key)
         | 
| 62 | 
            +
                  if key.nil?
         | 
| 63 | 
            +
                    log_nil(:key, :get_treatment)
         | 
| 64 | 
            +
                    return false
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  return true
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                def valid_matching_key?(matching_key)
         | 
| 71 | 
            +
                  if matching_key.nil?
         | 
| 72 | 
            +
                    log_nil(:matching_key, :get_treatment)
         | 
| 73 | 
            +
                    return false
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  unless number_or_string?(matching_key)
         | 
| 77 | 
            +
                    log_number_or_string(:matching_key, :get_treatment)
         | 
| 78 | 
            +
                    return false
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                  if matching_key.is_a? Numeric
         | 
| 82 | 
            +
                    log_convert_numeric(:matching_key, :get_treatment)
         | 
| 83 | 
            +
                  end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                  return true
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                def valid_bucketing_key?(bucketing_key)
         | 
| 89 | 
            +
                  if bucketing_key.nil?
         | 
| 90 | 
            +
                    SplitIoClient.configuration.logger.warn('get_treatment: key object should have bucketing_key set')
         | 
| 91 | 
            +
                    return true
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  unless number_or_string?(bucketing_key)
         | 
| 95 | 
            +
                    log_number_or_string(:bucketing_key, :get_treatment)
         | 
| 96 | 
            +
                    return false
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  if bucketing_key.is_a? Numeric
         | 
| 100 | 
            +
                    log_convert_numeric(:bucketing_key, :get_treatment)
         | 
| 101 | 
            +
                  end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                  return true
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                def valid_split_names?(split_names)
         | 
| 107 | 
            +
                  if split_names.nil?
         | 
| 108 | 
            +
                    log_nil(:split_names, :get_treatments)
         | 
| 109 | 
            +
                    return false
         | 
| 110 | 
            +
                  end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                  unless split_names.is_a? Array
         | 
| 113 | 
            +
                    SplitIoClient.configuration.logger.warn('get_treatments: split_names must be an Array')
         | 
| 114 | 
            +
                    return false
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                  return true
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                def valid_track_key?(key)
         | 
| 121 | 
            +
                  if key.nil?
         | 
| 122 | 
            +
                    log_nil(:key, :track)
         | 
| 123 | 
            +
                    return false
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                  unless number_or_string?(key)
         | 
| 127 | 
            +
                    log_number_or_string(:key, :track)
         | 
| 128 | 
            +
                    return false
         | 
| 129 | 
            +
                  end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                  if key.is_a? Numeric
         | 
| 132 | 
            +
                    log_convert_numeric(:key, :track)
         | 
| 133 | 
            +
                  end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                  return true
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                def valid_event_type?(event_type)
         | 
| 139 | 
            +
                  if event_type.nil?
         | 
| 140 | 
            +
                    log_nil(:event_type, :track)
         | 
| 141 | 
            +
                    return false
         | 
| 142 | 
            +
                  end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                  unless string?(event_type)
         | 
| 145 | 
            +
                    log_string(:event_type, :track)
         | 
| 146 | 
            +
                    return false
         | 
| 147 | 
            +
                  end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                  if (event_type.to_s =~ /[a-zA-Z0-9][-_\.a-zA-Z0-9]{0,62}/).nil?
         | 
| 150 | 
            +
                    SplitIoClient.configuration.logger.error('track: event_type must adhere to [a-zA-Z0-9][-_\.a-zA-Z0-9]{0,62}')
         | 
| 151 | 
            +
                    return false
         | 
| 152 | 
            +
                  end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                  return true
         | 
| 155 | 
            +
                end
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                def valid_traffic_type_name?(traffic_type_name)
         | 
| 158 | 
            +
                  if traffic_type_name.nil?
         | 
| 159 | 
            +
                    log_nil(:traffic_type_name, :track)
         | 
| 160 | 
            +
                    return false
         | 
| 161 | 
            +
                  end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                  unless string?(traffic_type_name)
         | 
| 164 | 
            +
                    log_string(:traffic_type_name, :track)
         | 
| 165 | 
            +
                    return false
         | 
| 166 | 
            +
                  end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                  if traffic_type_name.empty?
         | 
| 169 | 
            +
                    SplitIoClient.configuration.logger.error('track: traffic_type_name must not be an empty String')
         | 
| 170 | 
            +
                    return false
         | 
| 171 | 
            +
                  end
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                  return true
         | 
| 174 | 
            +
                end
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                def valid_value?(value)
         | 
| 177 | 
            +
                  unless value.is_a?(Numeric) || value.nil?
         | 
| 178 | 
            +
                    SplitIoClient.configuration.logger.error('track: value must be a number')
         | 
| 179 | 
            +
                    return false
         | 
| 180 | 
            +
                  end
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                  return true
         | 
| 183 | 
            +
                end
         | 
| 184 | 
            +
              end
         | 
| 185 | 
            +
            end
         | 
    
        data/splitclient-rb.gemspec
    CHANGED
    
    | @@ -46,11 +46,13 @@ Gem::Specification.new do |spec| | |
| 46 46 | 
             
              spec.add_development_dependency 'rspec'
         | 
| 47 47 | 
             
              spec.add_development_dependency 'rubocop', '0.59.0'
         | 
| 48 48 | 
             
              spec.add_development_dependency 'simplecov'
         | 
| 49 | 
            +
              spec.add_development_dependency 'timecop'
         | 
| 49 50 | 
             
              spec.add_development_dependency 'webmock'
         | 
| 50 51 |  | 
| 51 52 | 
             
              spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
         | 
| 52 53 | 
             
              spec.add_runtime_dependency 'faraday', '>= 0.8'
         | 
| 53 54 | 
             
              spec.add_runtime_dependency 'json', '>= 1.8'
         | 
| 55 | 
            +
              spec.add_runtime_dependency 'lru_redux'
         | 
| 54 56 | 
             
              spec.add_runtime_dependency 'net-http-persistent', '~> 2.9'
         | 
| 55 57 | 
             
              spec.add_runtime_dependency 'redis', '>= 3.2'
         | 
| 56 58 | 
             
              spec.add_runtime_dependency 'thread_safe', '>= 0.3'
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: splitclient-rb
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 5.1. | 
| 4 | 
            +
              version: 5.1.3.pre.rc1
         | 
| 5 5 | 
             
            platform: java
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Split Software
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2018- | 
| 11 | 
            +
            date: 2018-11-05 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -136,6 +136,20 @@ dependencies: | |
| 136 136 | 
             
                - - ">="
         | 
| 137 137 | 
             
                  - !ruby/object:Gem::Version
         | 
| 138 138 | 
             
                    version: '0'
         | 
| 139 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 140 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 141 | 
            +
                requirements:
         | 
| 142 | 
            +
                - - ">="
         | 
| 143 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 144 | 
            +
                    version: '0'
         | 
| 145 | 
            +
              name: timecop
         | 
| 146 | 
            +
              prerelease: false
         | 
| 147 | 
            +
              type: :development
         | 
| 148 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 149 | 
            +
                requirements:
         | 
| 150 | 
            +
                - - ">="
         | 
| 151 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 152 | 
            +
                    version: '0'
         | 
| 139 153 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 140 154 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 141 155 | 
             
                requirements:
         | 
| @@ -192,6 +206,20 @@ dependencies: | |
| 192 206 | 
             
                - - ">="
         | 
| 193 207 | 
             
                  - !ruby/object:Gem::Version
         | 
| 194 208 | 
             
                    version: '1.8'
         | 
| 209 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 210 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 211 | 
            +
                requirements:
         | 
| 212 | 
            +
                - - ">="
         | 
| 213 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 214 | 
            +
                    version: '0'
         | 
| 215 | 
            +
              name: lru_redux
         | 
| 216 | 
            +
              prerelease: false
         | 
| 217 | 
            +
              type: :runtime
         | 
| 218 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 219 | 
            +
                requirements:
         | 
| 220 | 
            +
                - - ">="
         | 
| 221 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 222 | 
            +
                    version: '0'
         | 
| 195 223 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 196 224 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 197 225 | 
             
                requirements:
         | 
| @@ -257,6 +285,7 @@ files: | |
| 257 285 | 
             
            - lib/murmurhash/murmurhash.jar
         | 
| 258 286 | 
             
            - lib/murmurhash/murmurhash_mri.rb
         | 
| 259 287 | 
             
            - lib/splitclient-rb.rb
         | 
| 288 | 
            +
            - lib/splitclient-rb/cache/adapters/cache_adapter.rb
         | 
| 260 289 | 
             
            - lib/splitclient-rb/cache/adapters/memory_adapter.rb
         | 
| 261 290 | 
             
            - lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb
         | 
| 262 291 | 
             
            - lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb
         | 
| @@ -321,8 +350,7 @@ files: | |
| 321 350 | 
             
            - lib/splitclient-rb/engine/parser/evaluator.rb
         | 
| 322 351 | 
             
            - lib/splitclient-rb/engine/parser/partition.rb
         | 
| 323 352 | 
             
            - lib/splitclient-rb/engine/parser/split_adapter.rb
         | 
| 324 | 
            -
            - lib/splitclient-rb/exceptions | 
| 325 | 
            -
            - lib/splitclient-rb/exceptions/sdk_blocker_timeout_expired_exception.rb
         | 
| 353 | 
            +
            - lib/splitclient-rb/exceptions.rb
         | 
| 326 354 | 
             
            - lib/splitclient-rb/localhost_split_factory.rb
         | 
| 327 355 | 
             
            - lib/splitclient-rb/localhost_utils.rb
         | 
| 328 356 | 
             
            - lib/splitclient-rb/managers/localhost_split_manager.rb
         | 
| @@ -332,6 +360,7 @@ files: | |
| 332 360 | 
             
            - lib/splitclient-rb/split_factory_builder.rb
         | 
| 333 361 | 
             
            - lib/splitclient-rb/split_logger.rb
         | 
| 334 362 | 
             
            - lib/splitclient-rb/utilitites.rb
         | 
| 363 | 
            +
            - lib/splitclient-rb/validators.rb
         | 
| 335 364 | 
             
            - lib/splitclient-rb/version.rb
         | 
| 336 365 | 
             
            - splitclient-rb.gemspec
         | 
| 337 366 | 
             
            - splitio.yml.example
         |