Skip to content

Commit 8cea7d0

Browse files
authored
feat: Implement Requirement 1.1.2 (#78)
Signed-off-by: Max VelDink <[email protected]>
1 parent 2d89570 commit 8cea7d0

File tree

7 files changed

+113
-23
lines changed

7 files changed

+113
-23
lines changed

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,30 @@ object = client.fetch_object_value(flag_key: 'object_value', default_value: JSON
6565

6666
For complete documentation, visit: https://openfeature.dev/docs/category/concepts
6767

68+
### Providers
69+
70+
Providers are the abstraction layer between OpenFeature and different flag management systems.
71+
72+
The `NoOpProvider` is an example of a minimalist provider. For complete documentation on the Provider interface, visit: https://openfeature.dev/specification/sections/providers.
73+
74+
In addition to the `fetch_*` methods, providers can optionally implement lifecycle methods that are invoked when the underlying provider is switched out. For example:
75+
76+
```ruby
77+
class MyProvider
78+
def init
79+
# Perform any initialization steps with flag management system here
80+
# Return value is ignored
81+
end
82+
83+
def shutdown
84+
# Perform any shutdown/reclamation steps with flag management system here
85+
# Return value is ignored
86+
end
87+
end
88+
```
89+
90+
**Note** The OpenFeature spec defines a lifecycle method called `initialize` to be called when a new provider is set. To avoid conflicting with the Ruby `initialize` method, this method should be named `init` when creating a provider.
91+
6892
## Contributing
6993

7094
See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to the OpenFeature project.

lib/open_feature/sdk/api.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ module SDK
2727
#
2828
# client = OpenFeature::SDK::API.instance.build_client(name: 'my-open-feature-client')
2929
class API
30-
include Singleton
30+
include Singleton # Satisfies Flag Evaluation API Requirement 1.1.1
3131
extend Forwardable
3232

33-
def_delegators :configuration, :provider, :hooks, :context
33+
def_delegators :configuration, :provider, :provider=, :hooks, :context
3434

3535
def configuration
3636
@configuration ||= Configuration.new

lib/open_feature/sdk/configuration.rb

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,26 @@ module SDK
1313
class Configuration
1414
extend Forwardable
1515

16-
attr_accessor :context, :provider, :hooks
16+
attr_accessor :context, :hooks
17+
attr_reader :provider
1718

1819
def_delegator :@provider, :metadata
1920

2021
def initialize
2122
@hooks = []
2223
end
24+
25+
# When switching providers, there are a few lifecycle methods that need to be taken care of.
26+
# 1. If a provider is already set, we need to call `shutdown` on it.
27+
# 2. On the new provider, call `init`.
28+
# 3. Finally, set the internal provider to the new provider
29+
def provider=(provider)
30+
@provider.shutdown if @provider.respond_to?(:shutdown)
31+
32+
provider.init if provider.respond_to?(:init)
33+
34+
@provider = provider
35+
end
2336
end
2437
end
2538
end

spec/open_feature/sdk/api_spec.rb

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,6 @@
77
RSpec.describe OpenFeature::SDK::API do
88
subject(:api) { described_class.instance }
99

10-
context "with Requirement 1.1.2" do
11-
before do
12-
api.configure do |config|
13-
config.provider = OpenFeature::SDK::Provider::NoOpProvider.new
14-
end
15-
end
16-
17-
it do
18-
expect(api).to respond_to(:provider)
19-
end
20-
21-
it do
22-
expect(api.provider).not_to be_nil
23-
end
24-
25-
it do
26-
expect(api.provider).is_a?(OpenFeature::SDK::Provider)
27-
end
28-
end
29-
3010
context "with Requirement 1.1.3" do
3111
before do
3212
api.configure do |config|
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# frozen_string_literal: true
2+
3+
require "spec_helper"
4+
5+
RSpec.describe OpenFeature::SDK::Configuration do
6+
subject(:configuration) { described_class.new }
7+
8+
describe "#provider=" do
9+
context "when provider has an init method" do
10+
let(:provider) { TestProvider.new }
11+
12+
it "inits and sets the provider" do
13+
expect(provider).to receive(:init)
14+
15+
configuration.provider = provider
16+
17+
expect(configuration.provider).to be(provider)
18+
end
19+
end
20+
21+
context "when provider does not have an init method" do
22+
it "sets the provider" do
23+
provider = OpenFeature::SDK::Provider::NoOpProvider.new
24+
25+
configuration.provider = provider
26+
27+
expect(configuration.provider).to be(provider)
28+
end
29+
end
30+
end
31+
end

spec/specification/flag_evaluation_api_spec.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# frozen_string_literal: true
22

33
require "spec_helper"
4+
require_relative "../support/test_provider"
45

56
RSpec.describe "Flag Evaluation API" do
67
context "1.1 - API Initialization and Configuration" do
@@ -9,5 +10,37 @@
910
expect(OpenFeature::SDK::API).to include(Singleton)
1011
end
1112
end
13+
14+
context "Requirement 1.1.2.1" do
15+
specify "the API must define a provider mutator" do
16+
provider = OpenFeature::SDK::Provider::NoOpProvider.new
17+
18+
OpenFeature::SDK.provider = provider
19+
20+
expect(OpenFeature::SDK.provider).to be(provider)
21+
end
22+
end
23+
24+
context "Requirement 1.1.2.2" do
25+
specify "the provider mutator must invoke an initialize function on the provider" do
26+
provider = TestProvider.new
27+
expect(provider).to receive(:init)
28+
29+
OpenFeature::SDK.provider = provider
30+
end
31+
end
32+
33+
context "Requirement 1.1.2.3" do
34+
specify "the provider mutator must invoke a shutdown function on previously registered provider" do
35+
previous_provider = TestProvider.new
36+
new_provider = TestProvider.new
37+
38+
expect(previous_provider).to receive(:shutdown)
39+
expect(new_provider).not_to receive(:shutdown)
40+
41+
OpenFeature::SDK.provider = previous_provider
42+
OpenFeature::SDK.provider = new_provider
43+
end
44+
end
1245
end
1346
end

spec/support/test_provider.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# frozen_string_literal: true
2+
3+
class TestProvider
4+
def init
5+
end
6+
7+
def shutdown
8+
end
9+
end

0 commit comments

Comments
 (0)