flipper 0.28.3 → 1.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/.github/workflows/examples.yml +2 -2
- data/Changelog.md +190 -165
- data/Gemfile +5 -3
- data/docs/images/flipper_cloud.png +0 -0
- data/examples/cloud/app.ru +12 -0
- data/examples/cloud/basic.rb +22 -0
- data/examples/cloud/cloud_setup.rb +4 -0
- data/examples/cloud/forked.rb +31 -0
- data/examples/cloud/import.rb +17 -0
- data/examples/cloud/threaded.rb +36 -0
- data/examples/dsl.rb +0 -14
- data/flipper-cloud.gemspec +19 -0
- data/flipper.gemspec +3 -2
- data/lib/flipper/cloud/configuration.rb +189 -0
- data/lib/flipper/cloud/dsl.rb +27 -0
- data/lib/flipper/cloud/instrumenter.rb +48 -0
- data/lib/flipper/cloud/message_verifier.rb +95 -0
- data/lib/flipper/cloud/middleware.rb +63 -0
- data/lib/flipper/cloud/routes.rb +14 -0
- data/lib/flipper/cloud.rb +53 -0
- data/lib/flipper/dsl.rb +0 -46
- data/lib/flipper/{railtie.rb → engine.rb} +19 -3
- data/lib/flipper/metadata.rb +5 -1
- data/lib/flipper/middleware/memoizer.rb +1 -1
- data/lib/flipper/spec/shared_adapter_specs.rb +43 -43
- data/lib/flipper/test/shared_adapter_test.rb +43 -43
- data/lib/flipper/version.rb +1 -1
- data/lib/flipper.rb +3 -5
- data/spec/flipper/adapters/dual_write_spec.rb +2 -2
- data/spec/flipper/adapters/instrumented_spec.rb +1 -1
- data/spec/flipper/adapters/memoizable_spec.rb +6 -6
- data/spec/flipper/adapters/operation_logger_spec.rb +2 -2
- data/spec/flipper/adapters/read_only_spec.rb +6 -6
- data/spec/flipper/cloud/configuration_spec.rb +269 -0
- data/spec/flipper/cloud/dsl_spec.rb +82 -0
- data/spec/flipper/cloud/message_verifier_spec.rb +104 -0
- data/spec/flipper/cloud/middleware_spec.rb +289 -0
- data/spec/flipper/cloud_spec.rb +180 -0
- data/spec/flipper/dsl_spec.rb +0 -75
- data/spec/flipper/engine_spec.rb +190 -0
- data/spec/flipper_integration_spec.rb +12 -12
- data/spec/flipper_spec.rb +0 -30
- data/spec/spec_helper.rb +0 -12
- data/spec/support/climate_control.rb +7 -0
- metadata +54 -11
- data/.tool-versions +0 -1
- data/spec/flipper/railtie_spec.rb +0 -109
| @@ -0,0 +1,190 @@ | |
| 1 | 
            +
            require 'rails'
         | 
| 2 | 
            +
            require 'flipper/engine'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            RSpec.describe Flipper::Engine do
         | 
| 5 | 
            +
              let(:application) do
         | 
| 6 | 
            +
                Class.new(Rails::Application) do
         | 
| 7 | 
            +
                  config.eager_load = false
         | 
| 8 | 
            +
                  config.logger = ActiveSupport::Logger.new($stdout)
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              before do
         | 
| 13 | 
            +
                Rails.application = nil
         | 
| 14 | 
            +
                ActiveSupport::Dependencies.autoload_paths = ActiveSupport::Dependencies.autoload_paths.dup
         | 
| 15 | 
            +
                ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_once_paths.dup
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              let(:config) { application.config.flipper }
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              subject { application.initialize! }
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              context 'cloudless' do
         | 
| 23 | 
            +
                it 'can set env_key from ENV' do
         | 
| 24 | 
            +
                  with_env 'FLIPPER_ENV_KEY' => 'flopper' do
         | 
| 25 | 
            +
                    subject
         | 
| 26 | 
            +
                    expect(config.env_key).to eq('flopper')
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                it 'can set memoize from ENV' do
         | 
| 31 | 
            +
                  with_env 'FLIPPER_MEMOIZE' => 'false' do
         | 
| 32 | 
            +
                    subject
         | 
| 33 | 
            +
                    expect(config.memoize).to eq(false)
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                it 'can set preload from ENV' do
         | 
| 38 | 
            +
                  with_env 'FLIPPER_PRELOAD' => 'false' do
         | 
| 39 | 
            +
                    subject
         | 
| 40 | 
            +
                    expect(config.preload).to eq(false)
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                it 'can set instrumenter from ENV' do
         | 
| 45 | 
            +
                  stub_const('My::Cool::Instrumenter', Class.new)
         | 
| 46 | 
            +
                  with_env 'FLIPPER_INSTRUMENTER' => 'My::Cool::Instrumenter' do
         | 
| 47 | 
            +
                    subject
         | 
| 48 | 
            +
                    expect(config.instrumenter).to eq(My::Cool::Instrumenter)
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                it 'can set log from ENV' do
         | 
| 53 | 
            +
                  with_env 'FLIPPER_LOG' => 'false' do
         | 
| 54 | 
            +
                    subject
         | 
| 55 | 
            +
                    expect(config.log).to eq(false)
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                it 'sets defaults' do
         | 
| 60 | 
            +
                  subject # initialize
         | 
| 61 | 
            +
                  expect(config.env_key).to eq("flipper")
         | 
| 62 | 
            +
                  expect(config.memoize).to be(true)
         | 
| 63 | 
            +
                  expect(config.preload).to be(true)
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                it "configures instrumentor on default instance" do
         | 
| 67 | 
            +
                  subject # initialize
         | 
| 68 | 
            +
                  expect(Flipper.instance.instrumenter).to eq(ActiveSupport::Notifications)
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                it 'uses Memoizer middleware if config.memoize = true' do
         | 
| 72 | 
            +
                  initializer { config.memoize = true }
         | 
| 73 | 
            +
                  expect(subject.middleware).to include(Flipper::Middleware::Memoizer)
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                it 'does not use Memoizer middleware if config.memoize = false' do
         | 
| 77 | 
            +
                  initializer { config.memoize = false }
         | 
| 78 | 
            +
                  expect(subject.middleware).not_to include(Flipper::Middleware::Memoizer)
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                it 'passes config to memoizer' do
         | 
| 82 | 
            +
                  initializer do
         | 
| 83 | 
            +
                    config.update(
         | 
| 84 | 
            +
                      env_key: 'my_flipper',
         | 
| 85 | 
            +
                      preload: [:stats, :search]
         | 
| 86 | 
            +
                    )
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  expect(subject.middleware).to include(Flipper::Middleware::Memoizer)
         | 
| 90 | 
            +
                  middleware = subject.middleware.detect { |m| m.klass == Flipper::Middleware::Memoizer }
         | 
| 91 | 
            +
                  expect(middleware.args[0]).to eq({
         | 
| 92 | 
            +
                    env_key: config.env_key,
         | 
| 93 | 
            +
                    preload: config.preload,
         | 
| 94 | 
            +
                    if: nil
         | 
| 95 | 
            +
                  })
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                it "defines #flipper_id on AR::Base" do
         | 
| 99 | 
            +
                  subject
         | 
| 100 | 
            +
                  require 'active_record'
         | 
| 101 | 
            +
                  expect(ActiveRecord::Base.ancestors).to include(Flipper::Identifier)
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
              end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
              context 'with cloud' do
         | 
| 106 | 
            +
                around do |example|
         | 
| 107 | 
            +
                  with_env "FLIPPER_CLOUD_TOKEN" => "test-token" do
         | 
| 108 | 
            +
                    example.run
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                # App for Rack::Test
         | 
| 113 | 
            +
                let(:app) { application.routes }
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                it "initializes cloud configuration" do
         | 
| 116 | 
            +
                  stub_request(:get, /flippercloud\.io/).to_return(status: 200, body: "{}")
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                  application.initialize!
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                  expect(Flipper.instance).to be_a(Flipper::Cloud::DSL)
         | 
| 121 | 
            +
                  expect(Flipper.instance.instrumenter).to be(ActiveSupport::Notifications)
         | 
| 122 | 
            +
                end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                context "with CLOUD_SYNC_SECRET" do
         | 
| 125 | 
            +
                  around do |example|
         | 
| 126 | 
            +
                    with_env "FLIPPER_CLOUD_SYNC_SECRET" => "test-secret" do
         | 
| 127 | 
            +
                      example.run
         | 
| 128 | 
            +
                    end
         | 
| 129 | 
            +
                  end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                  let(:request_body) do
         | 
| 132 | 
            +
                    JSON.generate({
         | 
| 133 | 
            +
                      "environment_id" => 1,
         | 
| 134 | 
            +
                      "webhook_id" => 1,
         | 
| 135 | 
            +
                      "delivery_id" => SecureRandom.uuid,
         | 
| 136 | 
            +
                      "action" => "sync",
         | 
| 137 | 
            +
                    })
         | 
| 138 | 
            +
                  end
         | 
| 139 | 
            +
                  let(:timestamp) { Time.now }
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                  let(:signature) {
         | 
| 142 | 
            +
                    Flipper::Cloud::MessageVerifier.new(secret: ENV["FLIPPER_CLOUD_SYNC_SECRET"]).generate(request_body, timestamp)
         | 
| 143 | 
            +
                  }
         | 
| 144 | 
            +
                  let(:signature_header_value) {
         | 
| 145 | 
            +
                    Flipper::Cloud::MessageVerifier.new(secret: "").header(signature, timestamp)
         | 
| 146 | 
            +
                  }
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                  it "configures webhook app" do
         | 
| 149 | 
            +
                    application.initialize!
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                    stub = stub_request(:get, "https://www.flippercloud.io/adapter/features?exclude_gate_names=true").with({
         | 
| 152 | 
            +
                      headers: { "Flipper-Cloud-Token" => ENV["FLIPPER_CLOUD_TOKEN"] },
         | 
| 153 | 
            +
                    }).to_return(status: 200, body: JSON.generate({ features: {} }), headers: {})
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                    post "/_flipper", request_body, { "HTTP_FLIPPER_CLOUD_SIGNATURE" => signature_header_value }
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                    expect(last_response.status).to eq(200)
         | 
| 158 | 
            +
                    expect(stub).to have_been_requested
         | 
| 159 | 
            +
                  end
         | 
| 160 | 
            +
                end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                context "without CLOUD_SYNC_SECRET" do
         | 
| 163 | 
            +
                  it "does not configure webhook app" do
         | 
| 164 | 
            +
                    application.initialize!
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                    post "/_flipper"
         | 
| 167 | 
            +
                    expect(last_response.status).to eq(404)
         | 
| 168 | 
            +
                  end
         | 
| 169 | 
            +
                end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                context "without FLIPPER_CLOUD_TOKEN" do
         | 
| 172 | 
            +
                  it "gracefully skips configuring webhook app" do
         | 
| 173 | 
            +
                    with_env "FLIPPER_CLOUD_TOKEN" => nil do
         | 
| 174 | 
            +
                      application.initialize!
         | 
| 175 | 
            +
                      expect(Flipper.instance).to be_a(Flipper::DSL)
         | 
| 176 | 
            +
                    end
         | 
| 177 | 
            +
             | 
| 178 | 
            +
                    post "/_flipper"
         | 
| 179 | 
            +
                    expect(last_response.status).to eq(404)
         | 
| 180 | 
            +
                  end
         | 
| 181 | 
            +
                end
         | 
| 182 | 
            +
              end
         | 
| 183 | 
            +
             | 
| 184 | 
            +
              # Add app initializer in the same order as config/initializers/*
         | 
| 185 | 
            +
              def initializer(&block)
         | 
| 186 | 
            +
                application.initializer 'spec', before: :load_config_initializers do
         | 
| 187 | 
            +
                  block.call
         | 
| 188 | 
            +
                end
         | 
| 189 | 
            +
              end
         | 
| 190 | 
            +
            end
         | 
| @@ -24,8 +24,8 @@ RSpec.describe Flipper do | |
| 24 24 | 
             
              let(:pitt)        { Flipper::Actor.new(1) }
         | 
| 25 25 | 
             
              let(:clooney)     { Flipper::Actor.new(10) }
         | 
| 26 26 |  | 
| 27 | 
            -
              let(:five_percent_of_actors) {  | 
| 28 | 
            -
              let(:five_percent_of_time) {  | 
| 27 | 
            +
              let(:five_percent_of_actors) { Flipper::Types::PercentageOfActors.new(5) }
         | 
| 28 | 
            +
              let(:five_percent_of_time) { Flipper::Types::PercentageOfTime.new(5) }
         | 
| 29 29 |  | 
| 30 30 | 
             
              before do
         | 
| 31 31 | 
             
                described_class.register(:admins, &:admin?)
         | 
| @@ -69,11 +69,11 @@ RSpec.describe Flipper do | |
| 69 69 | 
             
                  end
         | 
| 70 70 |  | 
| 71 71 | 
             
                  it 'enables feature for flipper actor in group' do
         | 
| 72 | 
            -
                    expect(feature.enabled?( | 
| 72 | 
            +
                    expect(feature.enabled?(Flipper::Types::Actor.new(admin_actor))).to eq(true)
         | 
| 73 73 | 
             
                  end
         | 
| 74 74 |  | 
| 75 75 | 
             
                  it 'does not enable for flipper actor not in group' do
         | 
| 76 | 
            -
                    expect(feature.enabled?( | 
| 76 | 
            +
                    expect(feature.enabled?(Flipper::Types::Actor.new(dev_actor))).to eq(false)
         | 
| 77 77 | 
             
                  end
         | 
| 78 78 |  | 
| 79 79 | 
             
                  it 'does not enable feature for all' do
         | 
| @@ -256,11 +256,11 @@ RSpec.describe Flipper do | |
| 256 256 | 
             
                  end
         | 
| 257 257 |  | 
| 258 258 | 
             
                  it 'disables feature for flipper actor in group' do
         | 
| 259 | 
            -
                    expect(feature.enabled?( | 
| 259 | 
            +
                    expect(feature.enabled?(Flipper::Types::Actor.new(admin_actor))).to eq(false)
         | 
| 260 260 | 
             
                  end
         | 
| 261 261 |  | 
| 262 262 | 
             
                  it 'does not disable feature for flipper actor in other groups' do
         | 
| 263 | 
            -
                    expect(feature.enabled?( | 
| 263 | 
            +
                    expect(feature.enabled?(Flipper::Types::Actor.new(dev_actor))).to eq(true)
         | 
| 264 264 | 
             
                  end
         | 
| 265 265 |  | 
| 266 266 | 
             
                  it 'adds feature to set of features' do
         | 
| @@ -294,7 +294,7 @@ RSpec.describe Flipper do | |
| 294 294 |  | 
| 295 295 | 
             
                context 'with a percentage of actors' do
         | 
| 296 296 | 
             
                  before do
         | 
| 297 | 
            -
                    @result = feature.disable( | 
| 297 | 
            +
                    @result = feature.disable(Flipper::Types::PercentageOfActors.new(0))
         | 
| 298 298 | 
             
                  end
         | 
| 299 299 |  | 
| 300 300 | 
             
                  it 'returns true' do
         | 
| @@ -318,7 +318,7 @@ RSpec.describe Flipper do | |
| 318 318 | 
             
                context 'with a percentage of time' do
         | 
| 319 319 | 
             
                  before do
         | 
| 320 320 | 
             
                    @gate = feature.gate(:percentage_of_time)
         | 
| 321 | 
            -
                    @result = feature.disable( | 
| 321 | 
            +
                    @result = feature.disable(Flipper::Types::PercentageOfTime.new(0))
         | 
| 322 322 | 
             
                  end
         | 
| 323 323 |  | 
| 324 324 | 
             
                  it 'returns true' do
         | 
| @@ -373,12 +373,12 @@ RSpec.describe Flipper do | |
| 373 373 | 
             
                  end
         | 
| 374 374 |  | 
| 375 375 | 
             
                  it 'returns true' do
         | 
| 376 | 
            -
                    expect(feature.enabled?( | 
| 376 | 
            +
                    expect(feature.enabled?(Flipper::Types::Actor.new(admin_actor))).to eq(true)
         | 
| 377 377 | 
             
                    expect(feature.enabled?(admin_actor)).to eq(true)
         | 
| 378 378 | 
             
                  end
         | 
| 379 379 |  | 
| 380 380 | 
             
                  it 'returns true for truthy block values' do
         | 
| 381 | 
            -
                    expect(feature.enabled?( | 
| 381 | 
            +
                    expect(feature.enabled?(Flipper::Types::Actor.new(admin_truthy_actor))).to eq(true)
         | 
| 382 382 | 
             
                  end
         | 
| 383 383 |  | 
| 384 384 | 
             
                  it 'returns true if any actor is in enabled group' do
         | 
| @@ -388,12 +388,12 @@ RSpec.describe Flipper do | |
| 388 388 |  | 
| 389 389 | 
             
                context 'for actor in disabled group' do
         | 
| 390 390 | 
             
                  it 'returns false' do
         | 
| 391 | 
            -
                    expect(feature.enabled?( | 
| 391 | 
            +
                    expect(feature.enabled?(Flipper::Types::Actor.new(dev_actor))).to eq(false)
         | 
| 392 392 | 
             
                    expect(feature.enabled?(dev_actor)).to eq(false)
         | 
| 393 393 | 
             
                  end
         | 
| 394 394 |  | 
| 395 395 | 
             
                  it 'returns false for falsey block values' do
         | 
| 396 | 
            -
                    expect(feature.enabled?( | 
| 396 | 
            +
                    expect(feature.enabled?(Flipper::Types::Actor.new(admin_falsey_actor))).to eq(false)
         | 
| 397 397 | 
             
                  end
         | 
| 398 398 | 
             
                end
         | 
| 399 399 |  | 
    
        data/spec/flipper_spec.rb
    CHANGED
    
    | @@ -88,14 +88,6 @@ RSpec.describe Flipper do | |
| 88 88 | 
             
                  expect(described_class.instance.enabled?(:search)).to be(false)
         | 
| 89 89 | 
             
                end
         | 
| 90 90 |  | 
| 91 | 
            -
                it 'delegates bool to instance' do
         | 
| 92 | 
            -
                  expect(described_class.bool).to eq(described_class.instance.bool)
         | 
| 93 | 
            -
                end
         | 
| 94 | 
            -
             | 
| 95 | 
            -
                it 'delegates boolean to instance' do
         | 
| 96 | 
            -
                  expect(described_class.boolean).to eq(described_class.instance.boolean)
         | 
| 97 | 
            -
                end
         | 
| 98 | 
            -
             | 
| 99 91 | 
             
                it 'delegates enable_actor to instance' do
         | 
| 100 92 | 
             
                  described_class.enable_actor(:search, actor)
         | 
| 101 93 | 
             
                  expect(described_class.instance.enabled?(:search, actor)).to be(true)
         | 
| @@ -106,10 +98,6 @@ RSpec.describe Flipper do | |
| 106 98 | 
             
                  expect(described_class.instance.enabled?(:search, actor)).to be(false)
         | 
| 107 99 | 
             
                end
         | 
| 108 100 |  | 
| 109 | 
            -
                it 'delegates actor to instance' do
         | 
| 110 | 
            -
                  expect(described_class.actor(actor)).to eq(described_class.instance.actor(actor))
         | 
| 111 | 
            -
                end
         | 
| 112 | 
            -
             | 
| 113 101 | 
             
                it 'delegates enable_group to instance' do
         | 
| 114 102 | 
             
                  described_class.enable_group(:search, group)
         | 
| 115 103 | 
             
                  expect(described_class.instance[:search].enabled_groups).to include(group)
         | 
| @@ -130,15 +118,6 @@ RSpec.describe Flipper do | |
| 130 118 | 
             
                  expect(described_class.instance[:search].percentage_of_actors_value).to be(0)
         | 
| 131 119 | 
             
                end
         | 
| 132 120 |  | 
| 133 | 
            -
                it 'delegates actors to instance' do
         | 
| 134 | 
            -
                  expect(described_class.actors(5)).to eq(described_class.instance.actors(5))
         | 
| 135 | 
            -
                end
         | 
| 136 | 
            -
             | 
| 137 | 
            -
                it 'delegates percentage_of_actors to instance' do
         | 
| 138 | 
            -
                  expected = described_class.instance.percentage_of_actors(5)
         | 
| 139 | 
            -
                  expect(described_class.percentage_of_actors(5)).to eq(expected)
         | 
| 140 | 
            -
                end
         | 
| 141 | 
            -
             | 
| 142 121 | 
             
                it 'delegates enable_percentage_of_time to instance' do
         | 
| 143 122 | 
             
                  described_class.enable_percentage_of_time(:search, 5)
         | 
| 144 123 | 
             
                  expect(described_class.instance[:search].percentage_of_time_value).to be(5)
         | 
| @@ -149,15 +128,6 @@ RSpec.describe Flipper do | |
| 149 128 | 
             
                  expect(described_class.instance[:search].percentage_of_time_value).to be(0)
         | 
| 150 129 | 
             
                end
         | 
| 151 130 |  | 
| 152 | 
            -
                it 'delegates time to instance' do
         | 
| 153 | 
            -
                  expect(described_class.time(56)).to eq(described_class.instance.time(56))
         | 
| 154 | 
            -
                end
         | 
| 155 | 
            -
             | 
| 156 | 
            -
                it 'delegates percentage_of_time to instance' do
         | 
| 157 | 
            -
                  expected = described_class.instance.percentage_of_time(56)
         | 
| 158 | 
            -
                  expect(described_class.percentage_of_time(56)).to eq(expected)
         | 
| 159 | 
            -
                end
         | 
| 160 | 
            -
             | 
| 161 131 | 
             
                it 'delegates features to instance' do
         | 
| 162 132 | 
             
                  described_class.instance.add(:search)
         | 
| 163 133 | 
             
                  expect(described_class.features).to eq(described_class.instance.features)
         | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | @@ -91,15 +91,3 @@ RSpec.shared_examples_for 'a DSL feature' do | |
| 91 91 | 
             
                end.to raise_error(ArgumentError, /must be a String or Symbol/)
         | 
| 92 92 | 
             
              end
         | 
| 93 93 | 
             
            end
         | 
| 94 | 
            -
             | 
| 95 | 
            -
            RSpec.shared_examples_for 'a DSL boolean method' do
         | 
| 96 | 
            -
              it 'returns boolean with value set' do
         | 
| 97 | 
            -
                result = subject.send(method_name, true)
         | 
| 98 | 
            -
                expect(result).to be_instance_of(Flipper::Types::Boolean)
         | 
| 99 | 
            -
                expect(result.value).to be(true)
         | 
| 100 | 
            -
             | 
| 101 | 
            -
                result = subject.send(method_name, false)
         | 
| 102 | 
            -
                expect(result).to be_instance_of(Flipper::Types::Boolean)
         | 
| 103 | 
            -
                expect(result.value).to be(false)
         | 
| 104 | 
            -
              end
         | 
| 105 | 
            -
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: flipper
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 1.0.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - John Nunemaker
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023- | 
| 11 | 
            +
            date: 2023-08-23 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: concurrent-ruby
         | 
| @@ -24,9 +24,22 @@ dependencies: | |
| 24 24 | 
             
                - - "<"
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 26 | 
             
                    version: '2'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: brow
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - "~>"
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: 0.4.1
         | 
| 34 | 
            +
              type: :runtime
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - "~>"
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: 0.4.1
         | 
| 27 41 | 
             
            description:
         | 
| 28 | 
            -
            email:
         | 
| 29 | 
            -
            - nunemaker@gmail.com
         | 
| 42 | 
            +
            email: support@flippercloud.io
         | 
| 30 43 | 
             
            executables: []
         | 
| 31 44 | 
             
            extensions: []
         | 
| 32 45 | 
             
            extra_rdoc_files: []
         | 
| @@ -36,7 +49,6 @@ files: | |
| 36 49 | 
             
            - ".github/workflows/ci.yml"
         | 
| 37 50 | 
             
            - ".github/workflows/examples.yml"
         | 
| 38 51 | 
             
            - ".rspec"
         | 
| 39 | 
            -
            - ".tool-versions"
         | 
| 40 52 | 
             
            - CODE_OF_CONDUCT.md
         | 
| 41 53 | 
             
            - Changelog.md
         | 
| 42 54 | 
             
            - Dockerfile
         | 
| @@ -53,10 +65,17 @@ files: | |
| 53 65 | 
             
            - docs/DockerCompose.md
         | 
| 54 66 | 
             
            - docs/README.md
         | 
| 55 67 | 
             
            - docs/images/banner.jpg
         | 
| 68 | 
            +
            - docs/images/flipper_cloud.png
         | 
| 56 69 | 
             
            - examples/api/basic.ru
         | 
| 57 70 | 
             
            - examples/api/custom_memoized.ru
         | 
| 58 71 | 
             
            - examples/api/memoized.ru
         | 
| 59 72 | 
             
            - examples/basic.rb
         | 
| 73 | 
            +
            - examples/cloud/app.ru
         | 
| 74 | 
            +
            - examples/cloud/basic.rb
         | 
| 75 | 
            +
            - examples/cloud/cloud_setup.rb
         | 
| 76 | 
            +
            - examples/cloud/forked.rb
         | 
| 77 | 
            +
            - examples/cloud/import.rb
         | 
| 78 | 
            +
            - examples/cloud/threaded.rb
         | 
| 60 79 | 
             
            - examples/configuring_default.rb
         | 
| 61 80 | 
             
            - examples/dsl.rb
         | 
| 62 81 | 
             
            - examples/enabled_for_actor.rb
         | 
| @@ -73,6 +92,7 @@ files: | |
| 73 92 | 
             
            - examples/percentage_of_actors_enabled_check.rb
         | 
| 74 93 | 
             
            - examples/percentage_of_actors_group.rb
         | 
| 75 94 | 
             
            - examples/percentage_of_time.rb
         | 
| 95 | 
            +
            - flipper-cloud.gemspec
         | 
| 76 96 | 
             
            - flipper.gemspec
         | 
| 77 97 | 
             
            - lib/flipper.rb
         | 
| 78 98 | 
             
            - lib/flipper/actor.rb
         | 
| @@ -95,8 +115,16 @@ files: | |
| 95 115 | 
             
            - lib/flipper/adapters/sync/feature_synchronizer.rb
         | 
| 96 116 | 
             
            - lib/flipper/adapters/sync/interval_synchronizer.rb
         | 
| 97 117 | 
             
            - lib/flipper/adapters/sync/synchronizer.rb
         | 
| 118 | 
            +
            - lib/flipper/cloud.rb
         | 
| 119 | 
            +
            - lib/flipper/cloud/configuration.rb
         | 
| 120 | 
            +
            - lib/flipper/cloud/dsl.rb
         | 
| 121 | 
            +
            - lib/flipper/cloud/instrumenter.rb
         | 
| 122 | 
            +
            - lib/flipper/cloud/message_verifier.rb
         | 
| 123 | 
            +
            - lib/flipper/cloud/middleware.rb
         | 
| 124 | 
            +
            - lib/flipper/cloud/routes.rb
         | 
| 98 125 | 
             
            - lib/flipper/configuration.rb
         | 
| 99 126 | 
             
            - lib/flipper/dsl.rb
         | 
| 127 | 
            +
            - lib/flipper/engine.rb
         | 
| 100 128 | 
             
            - lib/flipper/errors.rb
         | 
| 101 129 | 
             
            - lib/flipper/export.rb
         | 
| 102 130 | 
             
            - lib/flipper/exporter.rb
         | 
| @@ -122,7 +150,6 @@ files: | |
| 122 150 | 
             
            - lib/flipper/middleware/memoizer.rb
         | 
| 123 151 | 
             
            - lib/flipper/middleware/setup_env.rb
         | 
| 124 152 | 
             
            - lib/flipper/poller.rb
         | 
| 125 | 
            -
            - lib/flipper/railtie.rb
         | 
| 126 153 | 
             
            - lib/flipper/registry.rb
         | 
| 127 154 | 
             
            - lib/flipper/spec/shared_adapter_specs.rb
         | 
| 128 155 | 
             
            - lib/flipper/test/shared_adapter_test.rb
         | 
| @@ -153,8 +180,14 @@ files: | |
| 153 180 | 
             
            - spec/flipper/adapters/sync/interval_synchronizer_spec.rb
         | 
| 154 181 | 
             
            - spec/flipper/adapters/sync/synchronizer_spec.rb
         | 
| 155 182 | 
             
            - spec/flipper/adapters/sync_spec.rb
         | 
| 183 | 
            +
            - spec/flipper/cloud/configuration_spec.rb
         | 
| 184 | 
            +
            - spec/flipper/cloud/dsl_spec.rb
         | 
| 185 | 
            +
            - spec/flipper/cloud/message_verifier_spec.rb
         | 
| 186 | 
            +
            - spec/flipper/cloud/middleware_spec.rb
         | 
| 187 | 
            +
            - spec/flipper/cloud_spec.rb
         | 
| 156 188 | 
             
            - spec/flipper/configuration_spec.rb
         | 
| 157 189 | 
             
            - spec/flipper/dsl_spec.rb
         | 
| 190 | 
            +
            - spec/flipper/engine_spec.rb
         | 
| 158 191 | 
             
            - spec/flipper/export_spec.rb
         | 
| 159 192 | 
             
            - spec/flipper/exporter_spec.rb
         | 
| 160 193 | 
             
            - spec/flipper/exporters/json/export_spec.rb
         | 
| @@ -176,7 +209,6 @@ files: | |
| 176 209 | 
             
            - spec/flipper/middleware/memoizer_spec.rb
         | 
| 177 210 | 
             
            - spec/flipper/middleware/setup_env_spec.rb
         | 
| 178 211 | 
             
            - spec/flipper/poller_spec.rb
         | 
| 179 | 
            -
            - spec/flipper/railtie_spec.rb
         | 
| 180 212 | 
             
            - spec/flipper/registry_spec.rb
         | 
| 181 213 | 
             
            - spec/flipper/typecast_spec.rb
         | 
| 182 214 | 
             
            - spec/flipper/types/actor_spec.rb
         | 
| @@ -188,6 +220,7 @@ files: | |
| 188 220 | 
             
            - spec/flipper_integration_spec.rb
         | 
| 189 221 | 
             
            - spec/flipper_spec.rb
         | 
| 190 222 | 
             
            - spec/spec_helper.rb
         | 
| 223 | 
            +
            - spec/support/climate_control.rb
         | 
| 191 224 | 
             
            - spec/support/descriptions.yml
         | 
| 192 225 | 
             
            - spec/support/fake_udp_socket.rb
         | 
| 193 226 | 
             
            - spec/support/skippable.rb
         | 
| @@ -196,11 +229,15 @@ files: | |
| 196 229 | 
             
            - test/adapters/pstore_test.rb
         | 
| 197 230 | 
             
            - test/test_helper.rb
         | 
| 198 231 | 
             
            - test_rails/helper.rb
         | 
| 199 | 
            -
            homepage: https:// | 
| 232 | 
            +
            homepage: https://www.flippercloud.io/docs
         | 
| 200 233 | 
             
            licenses:
         | 
| 201 234 | 
             
            - MIT
         | 
| 202 235 | 
             
            metadata:
         | 
| 203 | 
            -
               | 
| 236 | 
            +
              documentation_uri: https://www.flippercloud.io/docs
         | 
| 237 | 
            +
              homepage_uri: https://www.flippercloud.io
         | 
| 238 | 
            +
              source_code_uri: https://github.com/flippercloud/flipper
         | 
| 239 | 
            +
              bug_tracker_uri: https://github.com/flippercloud/flipper/issues
         | 
| 240 | 
            +
              changelog_uri: https://github.com/flippercloud/flipper/blob/main/Changelog.md
         | 
| 204 241 | 
             
            post_install_message:
         | 
| 205 242 | 
             
            rdoc_options: []
         | 
| 206 243 | 
             
            require_paths:
         | 
| @@ -216,7 +253,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 216 253 | 
             
                - !ruby/object:Gem::Version
         | 
| 217 254 | 
             
                  version: '0'
         | 
| 218 255 | 
             
            requirements: []
         | 
| 219 | 
            -
            rubygems_version: 3. | 
| 256 | 
            +
            rubygems_version: 3.4.10
         | 
| 220 257 | 
             
            signing_key:
         | 
| 221 258 | 
             
            specification_version: 4
         | 
| 222 259 | 
             
            summary: Feature flipper for ANYTHING
         | 
| @@ -239,8 +276,14 @@ test_files: | |
| 239 276 | 
             
            - spec/flipper/adapters/sync/interval_synchronizer_spec.rb
         | 
| 240 277 | 
             
            - spec/flipper/adapters/sync/synchronizer_spec.rb
         | 
| 241 278 | 
             
            - spec/flipper/adapters/sync_spec.rb
         | 
| 279 | 
            +
            - spec/flipper/cloud/configuration_spec.rb
         | 
| 280 | 
            +
            - spec/flipper/cloud/dsl_spec.rb
         | 
| 281 | 
            +
            - spec/flipper/cloud/message_verifier_spec.rb
         | 
| 282 | 
            +
            - spec/flipper/cloud/middleware_spec.rb
         | 
| 283 | 
            +
            - spec/flipper/cloud_spec.rb
         | 
| 242 284 | 
             
            - spec/flipper/configuration_spec.rb
         | 
| 243 285 | 
             
            - spec/flipper/dsl_spec.rb
         | 
| 286 | 
            +
            - spec/flipper/engine_spec.rb
         | 
| 244 287 | 
             
            - spec/flipper/export_spec.rb
         | 
| 245 288 | 
             
            - spec/flipper/exporter_spec.rb
         | 
| 246 289 | 
             
            - spec/flipper/exporters/json/export_spec.rb
         | 
| @@ -262,7 +305,6 @@ test_files: | |
| 262 305 | 
             
            - spec/flipper/middleware/memoizer_spec.rb
         | 
| 263 306 | 
             
            - spec/flipper/middleware/setup_env_spec.rb
         | 
| 264 307 | 
             
            - spec/flipper/poller_spec.rb
         | 
| 265 | 
            -
            - spec/flipper/railtie_spec.rb
         | 
| 266 308 | 
             
            - spec/flipper/registry_spec.rb
         | 
| 267 309 | 
             
            - spec/flipper/typecast_spec.rb
         | 
| 268 310 | 
             
            - spec/flipper/types/actor_spec.rb
         | 
| @@ -274,6 +316,7 @@ test_files: | |
| 274 316 | 
             
            - spec/flipper_integration_spec.rb
         | 
| 275 317 | 
             
            - spec/flipper_spec.rb
         | 
| 276 318 | 
             
            - spec/spec_helper.rb
         | 
| 319 | 
            +
            - spec/support/climate_control.rb
         | 
| 277 320 | 
             
            - spec/support/descriptions.yml
         | 
| 278 321 | 
             
            - spec/support/fake_udp_socket.rb
         | 
| 279 322 | 
             
            - spec/support/skippable.rb
         | 
    
        data/.tool-versions
    DELETED
    
    | @@ -1 +0,0 @@ | |
| 1 | 
            -
            ruby 3.1.2
         | 
| @@ -1,109 +0,0 @@ | |
| 1 | 
            -
            require 'rails'
         | 
| 2 | 
            -
            require 'flipper/railtie'
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            RSpec.describe Flipper::Railtie do
         | 
| 5 | 
            -
              let(:application) do
         | 
| 6 | 
            -
                Class.new(Rails::Application).create(railties: [Flipper::Railtie]) do
         | 
| 7 | 
            -
                  config.eager_load = false
         | 
| 8 | 
            -
                end
         | 
| 9 | 
            -
              end
         | 
| 10 | 
            -
             | 
| 11 | 
            -
              before do
         | 
| 12 | 
            -
                ActiveSupport::Dependencies.autoload_paths = ActiveSupport::Dependencies.autoload_paths.dup
         | 
| 13 | 
            -
                ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_once_paths.dup
         | 
| 14 | 
            -
              end
         | 
| 15 | 
            -
             | 
| 16 | 
            -
              let(:config) { application.config.flipper }
         | 
| 17 | 
            -
             | 
| 18 | 
            -
              subject { application.initialize! }
         | 
| 19 | 
            -
             | 
| 20 | 
            -
              describe 'initializers' do
         | 
| 21 | 
            -
                it 'can set env_key from ENV' do
         | 
| 22 | 
            -
                  ENV['FLIPPER_ENV_KEY'] = 'flopper'
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                  subject
         | 
| 25 | 
            -
                  expect(config.env_key).to eq('flopper')
         | 
| 26 | 
            -
                end
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                it 'can set memoize from ENV' do
         | 
| 29 | 
            -
                  ENV['FLIPPER_MEMOIZE'] = 'false'
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                  subject
         | 
| 32 | 
            -
                  expect(config.memoize).to eq(false)
         | 
| 33 | 
            -
                end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                it 'can set preload from ENV' do
         | 
| 36 | 
            -
                  ENV['FLIPPER_PRELOAD'] = 'false'
         | 
| 37 | 
            -
             | 
| 38 | 
            -
                  subject
         | 
| 39 | 
            -
                  expect(config.preload).to eq(false)
         | 
| 40 | 
            -
                end
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                it 'can set instrumenter from ENV' do
         | 
| 43 | 
            -
                  stub_const('My::Cool::Instrumenter', Class.new)
         | 
| 44 | 
            -
                  ENV['FLIPPER_INSTRUMENTER'] = 'My::Cool::Instrumenter'
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                  subject
         | 
| 47 | 
            -
                  expect(config.instrumenter).to eq(My::Cool::Instrumenter)
         | 
| 48 | 
            -
                end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                it 'can set log from ENV' do
         | 
| 51 | 
            -
                  ENV['FLIPPER_LOG'] = 'false'
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                  subject
         | 
| 54 | 
            -
                  expect(config.log).to eq(false)
         | 
| 55 | 
            -
                end
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                it 'sets defaults' do
         | 
| 58 | 
            -
                  subject # initialize
         | 
| 59 | 
            -
                  expect(config.env_key).to eq("flipper")
         | 
| 60 | 
            -
                  expect(config.memoize).to be(true)
         | 
| 61 | 
            -
                  expect(config.preload).to be(true)
         | 
| 62 | 
            -
                end
         | 
| 63 | 
            -
             | 
| 64 | 
            -
                it "configures instrumentor on default instance" do
         | 
| 65 | 
            -
                  subject # initialize
         | 
| 66 | 
            -
                  expect(Flipper.instance.instrumenter).to eq(ActiveSupport::Notifications)
         | 
| 67 | 
            -
                end
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                it 'uses Memoizer middleware if config.memoize = true' do
         | 
| 70 | 
            -
                  initializer { config.memoize = true }
         | 
| 71 | 
            -
                  expect(subject.middleware).to include(Flipper::Middleware::Memoizer)
         | 
| 72 | 
            -
                end
         | 
| 73 | 
            -
             | 
| 74 | 
            -
                it 'does not use Memoizer middleware if config.memoize = false' do
         | 
| 75 | 
            -
                  initializer { config.memoize = false }
         | 
| 76 | 
            -
                  expect(subject.middleware).not_to include(Flipper::Middleware::Memoizer)
         | 
| 77 | 
            -
                end
         | 
| 78 | 
            -
             | 
| 79 | 
            -
                it 'passes config to memoizer' do
         | 
| 80 | 
            -
                  initializer do
         | 
| 81 | 
            -
                    config.update(
         | 
| 82 | 
            -
                      env_key: 'my_flipper',
         | 
| 83 | 
            -
                      preload: [:stats, :search]
         | 
| 84 | 
            -
                    )
         | 
| 85 | 
            -
                  end
         | 
| 86 | 
            -
             | 
| 87 | 
            -
                  expect(subject.middleware).to include(Flipper::Middleware::Memoizer)
         | 
| 88 | 
            -
                  middleware = subject.middleware.detect { |m| m.klass == Flipper::Middleware::Memoizer }
         | 
| 89 | 
            -
                  expect(middleware.args[0]).to eq({
         | 
| 90 | 
            -
                    env_key: config.env_key,
         | 
| 91 | 
            -
                    preload: config.preload,
         | 
| 92 | 
            -
                    if: nil
         | 
| 93 | 
            -
                  })
         | 
| 94 | 
            -
                end
         | 
| 95 | 
            -
             | 
| 96 | 
            -
                it "defines #flipper_id on AR::Base" do
         | 
| 97 | 
            -
                  subject
         | 
| 98 | 
            -
                  require 'active_record'
         | 
| 99 | 
            -
                  expect(ActiveRecord::Base.ancestors).to include(Flipper::Identifier)
         | 
| 100 | 
            -
                end
         | 
| 101 | 
            -
              end
         | 
| 102 | 
            -
             | 
| 103 | 
            -
              # Add app initializer in the same order as config/initializers/*
         | 
| 104 | 
            -
              def initializer(&block)
         | 
| 105 | 
            -
                application.initializer 'spec', before: :load_config_initializers do
         | 
| 106 | 
            -
                  block.call
         | 
| 107 | 
            -
                end
         | 
| 108 | 
            -
              end
         | 
| 109 | 
            -
            end
         |