openfeature-flagd-provider 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '080ce76815c057f001cd65068841a1d73287a0f31a68e45e078b09846ebaf926'
4
+ data.tar.gz: 1bbde9f180b72331cfb50541e3d1572c3ed2092ca76f9093969d0bb2329acdc2
5
+ SHA512:
6
+ metadata.gz: 11ecdbebda3241daf7ed79a117ccbf0f90f6e13d8197aebca07f91cf949c4afc26b434b5ebf2a3d36037d4be543580c17250e0584c7ed7efae9e2581a90281a1
7
+ data.tar.gz: fb31f4675243aea5d23deef97270336ec53a9f7a9c2d8ca717f4f18c8de8f11ee23c71ef9cd30ebab06c4b2bf6349b0a8568a900393c65f491c2b0a49a02aa82
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ -I lib
2
+ --format documentation
3
+ --color
4
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,10 @@
1
+ inherit_from: ../../shared_config/.rubocop.yml
2
+
3
+ inherit_mode:
4
+ merge:
5
+ - Exclude
6
+
7
+ AllCops:
8
+ Exclude:
9
+ # gRPC generated files
10
+ - 'lib/openfeature/flagd/provider/flagd/**/*.rb'
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.1.4
data/CHANGELOG.md ADDED
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0](https://github.com/open-feature/ruby-sdk-contrib/compare/openfeature-flagd-provider-v0.0.1...openfeature-flagd-provider/v0.1.0) (2024-05-16)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * update flagd name and grpc schema ([#30](https://github.com/open-feature/ruby-sdk-contrib/issues/30))
9
+
10
+ ### ✨ New Features
11
+
12
+ * Add flagd provider ([#2](https://github.com/open-feature/ruby-sdk-contrib/issues/2)) ([98b695b](https://github.com/open-feature/ruby-sdk-contrib/commit/98b695b05eb1525cb796479be8b36c2751297b98))
13
+ * Add support for unix socket path and secure connection ([#8](https://github.com/open-feature/ruby-sdk-contrib/issues/8)) ([88436c7](https://github.com/open-feature/ruby-sdk-contrib/commit/88436c7175373552bc7cad236297028bb655e12d))
14
+ * Flagd provider uses structs from sdk ([#24](https://github.com/open-feature/ruby-sdk-contrib/issues/24)) ([d437e7f](https://github.com/open-feature/ruby-sdk-contrib/commit/d437e7f72f3790d6c82ce1d006efdd528da7402e))
15
+ * integrate flagd provider with OpenFeature SDK ([#18](https://github.com/open-feature/ruby-sdk-contrib/issues/18)) ([80d6d02](https://github.com/open-feature/ruby-sdk-contrib/commit/80d6d028fbe762fae243d687bba7f9642bb2c116))
16
+ * Return default value on error ([#25](https://github.com/open-feature/ruby-sdk-contrib/issues/25)) ([f365c6d](https://github.com/open-feature/ruby-sdk-contrib/commit/f365c6db6ab8465c39d55764c7715f81d6d7f922))
17
+ * update flagd name and grpc schema ([#30](https://github.com/open-feature/ruby-sdk-contrib/issues/30)) ([ddd438a](https://github.com/open-feature/ruby-sdk-contrib/commit/ddd438abc3c7b6d586c36ea94060c75448e99f27))
18
+
19
+
20
+ ### 🧹 Chore
21
+
22
+ * Format with standard ([#20](https://github.com/open-feature/ruby-sdk-contrib/issues/20)) ([bf25043](https://github.com/open-feature/ruby-sdk-contrib/commit/bf25043f87bdd9cd2bc8527fead8f4a0c3b95eff))
23
+ * Make things work ([#13](https://github.com/open-feature/ruby-sdk-contrib/issues/13)) ([5968037](https://github.com/open-feature/ruby-sdk-contrib/commit/5968037b7290f7f84ca96e621bf136f7c7a42e8a))
24
+ * update link to use new doc domain ([#12](https://github.com/open-feature/ruby-sdk-contrib/issues/12)) ([9baff65](https://github.com/open-feature/ruby-sdk-contrib/commit/9baff65051522705606e336ba1fe614115907418))
25
+ * upgrade grpc client ([#16](https://github.com/open-feature/ruby-sdk-contrib/issues/16)) ([23ed78a](https://github.com/open-feature/ruby-sdk-contrib/commit/23ed78a830c81030e1fb40d0aef04ea5458d2d6d))
26
+
27
+
28
+ ### 🔄 Refactoring
29
+
30
+ * OpenFeature::FlagD::Provider::Configuration ([#14](https://github.com/open-feature/ruby-sdk-contrib/issues/14)) ([3686eb5](https://github.com/open-feature/ruby-sdk-contrib/commit/3686eb5c31ec0e6af97bc74ff58ffb815b78e114))
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in openfeature-flagd-provider.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,92 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ openfeature-flagd-provider (0.1.0)
5
+ grpc (~> 1.50)
6
+ openfeature-sdk (~> 0.3)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ ast (2.4.2)
12
+ diff-lcs (1.5.1)
13
+ google-protobuf (3.25.3-arm64-darwin)
14
+ google-protobuf (3.25.3-x86_64-linux)
15
+ googleapis-common-protos-types (1.14.0)
16
+ google-protobuf (~> 3.18)
17
+ grpc (1.62.0-arm64-darwin)
18
+ google-protobuf (~> 3.25)
19
+ googleapis-common-protos-types (~> 1.0)
20
+ grpc (1.62.0-x86_64-linux)
21
+ google-protobuf (~> 3.25)
22
+ googleapis-common-protos-types (~> 1.0)
23
+ json (2.7.2)
24
+ language_server-protocol (3.17.0.3)
25
+ lint_roller (1.1.0)
26
+ openfeature-sdk (0.3.1)
27
+ parallel (1.24.0)
28
+ parser (3.3.0.5)
29
+ ast (~> 2.4.1)
30
+ racc
31
+ racc (1.7.3)
32
+ rainbow (3.1.1)
33
+ rake (13.2.1)
34
+ regexp_parser (2.9.0)
35
+ rexml (3.2.6)
36
+ rspec (3.12.0)
37
+ rspec-core (~> 3.12.0)
38
+ rspec-expectations (~> 3.12.0)
39
+ rspec-mocks (~> 3.12.0)
40
+ rspec-core (3.12.3)
41
+ rspec-support (~> 3.12.0)
42
+ rspec-expectations (3.12.4)
43
+ diff-lcs (>= 1.2.0, < 2.0)
44
+ rspec-support (~> 3.12.0)
45
+ rspec-mocks (3.12.7)
46
+ diff-lcs (>= 1.2.0, < 2.0)
47
+ rspec-support (~> 3.12.0)
48
+ rspec-support (3.12.2)
49
+ rubocop (1.62.1)
50
+ json (~> 2.3)
51
+ language_server-protocol (>= 3.17.0)
52
+ parallel (~> 1.10)
53
+ parser (>= 3.3.0.2)
54
+ rainbow (>= 2.2.2, < 4.0)
55
+ regexp_parser (>= 1.8, < 3.0)
56
+ rexml (>= 3.2.5, < 4.0)
57
+ rubocop-ast (>= 1.31.1, < 2.0)
58
+ ruby-progressbar (~> 1.7)
59
+ unicode-display_width (>= 2.4.0, < 3.0)
60
+ rubocop-ast (1.31.2)
61
+ parser (>= 3.3.0.4)
62
+ rubocop-performance (1.20.2)
63
+ rubocop (>= 1.48.1, < 2.0)
64
+ rubocop-ast (>= 1.30.0, < 2.0)
65
+ ruby-progressbar (1.13.0)
66
+ standard (1.35.1)
67
+ language_server-protocol (~> 3.17.0.2)
68
+ lint_roller (~> 1.0)
69
+ rubocop (~> 1.62.0)
70
+ standard-custom (~> 1.0.0)
71
+ standard-performance (~> 1.3)
72
+ standard-custom (1.0.2)
73
+ lint_roller (~> 1.0)
74
+ rubocop (~> 1.50)
75
+ standard-performance (1.3.1)
76
+ lint_roller (~> 1.1)
77
+ rubocop-performance (~> 1.20.2)
78
+ unicode-display_width (2.5.0)
79
+
80
+ PLATFORMS
81
+ arm64-darwin-21
82
+ x86_64-linux
83
+
84
+ DEPENDENCIES
85
+ openfeature-flagd-provider!
86
+ rake (~> 13.0)
87
+ rspec (~> 3.12.0)
88
+ rubocop
89
+ standard
90
+
91
+ BUNDLED WITH
92
+ 2.3.25
data/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # OpenFeature flagd Provider for Ruby
2
+
3
+ This is the Ruby [provider](https://openfeature.dev/docs/specification/sections/providers) implementation of the [flagd](https://flagd.dev/)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'openfeature-flagd-provider'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```sh
16
+ bundle install
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```sh
22
+ gem install openfeature-flagd-provider
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ The `OpenFeature::Flagd` supports multiple configuration options that dictate how the SDK communicates with flagd.
28
+ Options can be defined in the constructor or as environment variables, with constructor options having the highest precedence.
29
+
30
+ ### Available options
31
+
32
+ | Option name | Environment variable name | Type | Default |
33
+ | ----------- | ------------------------- | ------- | --------- |
34
+ | host | FLAGD_HOST | string | localhost |
35
+ | port | FLAGD_PORT | number | 8013 |
36
+ | tls | FLAGD_TLS | boolean | false |
37
+ | unix_socket_path | FLAGD_SOCKET_PATH | string | nil |
38
+ | root_cert_path | FLAGD_SERVER_CERT_PATH | string | nil |
39
+
40
+ ### Example using TCP
41
+
42
+ ```ruby
43
+ OpenFeature::SDK.configure do |config|
44
+ # your provider of choice
45
+ config.provider = OpenFeature::Flagd::Provider.configure do |provider_config|
46
+ provider_config.host = "localhost"
47
+ provider_config.port = 8013
48
+ provider_config.tls = false
49
+ end
50
+ end
51
+ ```
52
+
53
+ ### Example using a Unix socket
54
+
55
+ ```ruby
56
+ OpenFeature::SDK.configure do |config|
57
+ # your provider of choice
58
+ config.provider = OpenFeature::Flagd::Provider.configure do |provider_config|
59
+ provider_config.unix_socket_path = "tmp/flagd.sock"
60
+ end
61
+ end
62
+ ```
63
+
64
+
65
+ ### Example using a secure connection
66
+
67
+ ```ruby
68
+ OpenFeature::SDK.configure do |config|
69
+ # your provider of choice
70
+ config.provider = OpenFeature::Flagd::Provider.configure do |provider_config|
71
+ provider_config.host = "localhost"
72
+ provider_config.port = 8013
73
+ provider_config.tls = true
74
+ provider_config.root_cert_path = './ca.pem'
75
+ end
76
+ end
77
+ ```
78
+
79
+ If no environment variables are set the [default configuration](./lib/openfeature/flagd/provider/configuration.rb) is set
80
+
81
+ ## Contributing
82
+
83
+ https://github.com/open-feature/ruby-sdk-contrib
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "openfeature/flagd/provider"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,10 @@
1
+ version: '3.7'
2
+
3
+ services:
4
+ flagd:
5
+ image: ghcr.io/open-feature/flagd:v0.10.1
6
+ ports:
7
+ - '127.0.0.1:8013:8013'
8
+ volumes:
9
+ - ./:/etc/flagd
10
+ command: start -x --uri file:./etc/flagd/flags.json
data/docker/flags.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "$schema": "https://flagd.dev/schema/v0/flags.json",
3
+ "flags": {
4
+ "boolean-flag": {
5
+ "state": "ENABLED",
6
+ "variants": {
7
+ "on": true,
8
+ "off": false
9
+ },
10
+ "defaultVariant": "off"
11
+ },
12
+ "integer-flag": {
13
+ "state": "ENABLED",
14
+ "variants": {
15
+ "fourty-two": 42
16
+ },
17
+ "defaultVariant": "fourty-two"
18
+ },
19
+ "float-flag": {
20
+ "state": "ENABLED",
21
+ "variants": {
22
+ "four-point-two": 4.2
23
+ },
24
+ "defaultVariant": "four-point-two"
25
+ },
26
+ "string-flag": {
27
+ "state": "ENABLED",
28
+ "variants": {
29
+ "lilili": "lalala"
30
+ },
31
+ "defaultVariant": "lilili"
32
+ },
33
+ "object-flag": {
34
+ "state": "ENABLED",
35
+ "variants": {
36
+ "real-object": { "real": "value" }
37
+ },
38
+ "defaultVariant": "real-object"
39
+ },
40
+ "boolean-flag-targeting": {
41
+ "state": "ENABLED",
42
+ "variants": {
43
+ "on": true,
44
+ "off": false
45
+ },
46
+ "defaultVariant": "off",
47
+ "targeting": {
48
+ "if": [
49
+ {
50
+ "==": [
51
+ {
52
+ "var": "be_true"
53
+ },
54
+ true
55
+ ]
56
+ },
57
+ "on"
58
+ ]
59
+ }
60
+ },
61
+ "color-palette-experiment": {
62
+ "state": "ENABLED",
63
+ "defaultVariant": "grey",
64
+ "variants": {
65
+ "red": "#b91c1c",
66
+ "blue": "#0284c7",
67
+ "green": "#16a34a",
68
+ "grey": "#4b5563"
69
+ },
70
+ "targeting": {
71
+ "fractional": [
72
+ [
73
+ "red",
74
+ 25
75
+ ],
76
+ [
77
+ "blue",
78
+ 25
79
+ ],
80
+ [
81
+ "green",
82
+ 25
83
+ ],
84
+ [
85
+ "grey",
86
+ 25
87
+ ]
88
+ ]
89
+ }
90
+ }
91
+ }
92
+ }
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "grpc"
4
+ require "google/protobuf/well_known_types"
5
+
6
+ require_relative "flagd/evaluation/v1/evaluation_services_pb"
7
+ require_relative "configuration"
8
+
9
+ module OpenFeature
10
+ module Flagd
11
+ module Provider
12
+ # Client represents a wrapper for the GRPC stub that allows for resolution of boolean, string, number, and object
13
+ # values. The implementation follows the details specified in https://openfeature.dev/docs/specification/sections/providers
14
+ #
15
+ #
16
+ # The Client provides the following methods and attributes:
17
+ #
18
+ # * <tt>metadata</tt> - Returns the associated provider metadata with the name
19
+ #
20
+ # * <tt>fetch_boolean_value(flag_key:, default_value:, evaluation_context: nil)</tt>
21
+ # manner; <tt>client.fetch_boolean(flag_key: 'boolean-flag', default_value: false)</tt>
22
+ #
23
+ # * <tt>fetch_integer_value(flag_key:, default_value:, evaluation_context: nil)</tt>
24
+ # manner; <tt>client.fetch_integer_value(flag_key: 'integer-flag', default_value: 2)</tt>
25
+ #
26
+ # * <tt>fetch_float_value(flag_key:, default_value:, evaluation_context: nil)</tt>
27
+ # manner; <tt>client.fetch_float_value(flag_key: 'float-flag', default_value: 2.0)</tt>
28
+ #
29
+ # * <tt>fetch_string_value(flag_key:, default_value:, evaluation_context: nil)</tt>
30
+ # manner; <tt>client.fetch_string_value(flag_key: 'string-flag', default_value: 'some-default-value')</tt>
31
+ #
32
+ # * <tt>fetch_object_value(flag_key:, default_value:, evaluation_context: nil)</tt>
33
+ # manner; <tt>client.fetch_object_value(flag_key: 'flag', default_value: { default_value: 'value'})</tt>
34
+ class Client
35
+ PROVIDER_NAME = "flagd Provider"
36
+
37
+ attr_reader :metadata
38
+
39
+ def initialize(configuration: nil)
40
+ @metadata = OpenFeature::SDK::Provider::ProviderMetadata.new(name: PROVIDER_NAME)
41
+ @grpc_client = grpc_client(configuration)
42
+ end
43
+
44
+ def fetch_boolean_value(flag_key:, default_value:, evaluation_context: nil)
45
+ request = Grpc::Evaluation::ResolveBooleanRequest.new(flag_key: flag_key, context: prepare_evaluation_context(evaluation_context))
46
+ process_request(default_value) { @grpc_client.resolve_boolean(request) }
47
+ end
48
+
49
+ def fetch_number_value(flag_key:, default_value:, evaluation_context: nil)
50
+ case default_value
51
+ when Integer
52
+ fetch_integer_value(flag_key: flag_key, default_value: default_value, evaluation_context: evaluation_context)
53
+ when Float
54
+ fetch_float_value(flag_key: flag_key, default_value: default_value, evaluation_context: evaluation_context)
55
+ end
56
+ end
57
+
58
+ def fetch_integer_value(flag_key:, default_value:, evaluation_context: nil)
59
+ request = Grpc::Evaluation::ResolveIntRequest.new(flag_key: flag_key, context: prepare_evaluation_context(evaluation_context))
60
+ process_request(default_value) { @grpc_client.resolve_int(request) }
61
+ end
62
+
63
+ def fetch_float_value(flag_key:, default_value:, evaluation_context: nil)
64
+ request = Grpc::Evaluation::ResolveFloatRequest.new(flag_key: flag_key, context: prepare_evaluation_context(evaluation_context))
65
+ process_request(default_value) { @grpc_client.resolve_float(request) }
66
+ end
67
+
68
+ def fetch_string_value(flag_key:, default_value:, evaluation_context: nil)
69
+ request = Grpc::Evaluation::ResolveStringRequest.new(flag_key: flag_key, context: prepare_evaluation_context(evaluation_context))
70
+ process_request(default_value) { @grpc_client.resolve_string(request) }
71
+ end
72
+
73
+ def fetch_object_value(flag_key:, default_value:, evaluation_context: nil)
74
+ request = Grpc::Evaluation::ResolveObjectRequest.new(flag_key: flag_key, context: prepare_evaluation_context(evaluation_context))
75
+ process_request(default_value) { @grpc_client.resolve_object(request) }
76
+ end
77
+
78
+ private
79
+
80
+ def process_request(default_value, &block)
81
+ response = block.call
82
+ OpenFeature::SDK::Provider::ResolutionDetails.new(
83
+ value: response.value,
84
+ reason: response.reason,
85
+ variant: response.variant,
86
+ error_code: nil,
87
+ error_message: nil,
88
+ flag_metadata: nil
89
+ )
90
+ rescue GRPC::NotFound => e
91
+ error_response(default_value, "FLAG_NOT_FOUND", e.message)
92
+ rescue GRPC::InvalidArgument => e
93
+ error_response(default_value, "TYPE_MISMATCH", e.message)
94
+ rescue GRPC::Unavailable => e
95
+ error_response(default_value, "FLAG_NOT_FOUND", e.message)
96
+ rescue GRPC::DataLoss => e
97
+ error_response(default_value, "PARSE_ERROR", e.message)
98
+ rescue => e
99
+ error_response(default_value, "GENERAL", e.message)
100
+ end
101
+
102
+ def prepare_evaluation_context(evaluation_context)
103
+ return nil unless evaluation_context
104
+
105
+ fields = evaluation_context.fields
106
+ fields["targetingKey"] = fields.delete(:targeting_key)
107
+ Google::Protobuf::Struct.from_hash(fields)
108
+ end
109
+
110
+ def error_response(default_value, error_code, error_message)
111
+ OpenFeature::SDK::Provider::ResolutionDetails.new(
112
+ value: default_value,
113
+ reason: "ERROR",
114
+ variant: nil,
115
+ error_code: error_code,
116
+ error_message: error_message,
117
+ flag_metadata: nil
118
+ )
119
+ end
120
+
121
+ def grpc_client(configuration)
122
+ options = :this_channel_is_insecure
123
+ if configuration.tls
124
+ options = GRPC::Core::ChannelCredentials.new(
125
+ configuration.root_cert_path
126
+ )
127
+ end
128
+
129
+ Grpc::Evaluation::Service::Stub.new(server_address(configuration), options).freeze
130
+ end
131
+
132
+ def server_address(configuration)
133
+ if configuration.unix_socket_path
134
+ "unix://#{configuration.unix_socket_path}"
135
+ else
136
+ "#{configuration.host}:#{configuration.port}"
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenFeature
4
+ module Flagd
5
+ module Provider
6
+ # Represents the configuration object for the Flagd provider,
7
+ # This class is not meant to be interacted with directly but instead through the
8
+ # <tt>OpenFeature::Flagd::Provider.configure</tt> method
9
+ class Configuration < Struct.new(:host, :port, :tls, :unix_socket_path, :root_cert_path, keyword_init: true)
10
+ ENVIRONMENT_CONFIG_NAME = {
11
+ host: "FLAGD_HOST",
12
+ port: "FLAGD_PORT",
13
+ tls: "FLAGD_TLS",
14
+ unix_socket_path: "FLAGD_SOCKET_PATH",
15
+ root_cert_path: "FLAGD_SERVER_CERT_PATH"
16
+ }.freeze
17
+
18
+ class << self
19
+ def default_config
20
+ new(host: "localhost", port: 8013, tls: false, unix_socket_path: nil, root_cert_path: nil)
21
+ end
22
+
23
+ def environment_variables_config
24
+ new(
25
+ host: ENV.fetch(ENVIRONMENT_CONFIG_NAME[:host], nil),
26
+ port: ENV[ENVIRONMENT_CONFIG_NAME[:port]].nil? ? nil : Integer(ENV[ENVIRONMENT_CONFIG_NAME[:port]]),
27
+ tls: ENV[ENVIRONMENT_CONFIG_NAME[:tls]].nil? ? nil : ENV.fetch(ENVIRONMENT_CONFIG_NAME[:tls], nil) == "true",
28
+ unix_socket_path: ENV.fetch(ENVIRONMENT_CONFIG_NAME[:unix_socket_path], nil),
29
+ root_cert_path: ENV.fetch(ENVIRONMENT_CONFIG_NAME[:root_cert_path], nil)
30
+ )
31
+ end
32
+ end
33
+
34
+ def merge(other_configuration)
35
+ return self if other_configuration.nil?
36
+
37
+ self.class.new(**to_h.compact.merge(other_configuration.to_h.compact))
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: flagd/evaluation/v1/evaluation.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'google/protobuf/struct_pb'
8
+
9
+
10
+ descriptor_data = "\n$flagd/evaluation/v1/evaluation.proto\x12\x13\x66lagd.evaluation.v1\x1a\x1cgoogle/protobuf/struct.proto\"F\n\x11ResolveAllRequest\x12\x31\n\x07\x63ontext\x18\x01 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x63ontext\"\xb6\x01\n\x12ResolveAllResponse\x12H\n\x05\x66lags\x18\x01 \x03(\x0b\x32\x32.flagd.evaluation.v1.ResolveAllResponse.FlagsEntryR\x05\x66lags\x1aV\n\nFlagsEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x32\n\x05value\x18\x02 \x01(\x0b\x32\x1c.flagd.evaluation.v1.AnyFlagR\x05value:\x02\x38\x01\"\xed\x01\n\x07\x41nyFlag\x12\x16\n\x06reason\x18\x01 \x01(\tR\x06reason\x12\x18\n\x07variant\x18\x02 \x01(\tR\x07variant\x12\x1f\n\nbool_value\x18\x03 \x01(\x08H\x00R\tboolValue\x12#\n\x0cstring_value\x18\x04 \x01(\tH\x00R\x0bstringValue\x12#\n\x0c\x64ouble_value\x18\x05 \x01(\x01H\x00R\x0b\x64oubleValue\x12<\n\x0cobject_value\x18\x06 \x01(\x0b\x32\x17.google.protobuf.StructH\x00R\x0bobjectValueB\x07\n\x05value\"e\n\x15ResolveBooleanRequest\x12\x19\n\x08\x66lag_key\x18\x01 \x01(\tR\x07\x66lagKey\x12\x31\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x63ontext\"\x95\x01\n\x16ResolveBooleanResponse\x12\x14\n\x05value\x18\x01 \x01(\x08R\x05value\x12\x16\n\x06reason\x18\x02 \x01(\tR\x06reason\x12\x18\n\x07variant\x18\x03 \x01(\tR\x07variant\x12\x33\n\x08metadata\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\"d\n\x14ResolveStringRequest\x12\x19\n\x08\x66lag_key\x18\x01 \x01(\tR\x07\x66lagKey\x12\x31\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x63ontext\"\x94\x01\n\x15ResolveStringResponse\x12\x14\n\x05value\x18\x01 \x01(\tR\x05value\x12\x16\n\x06reason\x18\x02 \x01(\tR\x06reason\x12\x18\n\x07variant\x18\x03 \x01(\tR\x07variant\x12\x33\n\x08metadata\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\"c\n\x13ResolveFloatRequest\x12\x19\n\x08\x66lag_key\x18\x01 \x01(\tR\x07\x66lagKey\x12\x31\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x63ontext\"\x93\x01\n\x14ResolveFloatResponse\x12\x14\n\x05value\x18\x01 \x01(\x01R\x05value\x12\x16\n\x06reason\x18\x02 \x01(\tR\x06reason\x12\x18\n\x07variant\x18\x03 \x01(\tR\x07variant\x12\x33\n\x08metadata\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\"a\n\x11ResolveIntRequest\x12\x19\n\x08\x66lag_key\x18\x01 \x01(\tR\x07\x66lagKey\x12\x31\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x63ontext\"\x91\x01\n\x12ResolveIntResponse\x12\x14\n\x05value\x18\x01 \x01(\x03R\x05value\x12\x16\n\x06reason\x18\x02 \x01(\tR\x06reason\x12\x18\n\x07variant\x18\x03 \x01(\tR\x07variant\x12\x33\n\x08metadata\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\"d\n\x14ResolveObjectRequest\x12\x19\n\x08\x66lag_key\x18\x01 \x01(\tR\x07\x66lagKey\x12\x31\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x63ontext\"\xad\x01\n\x15ResolveObjectResponse\x12-\n\x05value\x18\x01 \x01(\x0b\x32\x17.google.protobuf.StructR\x05value\x12\x16\n\x06reason\x18\x02 \x01(\tR\x06reason\x12\x18\n\x07variant\x18\x03 \x01(\tR\x07variant\x12\x33\n\x08metadata\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\"V\n\x13\x45ventStreamResponse\x12\x12\n\x04type\x18\x01 \x01(\tR\x04type\x12+\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructR\x04\x64\x61ta\"\x14\n\x12\x45ventStreamRequest2\xd9\x05\n\x07Service\x12_\n\nResolveAll\x12&.flagd.evaluation.v1.ResolveAllRequest\x1a\'.flagd.evaluation.v1.ResolveAllResponse\"\x00\x12k\n\x0eResolveBoolean\x12*.flagd.evaluation.v1.ResolveBooleanRequest\x1a+.flagd.evaluation.v1.ResolveBooleanResponse\"\x00\x12h\n\rResolveString\x12).flagd.evaluation.v1.ResolveStringRequest\x1a*.flagd.evaluation.v1.ResolveStringResponse\"\x00\x12\x65\n\x0cResolveFloat\x12(.flagd.evaluation.v1.ResolveFloatRequest\x1a).flagd.evaluation.v1.ResolveFloatResponse\"\x00\x12_\n\nResolveInt\x12&.flagd.evaluation.v1.ResolveIntRequest\x1a\'.flagd.evaluation.v1.ResolveIntResponse\"\x00\x12h\n\rResolveObject\x12).flagd.evaluation.v1.ResolveObjectRequest\x1a*.flagd.evaluation.v1.ResolveObjectResponse\"\x00\x12\x64\n\x0b\x45ventStream\x12\'.flagd.evaluation.v1.EventStreamRequest\x1a(.flagd.evaluation.v1.EventStreamResponse\"\x00\x30\x01\x42\xc6\x01\n%dev.openfeature.flagd.grpc.evaluationZ\x13\x66lagd/evaluation/v1\xaa\x02!OpenFeature.Flagd.Grpc.Evaluation\xca\x02\x32OpenFeature\\Providers\\Flagd\\Schema\\Grpc\\Evaluation\xea\x02.OpenFeature::Flagd::Provider::Grpc::Evaluationb\x06proto3"
11
+
12
+ pool = Google::Protobuf::DescriptorPool.generated_pool
13
+
14
+ begin
15
+ pool.add_serialized_file(descriptor_data)
16
+ rescue TypeError => e
17
+ # Compatibility code: will be removed in the next major version.
18
+ require 'google/protobuf/descriptor_pb'
19
+ parsed = Google::Protobuf::FileDescriptorProto.decode(descriptor_data)
20
+ parsed.clear_dependency
21
+ serialized = parsed.class.encode(parsed)
22
+ file = pool.add_serialized_file(serialized)
23
+ warn "Warning: Protobuf detected an import path issue while loading generated file #{__FILE__}"
24
+ imports = [
25
+ ["google.protobuf.Struct", "google/protobuf/struct.proto"],
26
+ ]
27
+ imports.each do |type_name, expected_filename|
28
+ import_file = pool.lookup(type_name).file_descriptor
29
+ if import_file.name != expected_filename
30
+ warn "- #{file.name} imports #{expected_filename}, but that import was loaded as #{import_file.name}"
31
+ end
32
+ end
33
+ warn "Each proto file must use a consistent fully-qualified name."
34
+ warn "This will become an error in the next major version."
35
+ end
36
+
37
+ module OpenFeature
38
+ module Flagd
39
+ module Provider
40
+ module Grpc
41
+ module Evaluation
42
+ ResolveAllRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveAllRequest").msgclass
43
+ ResolveAllResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveAllResponse").msgclass
44
+ AnyFlag = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.AnyFlag").msgclass
45
+ ResolveBooleanRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveBooleanRequest").msgclass
46
+ ResolveBooleanResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveBooleanResponse").msgclass
47
+ ResolveStringRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveStringRequest").msgclass
48
+ ResolveStringResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveStringResponse").msgclass
49
+ ResolveFloatRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveFloatRequest").msgclass
50
+ ResolveFloatResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveFloatResponse").msgclass
51
+ ResolveIntRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveIntRequest").msgclass
52
+ ResolveIntResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveIntResponse").msgclass
53
+ ResolveObjectRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveObjectRequest").msgclass
54
+ ResolveObjectResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveObjectResponse").msgclass
55
+ EventStreamResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.EventStreamResponse").msgclass
56
+ EventStreamRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.EventStreamRequest").msgclass
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,44 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # Source: flagd/evaluation/v1/evaluation.proto for package 'OpenFeature.Flagd.Provider.Grpc.Evaluation'
3
+ # Original file comments:
4
+ # *
5
+ # Flag evaluation API
6
+ #
7
+ # This proto forms the basis of a flag-evaluation API.
8
+ # It supports single and bulk evaluation RPCs, and flags of various types, as well as establishing a stream for getting notifications about changes in a flag definition.
9
+ # It supports the inclusion of a "context" with each evaluation, which may contain arbitrary attributes relevant to flag evaluation.
10
+
11
+ require 'grpc'
12
+ require_relative 'evaluation_pb'
13
+
14
+ module OpenFeature
15
+ module Flagd
16
+ module Provider
17
+ module Grpc
18
+ module Evaluation
19
+ module Service
20
+ # Service defines the exposed rpcs of flagd
21
+ class Service
22
+
23
+ include ::GRPC::GenericService
24
+
25
+ self.marshal_class_method = :encode
26
+ self.unmarshal_class_method = :decode
27
+ self.service_name = 'flagd.evaluation.v1.Service'
28
+
29
+ rpc :ResolveAll, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveAllRequest, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveAllResponse
30
+ rpc :ResolveBoolean, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveBooleanRequest, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveBooleanResponse
31
+ rpc :ResolveString, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveStringRequest, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveStringResponse
32
+ rpc :ResolveFloat, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveFloatRequest, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveFloatResponse
33
+ rpc :ResolveInt, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveIntRequest, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveIntResponse
34
+ rpc :ResolveObject, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveObjectRequest, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveObjectResponse
35
+ rpc :EventStream, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::EventStreamRequest, stream(::OpenFeature::Flagd::Provider::Grpc::Evaluation::EventStreamResponse)
36
+ end
37
+
38
+ Stub = Service.rpc_stub_class
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: flagd/sync/v1/sync.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'google/protobuf/struct_pb'
8
+
9
+
10
+ descriptor_data = "\n\x18\x66lagd/sync/v1/sync.proto\x12\rflagd.sync.v1\x1a\x1cgoogle/protobuf/struct.proto\"O\n\x10SyncFlagsRequest\x12\x1f\n\x0bprovider_id\x18\x01 \x01(\tR\nproviderId\x12\x1a\n\x08selector\x18\x02 \x01(\tR\x08selector\"B\n\x11SyncFlagsResponse\x12-\n\x12\x66lag_configuration\x18\x01 \x01(\tR\x11\x66lagConfiguration\"S\n\x14\x46\x65tchAllFlagsRequest\x12\x1f\n\x0bprovider_id\x18\x01 \x01(\tR\nproviderId\x12\x1a\n\x08selector\x18\x02 \x01(\tR\x08selector\"F\n\x15\x46\x65tchAllFlagsResponse\x12-\n\x12\x66lag_configuration\x18\x01 \x01(\tR\x11\x66lagConfiguration\"\x14\n\x12GetMetadataRequest\"P\n\x13GetMetadataResponse\x12\x33\n\x08metadata\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadataJ\x04\x08\x01\x10\x02\x32\x9b\x02\n\x0f\x46lagSyncService\x12R\n\tSyncFlags\x12\x1f.flagd.sync.v1.SyncFlagsRequest\x1a .flagd.sync.v1.SyncFlagsResponse\"\x00\x30\x01\x12\\\n\rFetchAllFlags\x12#.flagd.sync.v1.FetchAllFlagsRequest\x1a$.flagd.sync.v1.FetchAllFlagsResponse\"\x00\x12V\n\x0bGetMetadata\x12!.flagd.sync.v1.GetMetadataRequest\x1a\".flagd.sync.v1.GetMetadataResponse\"\x00\x42\xa8\x01\n\x1f\x64\x65v.openfeature.flagd.grpc.syncZ\rflagd/sync/v1\xaa\x02\x1bOpenFeature.Flagd.Grpc.Sync\xca\x02,OpenFeature\\Providers\\Flagd\\Schema\\Grpc\\Sync\xea\x02(OpenFeature::Flagd::Provider::Grpc::Syncb\x06proto3"
11
+
12
+ pool = Google::Protobuf::DescriptorPool.generated_pool
13
+
14
+ begin
15
+ pool.add_serialized_file(descriptor_data)
16
+ rescue TypeError => e
17
+ # Compatibility code: will be removed in the next major version.
18
+ require 'google/protobuf/descriptor_pb'
19
+ parsed = Google::Protobuf::FileDescriptorProto.decode(descriptor_data)
20
+ parsed.clear_dependency
21
+ serialized = parsed.class.encode(parsed)
22
+ file = pool.add_serialized_file(serialized)
23
+ warn "Warning: Protobuf detected an import path issue while loading generated file #{__FILE__}"
24
+ imports = [
25
+ ["google.protobuf.Struct", "google/protobuf/struct.proto"],
26
+ ]
27
+ imports.each do |type_name, expected_filename|
28
+ import_file = pool.lookup(type_name).file_descriptor
29
+ if import_file.name != expected_filename
30
+ warn "- #{file.name} imports #{expected_filename}, but that import was loaded as #{import_file.name}"
31
+ end
32
+ end
33
+ warn "Each proto file must use a consistent fully-qualified name."
34
+ warn "This will become an error in the next major version."
35
+ end
36
+
37
+ module OpenFeature
38
+ module Flagd
39
+ module Provider
40
+ module Grpc
41
+ module Sync
42
+ SyncFlagsRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.sync.v1.SyncFlagsRequest").msgclass
43
+ SyncFlagsResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.sync.v1.SyncFlagsResponse").msgclass
44
+ FetchAllFlagsRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.sync.v1.FetchAllFlagsRequest").msgclass
45
+ FetchAllFlagsResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.sync.v1.FetchAllFlagsResponse").msgclass
46
+ GetMetadataRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.sync.v1.GetMetadataRequest").msgclass
47
+ GetMetadataResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.sync.v1.GetMetadataResponse").msgclass
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,39 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # Source: flagd/sync/v1/sync.proto for package 'OpenFeature.Flagd.Provider.Grpc.Sync'
3
+ # Original file comments:
4
+ # *
5
+ # Flag definition sync API
6
+ #
7
+ # This proto defines a simple API to synchronize a feature flag definition.
8
+ # It supports establishing a stream for getting notifications about changes in a flag definition.
9
+
10
+ require 'grpc'
11
+ require 'flagd/sync/v1/sync_pb'
12
+
13
+ module OpenFeature
14
+ module Flagd
15
+ module Provider
16
+ module Grpc
17
+ module Sync
18
+ module FlagSyncService
19
+ # FlagService implements a server streaming to provide realtime flag configurations
20
+ class Service
21
+
22
+ include ::GRPC::GenericService
23
+
24
+ self.marshal_class_method = :encode
25
+ self.unmarshal_class_method = :decode
26
+ self.service_name = 'flagd.sync.v1.FlagSyncService'
27
+
28
+ rpc :SyncFlags, ::OpenFeature::Flagd::Provider::Grpc::Sync::SyncFlagsRequest, stream(::OpenFeature::Flagd::Provider::Grpc::Sync::SyncFlagsResponse)
29
+ rpc :FetchAllFlags, ::OpenFeature::Flagd::Provider::Grpc::Sync::FetchAllFlagsRequest, ::OpenFeature::Flagd::Provider::Grpc::Sync::FetchAllFlagsResponse
30
+ rpc :GetMetadata, ::OpenFeature::Flagd::Provider::Grpc::Sync::GetMetadataRequest, ::OpenFeature::Flagd::Provider::Grpc::Sync::GetMetadataResponse
31
+ end
32
+
33
+ Stub = Service.rpc_stub_class
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenFeature
4
+ module Flagd
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "grpc"
4
+
5
+ require_relative "provider/configuration"
6
+ require_relative "provider/client"
7
+ require_relative "provider/version"
8
+
9
+ module OpenFeature
10
+ module Flagd
11
+ # Provider represents the entry point for interacting with the Flagd provider
12
+ # values. The implementation follows the details specified in https://openfeature.dev/docs/specification/sections/providers
13
+ #
14
+ # Provider contains functionality to configure the GRPC connection via
15
+ # flagd_client = OpenFeature::Flagd::Provider.get_client
16
+ # flagd_client.configure do |config|
17
+ # config.host = 'localhost'
18
+ # config.port = 8379
19
+ # config.tls = false
20
+ # end
21
+ # The Provider provides the following methods and attributes:
22
+ #
23
+ # * <tt>metadata</tt> - Returns the associated provider metadata with the name
24
+ #
25
+ # * <tt>resolve_boolean_value(flag_key:, default_value:, context: nil)</tt>
26
+ # manner; <tt>client.resolve_boolean(flag_key: 'boolean-flag', default_value: false)</tt>
27
+ #
28
+ # * <tt>resolve_integer_value(flag_key:, default_value:, context: nil)</tt>
29
+ # manner; <tt>client.resolve_integer_value(flag_key: 'integer-flag', default_value: 2)</tt>
30
+ #
31
+ # * <tt>resolve_float_value(flag_key:, default_value:, context: nil)</tt>
32
+ # manner; <tt>client.resolve_float_value(flag_key: 'float-flag', default_value: 2.0)</tt>
33
+ #
34
+ # * <tt>resolve_string_value(flag_key:, default_value:, context: nil)</tt>
35
+ # manner; <tt>client.resolve_string_value(flag_key: 'string-flag', default_value: 'some-default-value')</tt>
36
+ #
37
+ # * <tt>resolve_object_value(flag_key:, default_value:, context: nil)</tt>
38
+ # manner; <tt>client.resolve_object_value(flag_key: 'object-flag', default_value: { default_value: 'value'})</tt>
39
+ module Provider
40
+ class << self
41
+ def build_client
42
+ ConfiguredClient.new
43
+ end
44
+ end
45
+
46
+ class ConfiguredClient
47
+ def method_missing(method_name, ...)
48
+ if client.respond_to?(method_name)
49
+ client.send(method_name, ...)
50
+ else
51
+ super
52
+ end
53
+ end
54
+
55
+ def respond_to_missing?(method_name, include_private = false)
56
+ client.respond_to?(method_name, include_private) || super
57
+ end
58
+
59
+ def configuration
60
+ @configuration ||= Configuration.default_config
61
+ .merge(Configuration.environment_variables_config)
62
+ .merge(explicit_configuration)
63
+ end
64
+
65
+ def configure(&block)
66
+ return unless block
67
+
68
+ block.call(explicit_configuration)
69
+ end
70
+
71
+ private
72
+
73
+ def explicit_configuration
74
+ @explicit_configuration ||= Configuration.new
75
+ end
76
+
77
+ def client
78
+ @client ||= Client.new(configuration: configuration)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/openfeature/flagd/provider/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "openfeature-flagd-provider"
7
+ spec.version = OpenFeature::Flagd::VERSION
8
+ spec.authors = ["OpenFeature Authors"]
9
+ spec.email = ["cncf-openfeature-contributors@lists.cncf.io"]
10
+
11
+ spec.summary = "The flagd provider for the OpenFeature Ruby SDK"
12
+ spec.description = "The flagd provider for the OpenFeature Ruby SDK"
13
+ spec.homepage = "https://github.com/open-feature/ruby-sdk-contrib/providers/openfeature-flagd-provider"
14
+ spec.license = "Apache-2.0"
15
+ spec.required_ruby_version = ">= 3.1"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/open-feature/ruby-sdk-contrib/providers/openfeature-flagd-provider"
19
+ spec.metadata["changelog_uri"] = "https://github.com/open-feature/ruby-sdk-contrib/blob/main/providers/openfeature-flagd-provider/CHANGELOG.md"
20
+ spec.metadata["bug_tracker_uri"] = "https://github.com/open-feature/ruby-sdk-contrib/issues"
21
+ spec.metadata["documentation_uri"] = "https://github.com/open-feature/ruby-sdk-contrib/README.md"
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+
32
+ spec.add_runtime_dependency "grpc", "~> 1.50"
33
+ spec.add_runtime_dependency "openfeature-sdk", "~> 0.3"
34
+
35
+ spec.add_development_dependency "rake", "~> 13.0"
36
+ spec.add_development_dependency "rspec", "~> 3.12.0"
37
+ spec.add_development_dependency "standard"
38
+ spec.add_development_dependency "rubocop"
39
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: openfeature-flagd-provider
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - OpenFeature Authors
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-05-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: grpc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.50'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.50'
27
+ - !ruby/object:Gem::Dependency
28
+ name: openfeature-sdk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.12.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 3.12.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: standard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: The flagd provider for the OpenFeature Ruby SDK
98
+ email:
99
+ - cncf-openfeature-contributors@lists.cncf.io
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".rubocop.yml"
107
+ - ".ruby-version"
108
+ - CHANGELOG.md
109
+ - Gemfile
110
+ - Gemfile.lock
111
+ - README.md
112
+ - Rakefile
113
+ - bin/console
114
+ - bin/setup
115
+ - docker/docker-compose.yml
116
+ - docker/flags.json
117
+ - lib/openfeature/flagd/provider.rb
118
+ - lib/openfeature/flagd/provider/client.rb
119
+ - lib/openfeature/flagd/provider/configuration.rb
120
+ - lib/openfeature/flagd/provider/flagd/evaluation/v1/evaluation_pb.rb
121
+ - lib/openfeature/flagd/provider/flagd/evaluation/v1/evaluation_services_pb.rb
122
+ - lib/openfeature/flagd/provider/flagd/sync/v1/sync_pb.rb
123
+ - lib/openfeature/flagd/provider/flagd/sync/v1/sync_services_pb.rb
124
+ - lib/openfeature/flagd/provider/version.rb
125
+ - openfeature-flagd-provider.gemspec
126
+ homepage: https://github.com/open-feature/ruby-sdk-contrib/providers/openfeature-flagd-provider
127
+ licenses:
128
+ - Apache-2.0
129
+ metadata:
130
+ homepage_uri: https://github.com/open-feature/ruby-sdk-contrib/providers/openfeature-flagd-provider
131
+ source_code_uri: https://github.com/open-feature/ruby-sdk-contrib/providers/openfeature-flagd-provider
132
+ changelog_uri: https://github.com/open-feature/ruby-sdk-contrib/blob/main/providers/openfeature-flagd-provider/CHANGELOG.md
133
+ bug_tracker_uri: https://github.com/open-feature/ruby-sdk-contrib/issues
134
+ documentation_uri: https://github.com/open-feature/ruby-sdk-contrib/README.md
135
+ post_install_message:
136
+ rdoc_options: []
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '3.1'
144
+ required_rubygems_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ requirements: []
150
+ rubygems_version: 3.5.9
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: The flagd provider for the OpenFeature Ruby SDK
154
+ test_files: []