diff --git a/README.md b/README.md
index 421997a..218cf6b 100644
--- a/README.md
+++ b/README.md
@@ -42,13 +42,15 @@ require 'json' # For JSON.dump
# API Initialization and configuration
OpenFeature::SDK.configure do |config|
- # your provider of choice
- config.provider = OpenFeature::SDK::Provider::InMemoryProvider.new(
- {
- "flag1" => true,
- "flag2" => 1
- }
- )
+ # your provider of choice, which will be used as the default provider
+ config.set_provider(OpenFeature::SDK::Provider::InMemoryProvider.new(
+ {
+ "flag1" => true,
+ "flag2" => 1
+ }
+ ))
+ # alternatively, you can bind multiple providers to different domains
+ config.set_provider(OpenFeature::SDK::Provider::NoOpProvider.new, domain: "legacy_flags")
end
# Create a client
diff --git a/lib/open_feature/sdk/api.rb b/lib/open_feature/sdk/api.rb
index e58198d..7ad7e2f 100644
--- a/lib/open_feature/sdk/api.rb
+++ b/lib/open_feature/sdk/api.rb
@@ -19,7 +19,7 @@ module SDK
# To use the SDK, you can optionally configure a Provider, with Hook
#
# OpenFeature::SDK::API.instance.configure do |config|
- # config.provider = NoOpProvider.new
+ # config.set_provider NoOpProvider.new
# end
#
# If no provider is specified, the NoOpProvider is set as the default Provider.
@@ -30,7 +30,7 @@ class API
include Singleton # Satisfies Flag Evaluation API Requirement 1.1.1
extend Forwardable
- def_delegators :configuration, :provider, :provider=, :hooks, :context
+ def_delegators :configuration, :provider, :set_provider, :hooks, :context
def configuration
@configuration ||= Configuration.new
diff --git a/lib/open_feature/sdk/configuration.rb b/lib/open_feature/sdk/configuration.rb
index ceed507..19e2c0a 100644
--- a/lib/open_feature/sdk/configuration.rb
+++ b/lib/open_feature/sdk/configuration.rb
@@ -14,24 +14,28 @@ class Configuration
extend Forwardable
attr_accessor :context, :hooks
- attr_reader :provider
- def_delegator :@provider, :metadata
+ def_delegator :provider, :metadata
def initialize
@hooks = []
+ @providers = {}
+ end
+
+ def provider(domain: nil)
+ @providers[domain]
end
# When switching providers, there are a few lifecycle methods that need to be taken care of.
# 1. If a provider is already set, we need to call `shutdown` on it.
# 2. On the new provider, call `init`.
# 3. Finally, set the internal provider to the new provider
- def provider=(provider)
- @provider.shutdown if @provider.respond_to?(:shutdown)
+ def set_provider(provider, domain: nil)
+ @providers[domain].shutdown if @providers[domain].respond_to?(:shutdown)
provider.init if provider.respond_to?(:init)
- @provider = provider
+ @providers[domain] = provider
end
end
end
diff --git a/lib/open_feature/sdk/provider/no_op_provider.rb b/lib/open_feature/sdk/provider/no_op_provider.rb
index c80118b..3939272 100644
--- a/lib/open_feature/sdk/provider/no_op_provider.rb
+++ b/lib/open_feature/sdk/provider/no_op_provider.rb
@@ -11,7 +11,7 @@ module Provider
# To use NoOpProvider, it can be set during the configuration of the SDK
#
# OpenFeature::SDK.configure do |config|
- # config.provider = NoOpProvider.new
+ # config.set_provider NoOpProvider.new
# end
#
# Within the NoOpProvider, the following methods exist
diff --git a/spec/open_feature/sdk/api_spec.rb b/spec/open_feature/sdk/api_spec.rb
index f0163c0..1b3be34 100644
--- a/spec/open_feature/sdk/api_spec.rb
+++ b/spec/open_feature/sdk/api_spec.rb
@@ -10,7 +10,7 @@
context "with Requirement 1.1.3" do
before do
api.configure do |config|
- config.provider = OpenFeature::SDK::Provider::NoOpProvider.new
+ config.set_provider(OpenFeature::SDK::Provider::NoOpProvider.new)
config.hooks << hook1
config.hooks << hook2
end
@@ -28,7 +28,7 @@
context "with Requirement 1.1.4" do
before do
api.configure do |config|
- config.provider = OpenFeature::SDK::Provider::NoOpProvider.new
+ config.set_provider(OpenFeature::SDK::Provider::NoOpProvider.new)
end
end
@@ -52,7 +52,7 @@
context "with Requirement 1.1.5" do
before do
api.configure do |config|
- config.provider = OpenFeature::SDK::Provider::NoOpProvider.new
+ config.set_provider(OpenFeature::SDK::Provider::NoOpProvider.new)
end
api.build_client(name: "requirement-1.1.5")
diff --git a/spec/open_feature/sdk/configuration_spec.rb b/spec/open_feature/sdk/configuration_spec.rb
index 8d98ddc..1d0eb4f 100644
--- a/spec/open_feature/sdk/configuration_spec.rb
+++ b/spec/open_feature/sdk/configuration_spec.rb
@@ -5,27 +5,38 @@
RSpec.describe OpenFeature::SDK::Configuration do
subject(:configuration) { described_class.new }
- describe "#provider=" do
+ describe "#set_provider" do
context "when provider has an init method" do
let(:provider) { OpenFeature::SDK::Provider::InMemoryProvider.new }
it "inits and sets the provider" do
expect(provider).to receive(:init)
- configuration.provider = provider
+ configuration.set_provider(provider)
expect(configuration.provider).to be(provider)
end
end
context "when provider does not have an init method" do
- it "sets the provider" do
+ it "sets the default provider" do
provider = OpenFeature::SDK::Provider::NoOpProvider.new
- configuration.provider = provider
+ configuration.set_provider(provider)
expect(configuration.provider).to be(provider)
end
end
+
+ context "when name is given" do
+ it "binds the provider to that name" do
+ provider = OpenFeature::SDK::Provider::InMemoryProvider.new
+ expect(provider).to receive(:init)
+
+ configuration.set_provider(provider, domain: "testing")
+
+ expect(configuration.provider(domain: "testing")).to be(provider)
+ end
+ end
end
end
diff --git a/spec/specification/flag_evaluation_api_spec.rb b/spec/specification/flag_evaluation_api_spec.rb
index 8f573fc..d76fa4e 100644
--- a/spec/specification/flag_evaluation_api_spec.rb
+++ b/spec/specification/flag_evaluation_api_spec.rb
@@ -14,7 +14,7 @@
specify "the API must define a provider mutator" do
provider = OpenFeature::SDK::Provider::NoOpProvider.new
- OpenFeature::SDK.provider = provider
+ OpenFeature::SDK.set_provider(provider)
expect(OpenFeature::SDK.provider).to be(provider)
end
@@ -25,7 +25,7 @@
provider = OpenFeature::SDK::Provider::InMemoryProvider.new
expect(provider).to receive(:init)
- OpenFeature::SDK.provider = provider
+ OpenFeature::SDK.set_provider(provider)
end
end
@@ -37,8 +37,32 @@
expect(previous_provider).to receive(:shutdown)
expect(new_provider).not_to receive(:shutdown)
- OpenFeature::SDK.provider = previous_provider
- OpenFeature::SDK.provider = new_provider
+ OpenFeature::SDK.set_provider(previous_provider)
+ OpenFeature::SDK.set_provider(new_provider)
+ end
+ end
+
+ context "Requirement 1.1.3" do
+ specify "the API must provide a function to bind a given provider to one or more client names" do
+ first_provider = OpenFeature::SDK::Provider::InMemoryProvider.new
+ second_provider = OpenFeature::SDK::Provider::InMemoryProvider.new
+
+ OpenFeature::SDK.set_provider(first_provider, domain: "first")
+ OpenFeature::SDK.set_provider(second_provider, domain: "second")
+
+ expect(OpenFeature::SDK.provider(domain: "first")).to be(first_provider)
+ expect(OpenFeature::SDK.provider(domain: "second")).to be(second_provider)
+ end
+
+ specify "if client name is already bound, it is overwritten" do
+ previous_provider = OpenFeature::SDK::Provider::InMemoryProvider.new
+ new_provider = OpenFeature::SDK::Provider::InMemoryProvider.new
+
+ OpenFeature::SDK.set_provider(previous_provider, domain: "testing")
+ expect(OpenFeature::SDK.provider(domain: "testing")).to be(previous_provider)
+
+ OpenFeature::SDK.set_provider(new_provider, domain: "testing")
+ expect(OpenFeature::SDK.provider(domain: "testing")).to be(new_provider)
end
end
end