configcat 2.0.2 → 4.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.
- checksums.yaml +4 -4
- data/lib/configcat.rb +52 -30
- data/lib/configcat/autopollingcachepolicy.rb +23 -18
- data/lib/configcat/configcache.rb +5 -5
- data/lib/configcat/configcatclient.rb +85 -13
- data/lib/configcat/configfetcher.rb +120 -18
- data/lib/configcat/constants.rb +17 -0
- data/lib/configcat/datagovernance.rb +10 -0
- data/lib/configcat/interfaces.rb +2 -2
- data/lib/configcat/lazyloadingcachepolicy.rb +17 -11
- data/lib/configcat/manualpollingcachepolicy.rb +14 -9
- data/lib/configcat/rolloutevaluator.rb +29 -26
- data/lib/configcat/user.rb +5 -5
- data/lib/configcat/version.rb +1 -1
- metadata +36 -21
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 118a3db79c8d7d9a0795897380a4dfaf14fecda8a636024abfd9d2433b3af924
         | 
| 4 | 
            +
              data.tar.gz: 4c85c82b81fe08fcf9b6eed0a40bea06369939301aa09bc12e82b33a3b2176eb
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: afe03eda0affc92755ae0eb91196a15bfe61f68a12244270bb5d19b3870bc023fe9ccf3231d8f11f414c4439b49fd2f9481e9a64295c3ab87697511ebcf57b25
         | 
| 7 | 
            +
              data.tar.gz: 5ac8e3beef89cbc84ef89f2eb5b071fcf5cb348db1c302755ba4fc619c759f9919f80785b2b08a4a583725d35ea6b9ef038d869706956485eec3b4a9d4cadbaa
         | 
    
        data/lib/configcat.rb
    CHANGED
    
    | @@ -10,29 +10,34 @@ module ConfigCat | |
| 10 10 | 
             
                attr_accessor :logger
         | 
| 11 11 | 
             
              end
         | 
| 12 12 |  | 
| 13 | 
            -
              def ConfigCat.create_client( | 
| 13 | 
            +
              def ConfigCat.create_client(sdk_key, data_governance: DataGovernance::GLOBAL)
         | 
| 14 14 | 
             
                #
         | 
| 15 15 | 
             
                #   Create an instance of ConfigCatClient and setup Auto Poll mode with default options
         | 
| 16 16 | 
             
                #
         | 
| 17 | 
            -
                #   :param  | 
| 17 | 
            +
                #   :param sdk_key: ConfigCat SDK Key to access your configuration.
         | 
| 18 | 
            +
                #   :param data_governance:
         | 
| 19 | 
            +
                #   Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
         | 
| 20 | 
            +
                #   https://app.configcat.com/organization/data-governance
         | 
| 21 | 
            +
                #   (Only Organization Admins have access)
         | 
| 18 22 | 
             
                #
         | 
| 19 | 
            -
                return create_client_with_auto_poll( | 
| 23 | 
            +
                return create_client_with_auto_poll(sdk_key, data_governance: data_governance)
         | 
| 20 24 | 
             
              end
         | 
| 21 25 |  | 
| 22 | 
            -
              def ConfigCat.create_client_with_auto_poll( | 
| 26 | 
            +
              def ConfigCat.create_client_with_auto_poll(sdk_key,
         | 
| 23 27 | 
             
                                                         poll_interval_seconds: 60,
         | 
| 24 28 | 
             
                                                         max_init_wait_time_seconds: 5,
         | 
| 25 29 | 
             
                                                         on_configuration_changed_callback: nil,
         | 
| 26 30 | 
             
                                                         config_cache_class: nil,
         | 
| 27 31 | 
             
                                                         base_url: nil,
         | 
| 28 | 
            -
                                                         proxy_address:nil,
         | 
| 29 | 
            -
                                                         proxy_port:nil,
         | 
| 30 | 
            -
                                                         proxy_user:nil,
         | 
| 31 | 
            -
                                                         proxy_pass:nil | 
| 32 | 
            +
                                                         proxy_address: nil,
         | 
| 33 | 
            +
                                                         proxy_port: nil,
         | 
| 34 | 
            +
                                                         proxy_user: nil,
         | 
| 35 | 
            +
                                                         proxy_pass: nil,
         | 
| 36 | 
            +
                                                         data_governance: DataGovernance::GLOBAL)
         | 
| 32 37 | 
             
                #
         | 
| 33 38 | 
             
                #   Create an instance of ConfigCatClient and setup Auto Poll mode with custom options
         | 
| 34 39 | 
             
                #
         | 
| 35 | 
            -
                #   :param  | 
| 40 | 
            +
                #   :param sdk_key: ConfigCat SDK Key to access your configuration.
         | 
| 36 41 | 
             
                #   :param poll_interval_seconds: The client's poll interval in seconds. Default: 60 seconds.
         | 
| 37 42 | 
             
                #   :param on_configuration_changed_callback: You can subscribe to configuration changes with this callback
         | 
| 38 43 | 
             
                #   :param max_init_wait_time_seconds: maximum waiting time for first configuration fetch in polling mode.
         | 
| @@ -43,9 +48,13 @@ module ConfigCat | |
| 43 48 | 
             
                #   :param proxy_port: Proxy port
         | 
| 44 49 | 
             
                #   :param proxy_user: username for proxy authentication
         | 
| 45 50 | 
             
                #   :param proxy_pass: password for proxy authentication
         | 
| 51 | 
            +
                #   :param data_governance:
         | 
| 52 | 
            +
                #   Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
         | 
| 53 | 
            +
                #   https://app.configcat.com/organization/data-governance
         | 
| 54 | 
            +
                #   (Only Organization Admins have access)
         | 
| 46 55 | 
             
                #
         | 
| 47 | 
            -
                if  | 
| 48 | 
            -
                  raise ConfigCatClientException, " | 
| 56 | 
            +
                if sdk_key === nil
         | 
| 57 | 
            +
                  raise ConfigCatClientException, "SDK Key is required."
         | 
| 49 58 | 
             
                end
         | 
| 50 59 | 
             
                if poll_interval_seconds < 1
         | 
| 51 60 | 
             
                  poll_interval_seconds = 1
         | 
| @@ -53,7 +62,7 @@ module ConfigCat | |
| 53 62 | 
             
                if max_init_wait_time_seconds < 0
         | 
| 54 63 | 
             
                  max_init_wait_time_seconds = 0
         | 
| 55 64 | 
             
                end
         | 
| 56 | 
            -
                return ConfigCatClient.new( | 
| 65 | 
            +
                return ConfigCatClient.new(sdk_key,
         | 
| 57 66 | 
             
                                           poll_interval_seconds: poll_interval_seconds,
         | 
| 58 67 | 
             
                                           max_init_wait_time_seconds: max_init_wait_time_seconds,
         | 
| 59 68 | 
             
                                           on_configuration_changed_callback: on_configuration_changed_callback,
         | 
| @@ -63,21 +72,23 @@ module ConfigCat | |
| 63 72 | 
             
                                           proxy_address: proxy_address,
         | 
| 64 73 | 
             
                                           proxy_port: proxy_port,
         | 
| 65 74 | 
             
                                           proxy_user: proxy_user,
         | 
| 66 | 
            -
                                           proxy_pass: proxy_pass | 
| 75 | 
            +
                                           proxy_pass: proxy_pass,
         | 
| 76 | 
            +
                                           data_governance: data_governance)
         | 
| 67 77 | 
             
              end
         | 
| 68 78 |  | 
| 69 | 
            -
              def ConfigCat.create_client_with_lazy_load( | 
| 79 | 
            +
              def ConfigCat.create_client_with_lazy_load(sdk_key,
         | 
| 70 80 | 
             
                                                         cache_time_to_live_seconds: 60,
         | 
| 71 81 | 
             
                                                         config_cache_class: nil,
         | 
| 72 82 | 
             
                                                         base_url: nil,
         | 
| 73 | 
            -
                                                         proxy_address:nil,
         | 
| 74 | 
            -
                                                         proxy_port:nil,
         | 
| 75 | 
            -
                                                         proxy_user:nil,
         | 
| 76 | 
            -
                                                         proxy_pass:nil | 
| 83 | 
            +
                                                         proxy_address: nil,
         | 
| 84 | 
            +
                                                         proxy_port: nil,
         | 
| 85 | 
            +
                                                         proxy_user: nil,
         | 
| 86 | 
            +
                                                         proxy_pass: nil,
         | 
| 87 | 
            +
                                                         data_governance: DataGovernance::GLOBAL)
         | 
| 77 88 | 
             
                #
         | 
| 78 89 | 
             
                #   Create an instance of ConfigCatClient and setup Lazy Load mode with custom options
         | 
| 79 90 | 
             
                #
         | 
| 80 | 
            -
                #   :param  | 
| 91 | 
            +
                #   :param sdk_key: ConfigCat SDK Key to access your configuration.
         | 
| 81 92 | 
             
                #   :param cache_time_to_live_seconds: The cache TTL.
         | 
| 82 93 | 
             
                #   :param config_cache_class: If you want to use custom caching instead of the client's default InMemoryConfigCache,
         | 
| 83 94 | 
             
                #   You can provide an implementation of ConfigCache.
         | 
| @@ -86,14 +97,18 @@ module ConfigCat | |
| 86 97 | 
             
                #   :param proxy_port: Proxy port
         | 
| 87 98 | 
             
                #   :param proxy_user: username for proxy authentication
         | 
| 88 99 | 
             
                #   :param proxy_pass: password for proxy authentication
         | 
| 100 | 
            +
                #   :param data_governance:
         | 
| 101 | 
            +
                #   Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
         | 
| 102 | 
            +
                #   https://app.configcat.com/organization/data-governance
         | 
| 103 | 
            +
                #   (Only Organization Admins have access)
         | 
| 89 104 | 
             
                #
         | 
| 90 | 
            -
                if  | 
| 91 | 
            -
                  raise ConfigCatClientException, " | 
| 105 | 
            +
                if sdk_key === nil
         | 
| 106 | 
            +
                  raise ConfigCatClientException, "SDK Key is required."
         | 
| 92 107 | 
             
                end
         | 
| 93 108 | 
             
                if cache_time_to_live_seconds < 1
         | 
| 94 109 | 
             
                  cache_time_to_live_seconds = 1
         | 
| 95 110 | 
             
                end
         | 
| 96 | 
            -
                return ConfigCatClient.new( | 
| 111 | 
            +
                return ConfigCatClient.new(sdk_key,
         | 
| 97 112 | 
             
                                           poll_interval_seconds: 0,
         | 
| 98 113 | 
             
                                           max_init_wait_time_seconds: 0,
         | 
| 99 114 | 
             
                                           on_configuration_changed_callback: nil,
         | 
| @@ -103,20 +118,22 @@ module ConfigCat | |
| 103 118 | 
             
                                           proxy_address: proxy_address,
         | 
| 104 119 | 
             
                                           proxy_port: proxy_port,
         | 
| 105 120 | 
             
                                           proxy_user: proxy_user,
         | 
| 106 | 
            -
                                           proxy_pass: proxy_pass | 
| 121 | 
            +
                                           proxy_pass: proxy_pass,
         | 
| 122 | 
            +
                                           data_governance: data_governance)
         | 
| 107 123 | 
             
              end
         | 
| 108 124 |  | 
| 109 | 
            -
              def ConfigCat.create_client_with_manual_poll( | 
| 125 | 
            +
              def ConfigCat.create_client_with_manual_poll(sdk_key,
         | 
| 110 126 | 
             
                                                           config_cache_class: nil,
         | 
| 111 127 | 
             
                                                           base_url: nil,
         | 
| 112 128 | 
             
                                                           proxy_address:nil,
         | 
| 113 129 | 
             
                                                           proxy_port:nil,
         | 
| 114 130 | 
             
                                                           proxy_user:nil,
         | 
| 115 | 
            -
                                                           proxy_pass:nil | 
| 131 | 
            +
                                                           proxy_pass:nil,
         | 
| 132 | 
            +
                                                           data_governance: DataGovernance::GLOBAL)
         | 
| 116 133 | 
             
                #
         | 
| 117 134 | 
             
                #   Create an instance of ConfigCatClient and setup Manual Poll mode with custom options
         | 
| 118 135 | 
             
                #
         | 
| 119 | 
            -
                #   :param  | 
| 136 | 
            +
                #   :param sdk_key: ConfigCat SDK Key to access your configuration.
         | 
| 120 137 | 
             
                #   :param config_cache_class: If you want to use custom caching instead of the client's default InMemoryConfigCache,
         | 
| 121 138 | 
             
                #   You can provide an implementation of ConfigCache.
         | 
| 122 139 | 
             
                #   :param base_url: You can set a base_url if you want to use a proxy server between your application and ConfigCat
         | 
| @@ -124,11 +141,15 @@ module ConfigCat | |
| 124 141 | 
             
                #   :param proxy_port: Proxy port
         | 
| 125 142 | 
             
                #   :param proxy_user: username for proxy authentication
         | 
| 126 143 | 
             
                #   :param proxy_pass: password for proxy authentication
         | 
| 144 | 
            +
                #   :param data_governance:
         | 
| 145 | 
            +
                #   Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
         | 
| 146 | 
            +
                #   https://app.configcat.com/organization/data-governance
         | 
| 147 | 
            +
                #   (Only Organization Admins have access)
         | 
| 127 148 | 
             
                #
         | 
| 128 | 
            -
                if  | 
| 129 | 
            -
                  raise ConfigCatClientException, " | 
| 149 | 
            +
                if sdk_key === nil
         | 
| 150 | 
            +
                  raise ConfigCatClientException, "SDK Key is required."
         | 
| 130 151 | 
             
                end
         | 
| 131 | 
            -
                return ConfigCatClient.new( | 
| 152 | 
            +
                return ConfigCatClient.new(sdk_key,
         | 
| 132 153 | 
             
                                           poll_interval_seconds: 0,
         | 
| 133 154 | 
             
                                           max_init_wait_time_seconds: 0,
         | 
| 134 155 | 
             
                                           on_configuration_changed_callback: nil,
         | 
| @@ -138,7 +159,8 @@ module ConfigCat | |
| 138 159 | 
             
                                           proxy_address: proxy_address,
         | 
| 139 160 | 
             
                                           proxy_port: proxy_port,
         | 
| 140 161 | 
             
                                           proxy_user: proxy_user,
         | 
| 141 | 
            -
                                           proxy_pass: proxy_pass | 
| 162 | 
            +
                                           proxy_pass: proxy_pass,
         | 
| 163 | 
            +
                                           data_governance: data_governance)
         | 
| 142 164 | 
             
              end
         | 
| 143 165 |  | 
| 144 166 | 
             
            end
         | 
| @@ -1,9 +1,10 @@ | |
| 1 1 | 
             
            require 'configcat/interfaces'
         | 
| 2 | 
            +
            require 'configcat/constants'
         | 
| 2 3 | 
             
            require 'concurrent'
         | 
| 3 4 |  | 
| 4 5 | 
             
            module ConfigCat
         | 
| 5 6 | 
             
              class AutoPollingCachePolicy < CachePolicy
         | 
| 6 | 
            -
                def initialize(config_fetcher, config_cache, poll_interval_seconds=60, max_init_wait_time_seconds=5, on_configuration_changed_callback=nil)
         | 
| 7 | 
            +
                def initialize(config_fetcher, config_cache, cache_key, poll_interval_seconds=60, max_init_wait_time_seconds=5, on_configuration_changed_callback=nil)
         | 
| 7 8 | 
             
                  if poll_interval_seconds < 1
         | 
| 8 9 | 
             
                    poll_interval_seconds = 1
         | 
| 9 10 | 
             
                  end
         | 
| @@ -12,6 +13,7 @@ module ConfigCat | |
| 12 13 | 
             
                  end
         | 
| 13 14 | 
             
                  @_config_fetcher = config_fetcher
         | 
| 14 15 | 
             
                  @_config_cache = config_cache
         | 
| 16 | 
            +
                  @_cache_key = cache_key
         | 
| 15 17 | 
             
                  @_poll_interval_seconds = poll_interval_seconds
         | 
| 16 18 | 
             
                  @_max_init_wait_time_seconds = max_init_wait_time_seconds
         | 
| 17 19 | 
             
                  @_on_configuration_changed_callback = on_configuration_changed_callback
         | 
| @@ -40,7 +42,7 @@ module ConfigCat | |
| 40 42 | 
             
                  end
         | 
| 41 43 | 
             
                  begin
         | 
| 42 44 | 
             
                    @_lock.acquire_read_lock()
         | 
| 43 | 
            -
                    return @_config_cache.get()
         | 
| 45 | 
            +
                    return @_config_cache.get(@_cache_key)
         | 
| 44 46 | 
             
                  ensure
         | 
| 45 47 | 
             
                    @_lock.release_read_lock()
         | 
| 46 48 | 
             
                  end
         | 
| @@ -48,29 +50,32 @@ module ConfigCat | |
| 48 50 |  | 
| 49 51 | 
             
                def force_refresh()
         | 
| 50 52 | 
             
                  begin
         | 
| 51 | 
            -
                     | 
| 53 | 
            +
                    configuration_response = @_config_fetcher.get_configuration_json()
         | 
| 52 54 |  | 
| 53 55 | 
             
                    begin
         | 
| 54 56 | 
             
                      @_lock.acquire_read_lock()
         | 
| 55 | 
            -
                      old_configuration = @_config_cache.get()
         | 
| 57 | 
            +
                      old_configuration = @_config_cache.get(@_cache_key)
         | 
| 56 58 | 
             
                    ensure
         | 
| 57 59 | 
             
                      @_lock.release_read_lock()
         | 
| 58 60 | 
             
                    end
         | 
| 59 61 |  | 
| 60 | 
            -
                    if  | 
| 61 | 
            -
                       | 
| 62 | 
            -
             | 
| 63 | 
            -
                         | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
                         | 
| 70 | 
            -
             | 
| 62 | 
            +
                    if configuration_response.is_fetched()
         | 
| 63 | 
            +
                      configuration = configuration_response.json()
         | 
| 64 | 
            +
                      if configuration != old_configuration
         | 
| 65 | 
            +
                        begin
         | 
| 66 | 
            +
                          @_lock.acquire_write_lock()
         | 
| 67 | 
            +
                          @_config_cache.set(@_cache_key, configuration)
         | 
| 68 | 
            +
                          @_initialized = true
         | 
| 69 | 
            +
                        ensure
         | 
| 70 | 
            +
                          @_lock.release_write_lock()
         | 
| 71 | 
            +
                        end
         | 
| 72 | 
            +
                        begin
         | 
| 73 | 
            +
                          if !@_on_configuration_changed_callback.equal?(nil)
         | 
| 74 | 
            +
                            @_on_configuration_changed_callback.()
         | 
| 75 | 
            +
                          end
         | 
| 76 | 
            +
                        rescue Exception => e
         | 
| 77 | 
            +
                          ConfigCat.logger.error("Exception in on_configuration_changed_callback: #{e.class}:'#{e}'")
         | 
| 71 78 | 
             
                        end
         | 
| 72 | 
            -
                      rescue Exception => e
         | 
| 73 | 
            -
                        ConfigCat.logger.error("Exception in on_configuration_changed_callback: #{e.class}:'#{e}'")
         | 
| 74 79 | 
             
                      end
         | 
| 75 80 | 
             
                    end
         | 
| 76 81 |  | 
| @@ -78,7 +83,7 @@ module ConfigCat | |
| 78 83 | 
             
                      @_initialized = true
         | 
| 79 84 | 
             
                    end
         | 
| 80 85 | 
             
                  rescue Exception => e
         | 
| 81 | 
            -
                    ConfigCat.logger.error("Double-check your  | 
| 86 | 
            +
                    ConfigCat.logger.error("Double-check your SDK Key at https://app.configcat.com/sdkkey.")
         | 
| 82 87 | 
             
                    ConfigCat.logger.error "threw exception #{e.class}:'#{e}'"
         | 
| 83 88 | 
             
                    ConfigCat.logger.error "stacktrace: #{e.backtrace}"
         | 
| 84 89 | 
             
                  end
         | 
| @@ -3,15 +3,15 @@ require 'configcat/interfaces' | |
| 3 3 | 
             
            module ConfigCat
         | 
| 4 4 | 
             
              class InMemoryConfigCache < ConfigCache
         | 
| 5 5 | 
             
                def initialize()
         | 
| 6 | 
            -
                  @_value =  | 
| 6 | 
            +
                  @_value = {}
         | 
| 7 7 | 
             
                end
         | 
| 8 8 |  | 
| 9 | 
            -
                def get()
         | 
| 10 | 
            -
                  return @_value
         | 
| 9 | 
            +
                def get(key)
         | 
| 10 | 
            +
                  return @_value.fetch(key, nil)
         | 
| 11 11 | 
             
                end
         | 
| 12 12 |  | 
| 13 | 
            -
                def set(value)
         | 
| 14 | 
            -
                  @_value = value
         | 
| 13 | 
            +
                def set(key, value)
         | 
| 14 | 
            +
                  @_value[key] = value
         | 
| 15 15 | 
             
                end
         | 
| 16 16 | 
             
              end
         | 
| 17 17 | 
             
            end
         | 
| @@ -5,10 +5,12 @@ require 'configcat/autopollingcachepolicy' | |
| 5 5 | 
             
            require 'configcat/manualpollingcachepolicy'
         | 
| 6 6 | 
             
            require 'configcat/lazyloadingcachepolicy'
         | 
| 7 7 | 
             
            require 'configcat/rolloutevaluator'
         | 
| 8 | 
            +
            require 'configcat/datagovernance'
         | 
| 8 9 |  | 
| 9 10 | 
             
            module ConfigCat
         | 
| 11 | 
            +
              KeyValue = Struct.new(:key, :value)
         | 
| 10 12 | 
             
              class ConfigCatClient
         | 
| 11 | 
            -
                def initialize( | 
| 13 | 
            +
                def initialize(sdk_key,
         | 
| 12 14 | 
             
                               poll_interval_seconds:60,
         | 
| 13 15 | 
             
                               max_init_wait_time_seconds:5,
         | 
| 14 16 | 
             
                               on_configuration_changed_callback:nil,
         | 
| @@ -18,11 +20,12 @@ module ConfigCat | |
| 18 20 | 
             
                               proxy_address:nil,
         | 
| 19 21 | 
             
                               proxy_port:nil,
         | 
| 20 22 | 
             
                               proxy_user:nil,
         | 
| 21 | 
            -
                               proxy_pass:nil | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 23 | 
            +
                               proxy_pass:nil,
         | 
| 24 | 
            +
                               data_governance: DataGovernance::GLOBAL)
         | 
| 25 | 
            +
                  if sdk_key === nil
         | 
| 26 | 
            +
                    raise ConfigCatClientException, "SDK Key is required."
         | 
| 24 27 | 
             
                  end
         | 
| 25 | 
            -
                  @ | 
| 28 | 
            +
                  @_sdk_key = sdk_key
         | 
| 26 29 |  | 
| 27 30 | 
             
                  if config_cache_class
         | 
| 28 31 | 
             
                    @_config_cache = config_cache_class.new()
         | 
| @@ -31,15 +34,15 @@ module ConfigCat | |
| 31 34 | 
             
                  end
         | 
| 32 35 |  | 
| 33 36 | 
             
                  if poll_interval_seconds > 0
         | 
| 34 | 
            -
                    @_config_fetcher = CacheControlConfigFetcher.new( | 
| 35 | 
            -
                    @_cache_policy = AutoPollingCachePolicy.new(@_config_fetcher, @_config_cache, poll_interval_seconds, max_init_wait_time_seconds, on_configuration_changed_callback)
         | 
| 37 | 
            +
                    @_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "p", base_url, proxy_address, proxy_port, proxy_user, proxy_pass, data_governance)
         | 
| 38 | 
            +
                    @_cache_policy = AutoPollingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key(), poll_interval_seconds, max_init_wait_time_seconds, on_configuration_changed_callback)
         | 
| 36 39 | 
             
                  else
         | 
| 37 40 | 
             
                    if cache_time_to_live_seconds > 0
         | 
| 38 | 
            -
                      @_config_fetcher = CacheControlConfigFetcher.new( | 
| 39 | 
            -
                      @_cache_policy = LazyLoadingCachePolicy.new(@_config_fetcher, @_config_cache, cache_time_to_live_seconds)
         | 
| 41 | 
            +
                      @_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "l", base_url, proxy_address, proxy_port, proxy_user, proxy_pass, data_governance)
         | 
| 42 | 
            +
                      @_cache_policy = LazyLoadingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key(), cache_time_to_live_seconds)
         | 
| 40 43 | 
             
                    else
         | 
| 41 | 
            -
                      @_config_fetcher = CacheControlConfigFetcher.new( | 
| 42 | 
            -
                      @_cache_policy = ManualPollingCachePolicy.new(@_config_fetcher, @_config_cache)
         | 
| 44 | 
            +
                      @_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "m", base_url, proxy_address, proxy_port, proxy_user, proxy_pass, data_governance)
         | 
| 45 | 
            +
                      @_cache_policy = ManualPollingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key())
         | 
| 43 46 | 
             
                    end
         | 
| 44 47 | 
             
                  end
         | 
| 45 48 | 
             
                end
         | 
| @@ -49,7 +52,8 @@ module ConfigCat | |
| 49 52 | 
             
                  if config === nil
         | 
| 50 53 | 
             
                    return default_value
         | 
| 51 54 | 
             
                  end
         | 
| 52 | 
            -
                   | 
| 55 | 
            +
                  value, variation_id = RolloutEvaluator.evaluate(key, user, default_value, nil, config)
         | 
| 56 | 
            +
                  return value
         | 
| 53 57 | 
             
                end
         | 
| 54 58 |  | 
| 55 59 | 
             
                def get_all_keys()
         | 
| @@ -57,7 +61,69 @@ module ConfigCat | |
| 57 61 | 
             
                  if config === nil
         | 
| 58 62 | 
             
                    return []
         | 
| 59 63 | 
             
                  end
         | 
| 60 | 
            -
                   | 
| 64 | 
            +
                  feature_flags = config.fetch(FEATURE_FLAGS, nil)
         | 
| 65 | 
            +
                  if feature_flags === nil
         | 
| 66 | 
            +
                    return []
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                  return feature_flags.keys
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                def get_variation_id(key, default_variation_id, user=nil)
         | 
| 72 | 
            +
                  config = @_cache_policy.get()
         | 
| 73 | 
            +
                  if config === nil
         | 
| 74 | 
            +
                    ConfigCat.logger.warn("Evaluating get_variation_id('%s') failed. Cache is empty. "\
         | 
| 75 | 
            +
                                          "Returning default_variation_id in your get_variation_id call: [%s]." %
         | 
| 76 | 
            +
                                          [key, default_variation_id.to_s])
         | 
| 77 | 
            +
                    return default_variation_id
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                  value, variation_id = RolloutEvaluator.evaluate(key, user, nil, default_variation_id, config)
         | 
| 80 | 
            +
                  return variation_id
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                def get_all_variation_ids(user: nil)
         | 
| 84 | 
            +
                  keys = get_all_keys()
         | 
| 85 | 
            +
                  variation_ids = []
         | 
| 86 | 
            +
                  for key in keys
         | 
| 87 | 
            +
                    variation_id = get_variation_id(key, nil, user)
         | 
| 88 | 
            +
                    if !variation_id.equal?(nil)
         | 
| 89 | 
            +
                      variation_ids.push(variation_id)
         | 
| 90 | 
            +
                    end
         | 
| 91 | 
            +
                  end
         | 
| 92 | 
            +
                  return variation_ids
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                def get_key_and_value(variation_id)
         | 
| 96 | 
            +
                  config = @_cache_policy.get()
         | 
| 97 | 
            +
                  if config === nil
         | 
| 98 | 
            +
                    ConfigCat.logger.warn("Evaluating get_variation_id('%s') failed. Cache is empty. Returning nil." % variation_id)
         | 
| 99 | 
            +
                    return nil
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  feature_flags = config.fetch(FEATURE_FLAGS, nil)
         | 
| 103 | 
            +
                  if feature_flags === nil
         | 
| 104 | 
            +
                    ConfigCat.logger.warn("Evaluating get_key_and_value('%s') failed. Cache is empty. Returning None." % variation_id)
         | 
| 105 | 
            +
                    return nil
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  for key, value in feature_flags
         | 
| 109 | 
            +
                    if variation_id == value.fetch(VARIATION_ID, nil)
         | 
| 110 | 
            +
                      return KeyValue.new(key, value[VALUE])
         | 
| 111 | 
            +
                    end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                    rollout_rules = value.fetch(ROLLOUT_RULES, [])
         | 
| 114 | 
            +
                    for rollout_rule in rollout_rules
         | 
| 115 | 
            +
                      if variation_id == rollout_rule.fetch(VARIATION_ID, nil)
         | 
| 116 | 
            +
                        return KeyValue.new(key, rollout_rule[VALUE])
         | 
| 117 | 
            +
                      end
         | 
| 118 | 
            +
                    end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                    rollout_percentage_items = value.fetch(ROLLOUT_PERCENTAGE_ITEMS, [])
         | 
| 121 | 
            +
                    for rollout_percentage_item in rollout_percentage_items
         | 
| 122 | 
            +
                      if variation_id == rollout_percentage_item.fetch(VARIATION_ID, nil)
         | 
| 123 | 
            +
                        return KeyValue.new(key, rollout_percentage_item[VALUE])
         | 
| 124 | 
            +
                      end
         | 
| 125 | 
            +
                    end
         | 
| 126 | 
            +
                  end
         | 
| 61 127 | 
             
                end
         | 
| 62 128 |  | 
| 63 129 | 
             
                def force_refresh()
         | 
| @@ -69,5 +135,11 @@ module ConfigCat | |
| 69 135 | 
             
                  @_config_fetcher.close()
         | 
| 70 136 | 
             
                end
         | 
| 71 137 |  | 
| 138 | 
            +
                private
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                def _get_cache_key()
         | 
| 141 | 
            +
                  return Digest::SHA1.hexdigest("ruby_" + CONFIG_FILE_NAME + "_" + @_sdk_key)
         | 
| 142 | 
            +
                end
         | 
| 143 | 
            +
             | 
| 72 144 | 
             
              end
         | 
| 73 145 | 
             
            end
         | 
| @@ -1,41 +1,129 @@ | |
| 1 1 | 
             
            require 'configcat/interfaces'
         | 
| 2 2 | 
             
            require 'configcat/version'
         | 
| 3 | 
            +
            require 'configcat/datagovernance'
         | 
| 4 | 
            +
            require 'configcat/constants'
         | 
| 3 5 | 
             
            require 'net/http'
         | 
| 4 6 | 
             
            require 'uri'
         | 
| 5 7 | 
             
            require 'json'
         | 
| 6 8 |  | 
| 7 9 | 
             
            module ConfigCat
         | 
| 8 | 
            -
               | 
| 10 | 
            +
              BASE_URL_GLOBAL = "https://cdn-global.configcat.com"
         | 
| 11 | 
            +
              BASE_URL_EU_ONLY = "https://cdn-eu.configcat.com"
         | 
| 9 12 | 
             
              BASE_PATH = "configuration-files/"
         | 
| 10 | 
            -
              BASE_EXTENSION = "/ | 
| 13 | 
            +
              BASE_EXTENSION = "/" + CONFIG_FILE_NAME + ".json"
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              class RedirectMode
         | 
| 16 | 
            +
                NO_REDIRECT = 0
         | 
| 17 | 
            +
                SHOULD_REDIRECT = 1
         | 
| 18 | 
            +
                FORCE_REDIRECT = 2
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              class FetchResponse
         | 
| 22 | 
            +
                def initialize(response)
         | 
| 23 | 
            +
                  @_response = response
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                # Returns the json-encoded content of a response, if any
         | 
| 27 | 
            +
                def json()
         | 
| 28 | 
            +
                  return JSON.parse(@_response.body)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                # Gets whether a new configuration value was fetched or not
         | 
| 32 | 
            +
                def is_fetched()
         | 
| 33 | 
            +
                  code = @_response.code.to_i
         | 
| 34 | 
            +
                  return 200 <= code && code < 300
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                # Gets whether the fetch resulted a '304 Not Modified' or not
         | 
| 38 | 
            +
                def is_not_modified()
         | 
| 39 | 
            +
                  return @_response.code == "304"
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
              end
         | 
| 11 42 |  | 
| 12 43 | 
             
              class CacheControlConfigFetcher < ConfigFetcher
         | 
| 13 | 
            -
                def initialize( | 
| 14 | 
            -
             | 
| 15 | 
            -
                  @ | 
| 44 | 
            +
                def initialize(sdk_key, mode, base_url=nil, proxy_address=nil, proxy_port=nil, proxy_user=nil, proxy_pass=nil,
         | 
| 45 | 
            +
                               data_governance=DataGovernance::GLOBAL)
         | 
| 46 | 
            +
                  @_sdk_key = sdk_key
         | 
| 47 | 
            +
                  @_proxy_address = proxy_address
         | 
| 48 | 
            +
                  @_proxy_port = proxy_port
         | 
| 49 | 
            +
                  @_proxy_user = proxy_user
         | 
| 50 | 
            +
                  @_proxy_pass = proxy_pass
         | 
| 51 | 
            +
                  @_etag = ""
         | 
| 16 52 | 
             
                  @_headers = {"User-Agent" => ((("ConfigCat-Ruby/") + mode) + ("-")) + VERSION, "X-ConfigCat-UserAgent" => ((("ConfigCat-Ruby/") + mode) + ("-")) + VERSION, "Content-Type" => "application/json"}
         | 
| 17 53 | 
             
                  if !base_url.equal?(nil)
         | 
| 54 | 
            +
                    @_base_url_overridden = true
         | 
| 18 55 | 
             
                    @_base_url = base_url.chomp("/")
         | 
| 19 56 | 
             
                  else
         | 
| 20 | 
            -
                    @ | 
| 57 | 
            +
                    @_base_url_overridden = false
         | 
| 58 | 
            +
                    if data_governance == DataGovernance::EU_ONLY
         | 
| 59 | 
            +
                      @_base_url = BASE_URL_EU_ONLY
         | 
| 60 | 
            +
                    else
         | 
| 61 | 
            +
                      @_base_url = BASE_URL_GLOBAL
         | 
| 62 | 
            +
                    end
         | 
| 21 63 | 
             
                  end
         | 
| 22 | 
            -
                  uri = URI.parse(@_base_url)
         | 
| 23 | 
            -
                  @_http = Net::HTTP.new(uri.host, uri.port, proxy_address, proxy_port, proxy_user, proxy_pass)
         | 
| 24 | 
            -
                  @_http.use_ssl = true if uri.scheme == 'https'
         | 
| 25 | 
            -
                  @_http.open_timeout = 10 # in seconds
         | 
| 26 | 
            -
                  @_http.read_timeout = 30 # in seconds
         | 
| 27 64 | 
             
                end
         | 
| 28 65 |  | 
| 29 | 
            -
                 | 
| 66 | 
            +
                # Returns the FetchResponse object contains configuration json Dictionary
         | 
| 67 | 
            +
                def get_configuration_json(retries=0)
         | 
| 30 68 | 
             
                  ConfigCat.logger.debug "Fetching configuration from ConfigCat"
         | 
| 31 | 
            -
                  uri = URI.parse((((@_base_url + ("/")) + BASE_PATH) + @ | 
| 32 | 
            -
                   | 
| 33 | 
            -
                   | 
| 69 | 
            +
                  uri = URI.parse((((@_base_url + ("/")) + BASE_PATH) + @_sdk_key) + BASE_EXTENSION)
         | 
| 70 | 
            +
                  headers = @_headers
         | 
| 71 | 
            +
                  headers["If-None-Match"] = @_etag unless @_etag.empty?
         | 
| 72 | 
            +
                  _create_http()
         | 
| 73 | 
            +
                  request = Net::HTTP::Get.new(uri.request_uri, headers)
         | 
| 34 74 | 
             
                  response = @_http.request(request)
         | 
| 35 | 
            -
                   | 
| 36 | 
            -
                  @_etag =  | 
| 75 | 
            +
                  etag = response["ETag"]
         | 
| 76 | 
            +
                  @_etag = etag unless etag.nil? || etag.empty?
         | 
| 37 77 | 
             
                  ConfigCat.logger.debug "ConfigCat configuration json fetch response code:#{response.code} Cached:#{response['ETag']}"
         | 
| 38 | 
            -
                   | 
| 78 | 
            +
                  fetch_response = FetchResponse.new(response)
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  # If there wasn't a config change, we return the response.
         | 
| 81 | 
            +
                  if !fetch_response.is_fetched()
         | 
| 82 | 
            +
                    return fetch_response
         | 
| 83 | 
            +
                  end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                  preferences = fetch_response.json().fetch(PREFERENCES, nil)
         | 
| 86 | 
            +
                  if preferences === nil
         | 
| 87 | 
            +
                    return fetch_response
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  base_url = preferences.fetch(BASE_URL, nil)
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                  # If the base_url is the same as the last called one, just return the response.
         | 
| 93 | 
            +
                  if base_url.equal?(nil) || @_base_url == base_url
         | 
| 94 | 
            +
                    return fetch_response
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                  redirect = preferences.fetch(REDIRECT, nil)
         | 
| 98 | 
            +
                  # If the base_url is overridden, and the redirect parameter is not 2 (force),
         | 
| 99 | 
            +
                  # the SDK should not redirect the calls and it just have to return the response.
         | 
| 100 | 
            +
                  if @_base_url_overridden && redirect != RedirectMode::FORCE_REDIRECT
         | 
| 101 | 
            +
                    return fetch_response
         | 
| 102 | 
            +
                  end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                  # The next call should use the base_url provided in the config json
         | 
| 105 | 
            +
                  @_base_url = base_url
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  # If the redirect property == 0 (redirect not needed), return the response
         | 
| 108 | 
            +
                  if redirect == RedirectMode::NO_REDIRECT
         | 
| 109 | 
            +
                    # Return the response
         | 
| 110 | 
            +
                    return fetch_response
         | 
| 111 | 
            +
                  end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                  # Try to download again with the new url
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                  if redirect == RedirectMode::SHOULD_REDIRECT
         | 
| 116 | 
            +
                    ConfigCat.logger.warn("Your data_governance parameter at ConfigCatClient initialization is not in sync with your preferences on the ConfigCat Dashboard: https://app.configcat.com/organization/data-governance. Only Organization Admins can set this preference.")
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  # To prevent loops we check if we retried at least 3 times with the new base_url
         | 
| 120 | 
            +
                  if retries >= 2
         | 
| 121 | 
            +
                    ConfigCat.logger.error("Redirect loop during config.json fetch. Please contact support@configcat.com.")
         | 
| 122 | 
            +
                    return fetch_response
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                  # Retry the config download with the new base_url
         | 
| 126 | 
            +
                  return get_configuration_json(retries + 1)
         | 
| 39 127 | 
             
                end
         | 
| 40 128 |  | 
| 41 129 | 
             
                def close()
         | 
| @@ -43,5 +131,19 @@ module ConfigCat | |
| 43 131 | 
             
                    @_http = nil
         | 
| 44 132 | 
             
                  end
         | 
| 45 133 | 
             
                end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                private
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                def _create_http()
         | 
| 138 | 
            +
                  uri = URI.parse(@_base_url)
         | 
| 139 | 
            +
                  use_ssl = true if uri.scheme == 'https'
         | 
| 140 | 
            +
                  if @_http.equal?(nil) || @_http.address != uri.host || @_http.port != uri.port || @_http.use_ssl? != use_ssl
         | 
| 141 | 
            +
                    close()
         | 
| 142 | 
            +
                    @_http = Net::HTTP.new(uri.host, uri.port, @_proxy_address, @_proxy_port, @_proxy_user, @_proxy_pass)
         | 
| 143 | 
            +
                    @_http.use_ssl = use_ssl
         | 
| 144 | 
            +
                    @_http.open_timeout = 10 # in seconds
         | 
| 145 | 
            +
                    @_http.read_timeout = 30 # in seconds
         | 
| 146 | 
            +
                  end
         | 
| 147 | 
            +
                end
         | 
| 46 148 | 
             
              end
         | 
| 47 149 | 
             
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            module ConfigCat
         | 
| 2 | 
            +
              CONFIG_FILE_NAME = "config_v5"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              PREFERENCES = "p"
         | 
| 5 | 
            +
              BASE_URL = "u"
         | 
| 6 | 
            +
              REDIRECT = "r"
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              FEATURE_FLAGS = "f"
         | 
| 9 | 
            +
              VALUE = "v"
         | 
| 10 | 
            +
              COMPARATOR = "t"
         | 
| 11 | 
            +
              COMPARISON_ATTRIBUTE = "a"
         | 
| 12 | 
            +
              COMPARISON_VALUE = "c"
         | 
| 13 | 
            +
              ROLLOUT_PERCENTAGE_ITEMS = "p"
         | 
| 14 | 
            +
              PERCENTAGE = "p"
         | 
| 15 | 
            +
              ROLLOUT_RULES = "r"
         | 
| 16 | 
            +
              VARIATION_ID = "i"
         | 
| 17 | 
            +
            end
         | 
| @@ -0,0 +1,10 @@ | |
| 1 | 
            +
            module ConfigCat
         | 
| 2 | 
            +
              class DataGovernance
         | 
| 3 | 
            +
                # Control the location of the config.json files containing your feature flags
         | 
| 4 | 
            +
                # and settings within the ConfigCat CDN.
         | 
| 5 | 
            +
                # Global: Select this if your feature flags are published to all global CDN nodes.
         | 
| 6 | 
            +
                # EuOnly: Select this if your feature flags are published to CDN nodes only in the EU.
         | 
| 7 | 
            +
                GLOBAL = 0
         | 
| 8 | 
            +
                EU_ONLY = 1
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
            end
         | 
    
        data/lib/configcat/interfaces.rb
    CHANGED
    
    
| @@ -1,15 +1,18 @@ | |
| 1 1 | 
             
            require 'configcat/interfaces'
         | 
| 2 | 
            +
            require 'configcat/constants'
         | 
| 2 3 | 
             
            require 'concurrent'
         | 
| 3 4 |  | 
| 5 | 
            +
             | 
| 4 6 | 
             
            module ConfigCat
         | 
| 5 7 | 
             
              class LazyLoadingCachePolicy < CachePolicy
         | 
| 6 8 |  | 
| 7 | 
            -
                def initialize(config_fetcher, config_cache, cache_time_to_live_seconds=60)
         | 
| 9 | 
            +
                def initialize(config_fetcher, config_cache, cache_key, cache_time_to_live_seconds=60)
         | 
| 8 10 | 
             
                  if cache_time_to_live_seconds < 1
         | 
| 9 11 | 
             
                    cache_time_to_live_seconds = 1
         | 
| 10 12 | 
             
                  end
         | 
| 11 13 | 
             
                  @_config_fetcher = config_fetcher
         | 
| 12 14 | 
             
                  @_config_cache = config_cache
         | 
| 15 | 
            +
                  @_cache_key = cache_key
         | 
| 13 16 | 
             
                  @_cache_time_to_live = cache_time_to_live_seconds
         | 
| 14 17 | 
             
                  @_lock = Concurrent::ReadWriteLock.new()
         | 
| 15 18 | 
             
                  @_last_updated = nil
         | 
| @@ -20,7 +23,7 @@ module ConfigCat | |
| 20 23 | 
             
                    @_lock.acquire_read_lock()
         | 
| 21 24 | 
             
                    utc_now = Time.now.utc
         | 
| 22 25 | 
             
                    if !@_last_updated.equal?(nil) && (@_last_updated + @_cache_time_to_live > utc_now)
         | 
| 23 | 
            -
                      config = @_config_cache.get()
         | 
| 26 | 
            +
                      config = @_config_cache.get(@_cache_key)
         | 
| 24 27 | 
             
                      if !config.equal?(nil)
         | 
| 25 28 | 
             
                        return config
         | 
| 26 29 | 
             
                      end
         | 
| @@ -31,7 +34,7 @@ module ConfigCat | |
| 31 34 | 
             
                  force_refresh()
         | 
| 32 35 | 
             
                  begin
         | 
| 33 36 | 
             
                    @_lock.acquire_read_lock()
         | 
| 34 | 
            -
                    config = @_config_cache.get()
         | 
| 37 | 
            +
                    config = @_config_cache.get(@_cache_key)
         | 
| 35 38 | 
             
                    return config
         | 
| 36 39 | 
             
                  ensure
         | 
| 37 40 | 
             
                    @_lock.release_read_lock()
         | 
| @@ -40,16 +43,19 @@ module ConfigCat | |
| 40 43 |  | 
| 41 44 | 
             
                def force_refresh()
         | 
| 42 45 | 
             
                  begin
         | 
| 43 | 
            -
                     | 
| 44 | 
            -
                     | 
| 45 | 
            -
                       | 
| 46 | 
            -
                       | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 46 | 
            +
                    configuration_response = @_config_fetcher.get_configuration_json()
         | 
| 47 | 
            +
                    if configuration_response.is_fetched()
         | 
| 48 | 
            +
                      configuration = configuration_response.json()
         | 
| 49 | 
            +
                      begin
         | 
| 50 | 
            +
                        @_lock.acquire_write_lock()
         | 
| 51 | 
            +
                        @_config_cache.set(@_cache_key, configuration)
         | 
| 52 | 
            +
                        @_last_updated = Time.now.utc
         | 
| 53 | 
            +
                      ensure
         | 
| 54 | 
            +
                        @_lock.release_write_lock()
         | 
| 55 | 
            +
                      end
         | 
| 50 56 | 
             
                    end
         | 
| 51 57 | 
             
                  rescue StandardError => e
         | 
| 52 | 
            -
                    ConfigCat.logger.error("Double-check your  | 
| 58 | 
            +
                    ConfigCat.logger.error("Double-check your SDK Key at https://app.configcat.com/sdkkey.")
         | 
| 53 59 | 
             
                    ConfigCat.logger.error "threw exception #{e.class}:'#{e}'"
         | 
| 54 60 | 
             
                    ConfigCat.logger.error "stacktrace: #{e.backtrace}"
         | 
| 55 61 | 
             
                  end
         | 
| @@ -1,18 +1,20 @@ | |
| 1 1 | 
             
            require 'configcat/interfaces'
         | 
| 2 | 
            +
            require 'configcat/constants'
         | 
| 2 3 | 
             
            require 'concurrent'
         | 
| 3 4 |  | 
| 4 5 | 
             
            module ConfigCat
         | 
| 5 6 | 
             
              class ManualPollingCachePolicy < CachePolicy
         | 
| 6 | 
            -
                def initialize(config_fetcher, config_cache)
         | 
| 7 | 
            +
                def initialize(config_fetcher, config_cache, cache_key)
         | 
| 7 8 | 
             
                  @_config_fetcher = config_fetcher
         | 
| 8 9 | 
             
                  @_config_cache = config_cache
         | 
| 10 | 
            +
                  @_cache_key = cache_key
         | 
| 9 11 | 
             
                  @_lock = Concurrent::ReadWriteLock.new()
         | 
| 10 12 | 
             
                end
         | 
| 11 13 |  | 
| 12 14 | 
             
                def get()
         | 
| 13 15 | 
             
                  begin
         | 
| 14 16 | 
             
                    @_lock.acquire_read_lock()
         | 
| 15 | 
            -
                    config = @_config_cache.get()
         | 
| 17 | 
            +
                    config = @_config_cache.get(@_cache_key)
         | 
| 16 18 | 
             
                    return config
         | 
| 17 19 | 
             
                  ensure
         | 
| 18 20 | 
             
                    @_lock.release_read_lock()
         | 
| @@ -21,15 +23,18 @@ module ConfigCat | |
| 21 23 |  | 
| 22 24 | 
             
                def force_refresh()
         | 
| 23 25 | 
             
                  begin
         | 
| 24 | 
            -
                     | 
| 25 | 
            -
                     | 
| 26 | 
            -
                       | 
| 27 | 
            -
                       | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 26 | 
            +
                    configuration_response = @_config_fetcher.get_configuration_json()
         | 
| 27 | 
            +
                    if configuration_response.is_fetched()
         | 
| 28 | 
            +
                      configuration = configuration_response.json()
         | 
| 29 | 
            +
                      begin
         | 
| 30 | 
            +
                        @_lock.acquire_write_lock()
         | 
| 31 | 
            +
                        @_config_cache.set(@_cache_key, configuration)
         | 
| 32 | 
            +
                      ensure
         | 
| 33 | 
            +
                        @_lock.release_write_lock()
         | 
| 34 | 
            +
                      end
         | 
| 30 35 | 
             
                    end
         | 
| 31 36 | 
             
                  rescue StandardError => e
         | 
| 32 | 
            -
                    ConfigCat.logger.error("Double-check your  | 
| 37 | 
            +
                    ConfigCat.logger.error("Double-check your SDK Key at https://app.configcat.com/sdkkey.")
         | 
| 33 38 | 
             
                    ConfigCat.logger.error "threw exception #{e.class}:'#{e}'"
         | 
| 34 39 | 
             
                    ConfigCat.logger.error "stacktrace: #{e.backtrace}"
         | 
| 35 40 | 
             
                  end
         | 
| @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            require 'configcat/user'
         | 
| 2 | 
            +
            require 'configcat/constants'
         | 
| 2 3 | 
             
            require 'digest'
         | 
| 3 4 | 
             
            require 'semantic'
         | 
| 4 5 |  | 
| @@ -6,21 +7,19 @@ module ConfigCat | |
| 6 7 | 
             
              class RolloutEvaluator
         | 
| 7 8 | 
             
                COMPARATOR_TEXTS = ["IS ONE OF", "IS NOT ONE OF", "CONTAINS", "DOES NOT CONTAIN", "IS ONE OF (SemVer)", "IS NOT ONE OF (SemVer)", "< (SemVer)", "<= (SemVer)", "> (SemVer)", ">= (SemVer)", "= (Number)", "<> (Number)", "< (Number)", "<= (Number)", "> (Number)", ">= (Number)"]
         | 
| 8 9 |  | 
| 9 | 
            -
                 | 
| 10 | 
            -
                COMPARATOR = "t"
         | 
| 11 | 
            -
                COMPARISON_ATTRIBUTE = "a"
         | 
| 12 | 
            -
                COMPARISON_VALUE = "c"
         | 
| 13 | 
            -
                ROLLOUT_PERCENTAGE_ITEMS = "p"
         | 
| 14 | 
            -
                PERCENTAGE = "p"
         | 
| 15 | 
            -
                ROLLOUT_RULES = "r"
         | 
| 16 | 
            -
             | 
| 17 | 
            -
                def self.evaluate(key, user, default_value, config)
         | 
| 10 | 
            +
                def self.evaluate(key, user, default_value, default_variation_id, config)
         | 
| 18 11 | 
             
                  ConfigCat.logger.info("Evaluating get_value('%s')." % key)
         | 
| 19 12 |  | 
| 20 | 
            -
                   | 
| 13 | 
            +
                  feature_flags = config.fetch(FEATURE_FLAGS, nil)
         | 
| 14 | 
            +
                  if feature_flags === nil
         | 
| 15 | 
            +
                    ConfigCat.logger.error("Evaluating get_value('%s') failed. Value not found for key '%s' Returning default_value: [%s]." % [key, key, default_value.to_s])
         | 
| 16 | 
            +
                    return default_value, default_variation_id
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  setting_descriptor = feature_flags.fetch(key, nil)
         | 
| 21 20 | 
             
                  if setting_descriptor === nil
         | 
| 22 | 
            -
                    ConfigCat.logger.error("Evaluating get_value('%s') failed. Value not found for key '%s'. Returning default_value: [%s]. Here are the available keys: %s" % [key, key, default_value.to_s,  | 
| 23 | 
            -
                    return default_value
         | 
| 21 | 
            +
                    ConfigCat.logger.error("Evaluating get_value('%s') failed. Value not found for key '%s'. Returning default_value: [%s]. Here are the available keys: %s" % [key, key, default_value.to_s, feature_flags.keys.join(", ")])
         | 
| 22 | 
            +
                    return default_value, default_variation_id
         | 
| 24 23 | 
             
                  end
         | 
| 25 24 |  | 
| 26 25 | 
             
                  rollout_rules = setting_descriptor.fetch(ROLLOUT_RULES, [])
         | 
| @@ -35,8 +34,9 @@ module ConfigCat | |
| 35 34 | 
             
                      ConfigCat.logger.warn("Evaluating get_value('%s'). UserObject missing! You should pass a UserObject to get_value(), in order to make targeting work properly. Read more: https://configcat.com/docs/advanced/user-object/" % key)
         | 
| 36 35 | 
             
                    end
         | 
| 37 36 | 
             
                    return_value = setting_descriptor.fetch(VALUE, default_value)
         | 
| 37 | 
            +
                    return_variation_id = setting_descriptor.fetch(VARIATION_ID, default_variation_id)
         | 
| 38 38 | 
             
                    ConfigCat.logger.info("Returning [%s]" % return_value.to_s)
         | 
| 39 | 
            -
                    return return_value
         | 
| 39 | 
            +
                    return return_value, return_variation_id
         | 
| 40 40 | 
             
                  end
         | 
| 41 41 |  | 
| 42 42 | 
             
                  ConfigCat.logger.info("User object:\n%s" % user.to_s)
         | 
| @@ -54,30 +54,31 @@ module ConfigCat | |
| 54 54 | 
             
                    end
         | 
| 55 55 |  | 
| 56 56 | 
             
                    value = rollout_rule.fetch(VALUE, nil)
         | 
| 57 | 
            +
                    variation_id = rollout_rule.fetch(VARIATION_ID, default_variation_id)
         | 
| 57 58 |  | 
| 58 59 | 
             
                    # IS ONE OF
         | 
| 59 60 | 
             
                    if comparator == 0
         | 
| 60 61 | 
             
                      if comparison_value.to_s.split(",").map { |x| x.strip() }.include?(user_value.to_s)
         | 
| 61 62 | 
             
                        ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
         | 
| 62 | 
            -
                        return value
         | 
| 63 | 
            +
                        return value, variation_id
         | 
| 63 64 | 
             
                      end
         | 
| 64 65 | 
             
                    # IS NOT ONE OF
         | 
| 65 66 | 
             
                    elsif comparator == 1
         | 
| 66 67 | 
             
                      if !comparison_value.to_s.split(",").map { |x| x.strip() }.include?(user_value.to_s)
         | 
| 67 68 | 
             
                        ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
         | 
| 68 | 
            -
                        return value
         | 
| 69 | 
            +
                        return value, variation_id
         | 
| 69 70 | 
             
                      end
         | 
| 70 71 | 
             
                    # CONTAINS
         | 
| 71 72 | 
             
                    elsif comparator == 2
         | 
| 72 73 | 
             
                      if user_value.to_s.include?(comparison_value.to_s)
         | 
| 73 74 | 
             
                        ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
         | 
| 74 | 
            -
                        return value
         | 
| 75 | 
            +
                        return value, variation_id
         | 
| 75 76 | 
             
                      end
         | 
| 76 77 | 
             
                    # DOES NOT CONTAIN
         | 
| 77 78 | 
             
                    elsif comparator == 3
         | 
| 78 79 | 
             
                      if !user_value.to_s.include?(comparison_value.to_s)
         | 
| 79 80 | 
             
                        ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
         | 
| 80 | 
            -
                        return value
         | 
| 81 | 
            +
                        return value, variation_id
         | 
| 81 82 | 
             
                      end
         | 
| 82 83 | 
             
                    # IS ONE OF, IS NOT ONE OF (Semantic version)
         | 
| 83 84 | 
             
                    elsif (4 <= comparator) && (comparator <= 5)
         | 
| @@ -90,7 +91,7 @@ module ConfigCat | |
| 90 91 | 
             
                        }
         | 
| 91 92 | 
             
                        if match && comparator == 4 || !match && comparator == 5
         | 
| 92 93 | 
             
                          ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
         | 
| 93 | 
            -
                          return value
         | 
| 94 | 
            +
                          return value, variation_id
         | 
| 94 95 | 
             
                        end
         | 
| 95 96 | 
             
                      rescue ArgumentError => e
         | 
| 96 97 | 
             
                        ConfigCat.logger.warn(format_validation_error_rule(comparison_attribute, user_value, comparator, comparison_value, e.to_s))
         | 
| @@ -106,7 +107,7 @@ module ConfigCat | |
| 106 107 | 
             
                           (comparator == 8 && user_value_version > comparison_value_version) ||
         | 
| 107 108 | 
             
                           (comparator == 9 && user_value_version >= comparison_value_version)
         | 
| 108 109 | 
             
                          ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
         | 
| 109 | 
            -
                          return value
         | 
| 110 | 
            +
                          return value, variation_id
         | 
| 110 111 | 
             
                        end
         | 
| 111 112 | 
             
                      rescue ArgumentError => e
         | 
| 112 113 | 
             
                        ConfigCat.logger.warn(format_validation_error_rule(comparison_attribute, user_value, comparator, comparison_value, e.to_s))
         | 
| @@ -123,7 +124,7 @@ module ConfigCat | |
| 123 124 | 
             
                           (comparator == 14 && user_value_float > comparison_value_float) ||
         | 
| 124 125 | 
             
                           (comparator == 15 && user_value_float >= comparison_value_float)
         | 
| 125 126 | 
             
                          ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
         | 
| 126 | 
            -
                          return value
         | 
| 127 | 
            +
                          return value, variation_id
         | 
| 127 128 | 
             
                        end
         | 
| 128 129 | 
             
                      rescue Exception => e
         | 
| 129 130 | 
             
                        ConfigCat.logger.warn(format_validation_error_rule(comparison_attribute, user_value, comparator, comparison_value, e.to_s))
         | 
| @@ -133,13 +134,13 @@ module ConfigCat | |
| 133 134 | 
             
                    elsif comparator == 16
         | 
| 134 135 | 
             
                      if comparison_value.to_s.split(",").map { |x| x.strip() }.include?(Digest::SHA1.hexdigest(user_value).to_s)
         | 
| 135 136 | 
             
                        ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
         | 
| 136 | 
            -
                        return value
         | 
| 137 | 
            +
                        return value, variation_id
         | 
| 137 138 | 
             
                      end
         | 
| 138 139 | 
             
                    # IS NOT ONE OF (Sensitive)
         | 
| 139 140 | 
             
                    elsif comparator == 17
         | 
| 140 141 | 
             
                      if !comparison_value.to_s.split(",").map { |x| x.strip() }.include?(Digest::SHA1.hexdigest(user_value).to_s)
         | 
| 141 142 | 
             
                        ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
         | 
| 142 | 
            -
                        return value
         | 
| 143 | 
            +
                        return value, variation_id
         | 
| 143 144 | 
             
                      end
         | 
| 144 145 | 
             
                    end
         | 
| 145 146 | 
             
                    ConfigCat.logger.info(format_no_match_rule(comparison_attribute, user_value, comparator, comparison_value))
         | 
| @@ -154,14 +155,16 @@ module ConfigCat | |
| 154 155 | 
             
                      bucket += rollout_percentage_item.fetch(PERCENTAGE, 0)
         | 
| 155 156 | 
             
                      if hash_val < bucket
         | 
| 156 157 | 
             
                        percentage_value = rollout_percentage_item.fetch(VALUE, nil)
         | 
| 158 | 
            +
                        variation_id = rollout_percentage_item.fetch(VARIATION_ID, default_variation_id)
         | 
| 157 159 | 
             
                        ConfigCat.logger.info("Evaluating %% options. Returning %s" % percentage_value)
         | 
| 158 | 
            -
                        return percentage_value
         | 
| 160 | 
            +
                        return percentage_value, variation_id
         | 
| 159 161 | 
             
                      end
         | 
| 160 162 | 
             
                    end
         | 
| 161 163 | 
             
                  end
         | 
| 162 | 
            -
                   | 
| 163 | 
            -
                   | 
| 164 | 
            -
                   | 
| 164 | 
            +
                  return_value = setting_descriptor.fetch(VALUE, default_value)
         | 
| 165 | 
            +
                  return_variation_id = setting_descriptor.fetch(VARIATION_ID, default_variation_id)
         | 
| 166 | 
            +
                  ConfigCat.logger.info("Returning %s" % return_value)
         | 
| 167 | 
            +
                  return return_value, return_variation_id
         | 
| 165 168 | 
             
                end
         | 
| 166 169 |  | 
| 167 170 | 
             
                private
         | 
    
        data/lib/configcat/user.rb
    CHANGED
    
    | @@ -5,11 +5,11 @@ module ConfigCat | |
| 5 5 | 
             
                #    The user object for variation evaluation
         | 
| 6 6 | 
             
                #
         | 
| 7 7 |  | 
| 8 | 
            -
                PREDEFINED = [" | 
| 8 | 
            +
                PREDEFINED = ["Identifier", "Email", "Country"]
         | 
| 9 9 |  | 
| 10 10 | 
             
                def initialize(identifier, email: nil, country: nil, custom: nil)
         | 
| 11 | 
            -
                  @__identifier = identifier
         | 
| 12 | 
            -
                  @__data = {" | 
| 11 | 
            +
                  @__identifier = (!identifier.equal?(nil)) ? identifier : ""
         | 
| 12 | 
            +
                  @__data = {"Identifier" => identifier, "Email" => email, "Country" => country}
         | 
| 13 13 | 
             
                  @__custom = custom
         | 
| 14 14 | 
             
                end
         | 
| 15 15 |  | 
| @@ -18,14 +18,14 @@ module ConfigCat | |
| 18 18 | 
             
                end
         | 
| 19 19 |  | 
| 20 20 | 
             
                def get_attribute(attribute)
         | 
| 21 | 
            -
                  attribute = attribute.to_s | 
| 21 | 
            +
                  attribute = attribute.to_s
         | 
| 22 22 | 
             
                  if PREDEFINED.include?(attribute)
         | 
| 23 23 | 
             
                    return @__data[attribute]
         | 
| 24 24 | 
             
                  end
         | 
| 25 25 |  | 
| 26 26 | 
             
                  if !@__custom.equal?(nil)
         | 
| 27 27 | 
             
                    @__custom.each do |customField, customValue|
         | 
| 28 | 
            -
                      if customField.to_s | 
| 28 | 
            +
                      if customField.to_s == attribute
         | 
| 29 29 | 
             
                        return customValue
         | 
| 30 30 | 
             
                      end
         | 
| 31 31 | 
             
                    end
         | 
    
        data/lib/configcat/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,43 +1,43 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: configcat
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version:  | 
| 4 | 
            +
              version: 4.0.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - ConfigCat
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2020- | 
| 11 | 
            +
            date: 2020-10-12 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: concurrent-ruby
         | 
| 15 15 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 16 | 
             
                requirements:
         | 
| 17 | 
            -
                - - " | 
| 17 | 
            +
                - - "~>"
         | 
| 18 18 | 
             
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            -
                    version: ' | 
| 19 | 
            +
                    version: '1.1'
         | 
| 20 20 | 
             
              type: :runtime
         | 
| 21 21 | 
             
              prerelease: false
         | 
| 22 22 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 23 | 
             
                requirements:
         | 
| 24 | 
            -
                - - " | 
| 24 | 
            +
                - - "~>"
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            -
                    version: ' | 
| 26 | 
            +
                    version: '1.1'
         | 
| 27 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 28 28 | 
             
              name: semantic
         | 
| 29 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 30 | 
             
                requirements:
         | 
| 31 | 
            -
                - - " | 
| 31 | 
            +
                - - "~>"
         | 
| 32 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version: ' | 
| 33 | 
            +
                    version: '1.6'
         | 
| 34 34 | 
             
              type: :runtime
         | 
| 35 35 | 
             
              prerelease: false
         | 
| 36 36 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 37 | 
             
                requirements:
         | 
| 38 | 
            -
                - - " | 
| 38 | 
            +
                - - "~>"
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            -
                    version: ' | 
| 40 | 
            +
                    version: '1.6'
         | 
| 41 41 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 42 | 
             
              name: rspec
         | 
| 43 43 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -56,30 +56,44 @@ dependencies: | |
| 56 56 | 
             
              name: rake
         | 
| 57 57 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 58 | 
             
                requirements:
         | 
| 59 | 
            -
                - - " | 
| 59 | 
            +
                - - "~>"
         | 
| 60 60 | 
             
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            -
                    version: ' | 
| 61 | 
            +
                    version: '12.3'
         | 
| 62 62 | 
             
              type: :development
         | 
| 63 63 | 
             
              prerelease: false
         | 
| 64 64 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 65 | 
             
                requirements:
         | 
| 66 | 
            -
                - - " | 
| 66 | 
            +
                - - "~>"
         | 
| 67 67 | 
             
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            -
                    version: ' | 
| 68 | 
            +
                    version: '12.3'
         | 
| 69 69 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 70 70 | 
             
              name: coveralls
         | 
| 71 71 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 72 72 | 
             
                requirements:
         | 
| 73 | 
            -
                - - " | 
| 73 | 
            +
                - - "~>"
         | 
| 74 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 75 | 
            +
                    version: '0.8'
         | 
| 76 | 
            +
              type: :development
         | 
| 77 | 
            +
              prerelease: false
         | 
| 78 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 79 | 
            +
                requirements:
         | 
| 80 | 
            +
                - - "~>"
         | 
| 81 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 82 | 
            +
                    version: '0.8'
         | 
| 83 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 84 | 
            +
              name: webmock
         | 
| 85 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 | 
            +
                requirements:
         | 
| 87 | 
            +
                - - "~>"
         | 
| 74 88 | 
             
                  - !ruby/object:Gem::Version
         | 
| 75 | 
            -
                    version: '0'
         | 
| 89 | 
            +
                    version: '3.0'
         | 
| 76 90 | 
             
              type: :development
         | 
| 77 91 | 
             
              prerelease: false
         | 
| 78 92 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 79 93 | 
             
                requirements:
         | 
| 80 | 
            -
                - - " | 
| 94 | 
            +
                - - "~>"
         | 
| 81 95 | 
             
                  - !ruby/object:Gem::Version
         | 
| 82 | 
            -
                    version: '0'
         | 
| 96 | 
            +
                    version: '3.0'
         | 
| 83 97 | 
             
            description: Feature Flags created by developers for developers with ❤️. ConfigCat
         | 
| 84 98 | 
             
              lets you manage feature flags across frontend, backend, mobile, and desktop apps
         | 
| 85 99 | 
             
              without (re)deploying code. % rollouts, user targeting, segmentation. Feature toggle
         | 
| @@ -96,6 +110,8 @@ files: | |
| 96 110 | 
             
            - lib/configcat/configcache.rb
         | 
| 97 111 | 
             
            - lib/configcat/configcatclient.rb
         | 
| 98 112 | 
             
            - lib/configcat/configfetcher.rb
         | 
| 113 | 
            +
            - lib/configcat/constants.rb
         | 
| 114 | 
            +
            - lib/configcat/datagovernance.rb
         | 
| 99 115 | 
             
            - lib/configcat/interfaces.rb
         | 
| 100 116 | 
             
            - lib/configcat/lazyloadingcachepolicy.rb
         | 
| 101 117 | 
             
            - lib/configcat/manualpollingcachepolicy.rb
         | 
| @@ -112,7 +128,7 @@ require_paths: | |
| 112 128 | 
             
            - lib
         | 
| 113 129 | 
             
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 114 130 | 
             
              requirements:
         | 
| 115 | 
            -
              - - " | 
| 131 | 
            +
              - - ">="
         | 
| 116 132 | 
             
                - !ruby/object:Gem::Version
         | 
| 117 133 | 
             
                  version: '2.2'
         | 
| 118 134 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| @@ -121,8 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 121 137 | 
             
                - !ruby/object:Gem::Version
         | 
| 122 138 | 
             
                  version: '0'
         | 
| 123 139 | 
             
            requirements: []
         | 
| 124 | 
            -
             | 
| 125 | 
            -
            rubygems_version: 2.7.7
         | 
| 140 | 
            +
            rubygems_version: 3.0.8
         | 
| 126 141 | 
             
            signing_key: 
         | 
| 127 142 | 
             
            specification_version: 4
         | 
| 128 143 | 
             
            summary: ConfigCat SDK for Ruby.
         |