openfeature-flagd-provider 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []