configcat-openfeature-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: bed72c8e9d480f7f261be86b760a6328c2d30a37debbf2835f6f55e8eca8a6b7
4
+ data.tar.gz: 0af26ce4ad07589802f0dde75aa4f9be8b23d0345c4d84e60e608b23bf75bc41
5
+ SHA512:
6
+ metadata.gz: 2a4c439d0849b523ddbd08228cde46f5e92747ea0936ad56d53598de61d352ccb5807a5cff04312b2f29c5aa92f6a367a3f32f7a8242bf55db267fcd385b5af5
7
+ data.tar.gz: d76022f65cbfd1f220ae452c0b1ffd48891a0be017d90f9ac9443f8c1ed5789483b5f3fdc6457767ec8ca97c53facf11c60983ff8903b15bcbbf1f284b2dc796
@@ -0,0 +1 @@
1
+ * @configcat/developers
@@ -0,0 +1,7 @@
1
+ version: 2
2
+ enable-beta-ecosystems: true
3
+ updates:
4
+ - package-ecosystem: "github-actions"
5
+ directory: "/"
6
+ schedule:
7
+ interval: "weekly"
@@ -0,0 +1,39 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ '*' ]
6
+ paths-ignore:
7
+ - '**.md'
8
+ pull_request:
9
+ paths-ignore:
10
+ - '**.md'
11
+
12
+ jobs:
13
+ standard:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: 3.2
20
+ - run: bundle install
21
+ - run: bundle exec rake standard
22
+
23
+ test:
24
+ runs-on: ubuntu-latest
25
+ name: Ruby ${{ matrix.ruby }}
26
+ strategy:
27
+ matrix:
28
+ ruby:
29
+ - "3.3"
30
+ - "3.2"
31
+ - "3.1"
32
+
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+ - uses: ruby/setup-ruby@v1
36
+ with:
37
+ ruby-version: ${{ matrix.ruby }}
38
+ - run: bundle install
39
+ - run: bundle exec rspec
@@ -0,0 +1,23 @@
1
+ name: Publish
2
+ on:
3
+ push:
4
+ tags: [ 'v[0-9]+.[0-9]+.[0-9]+' ]
5
+
6
+ jobs:
7
+ publish:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+ - uses: ruby/setup-ruby@v1
12
+ with:
13
+ ruby-version: 3.2
14
+ - name: Publish to RubyGems
15
+ run: |
16
+ mkdir -p $HOME/.gem
17
+ touch $HOME/.gem/credentials
18
+ chmod 0600 $HOME/.gem/credentials
19
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
20
+ gem build *.gemspec
21
+ gem push *.gem
22
+ env:
23
+ GEM_HOST_API_KEY: "${{ secrets.GEM_API_KEY }}"
@@ -0,0 +1,12 @@
1
+ name: Mark stale issues
2
+
3
+ on:
4
+ schedule:
5
+ - cron: '0 1 * * *'
6
+
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ stale:
11
+ uses: configcat/.github/.github/workflows/stale.yml@master
12
+ secrets: inherit
data/.gitignore ADDED
@@ -0,0 +1,60 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ # Ignore Byebug command history file.
17
+ .byebug_history
18
+
19
+ ## Specific to RubyMotion:
20
+ .dat*
21
+ .repl_history
22
+ build/
23
+ *.bridgesupport
24
+ build-iPhoneOS/
25
+ build-iPhoneSimulator/
26
+
27
+ ## Specific to RubyMotion (use of CocoaPods):
28
+ #
29
+ # We recommend against adding the Pods directory to your .gitignore. However
30
+ # you should judge for yourself, the pros and cons are mentioned at:
31
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
32
+ #
33
+ # vendor/Pods/
34
+
35
+ ## Documentation cache and generated files:
36
+ /.yardoc/
37
+ /_yardoc/
38
+ /doc/
39
+ /rdoc/
40
+
41
+ ## Environment normalization:
42
+ /.bundle/
43
+ /vendor/bundle
44
+ /lib/bundler/man/
45
+
46
+ # for a library or gem, you might want to ignore these files since the code is
47
+ # intended to run in multiple environments; otherwise, check them in:
48
+ # Gemfile.lock
49
+ # .ruby-version
50
+ # .ruby-gemset
51
+
52
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
53
+ .rvmrc
54
+
55
+ # Used by RuboCop. Remote config files pulled in from inherit_from directive.
56
+ # .rubocop-https?--*
57
+
58
+ .idea
59
+
60
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ -I lib
2
+ --format documentation
3
+ --color
4
+ --require spec_helper
data/.standard.yml ADDED
@@ -0,0 +1,5 @@
1
+ parallel: true
2
+ format: progress
3
+ ruby_version: 3.1
4
+ plugins:
5
+ - standard-performance
data/CHANGELOG.md ADDED
@@ -0,0 +1 @@
1
+ Please check the [Github Releases](https://github.com/configcat/openfeature-ruby/releases) page for the changelog of the ConfigCat OpenFeature Provider for Ruby.
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,42 @@
1
+ # Contributing to the ConfigCat OpenFeature Provider for Ruby
2
+
3
+ ConfigCat SDK is an open source project. Feedback and contribution are welcome. Contributions are made to this repo via Issues and Pull Requests.
4
+
5
+ ## Submitting bug reports and feature requests
6
+
7
+ The ConfigCat SDK team monitors the [issue tracker](https://github.com/configcat/openfeature-ruby/issues) in the Provider repository. Bug reports and feature requests specific to this SDK should be filed in this issue tracker. The team will respond to all newly filed issues.
8
+
9
+ ## Submitting pull requests
10
+
11
+ We encourage pull requests and other contributions from the community.
12
+ - Before submitting pull requests, ensure that all temporary or unintended code is removed.
13
+ - Be accompanied by a complete Pull Request template (loaded automatically when a PR is created).
14
+ - Add unit or integration tests for fixed or changed functionality.
15
+
16
+ When you submit a pull request or otherwise seek to include your change in the repository, you waive all your intellectual property rights, including your copyright and patent claims for the submission. For more details please read the [contribution agreement](https://github.com/configcat/legal/blob/main/contribution-agreement.md).
17
+
18
+ In general, we follow the ["fork-and-pull" Git workflow](https://github.com/susam/gitpr)
19
+
20
+ 1. Fork the repository to your own GitHub account
21
+ 2. Clone the project to your machine
22
+ 3. Create a branch locally with a succinct but descriptive name
23
+ 4. Commit changes to the branch
24
+ 5. Following any formatting and testing guidelines specific to this repo
25
+ 6. Push changes to your fork
26
+ 7. Open a PR in our repository and follow the PR template so that we can efficiently review the changes.
27
+
28
+ ## Build instructions
29
+
30
+ This provider is built with [Bundler](https://bundler.io). To install Bundler, run `gem install bundler`.
31
+
32
+ To install dependencies:
33
+
34
+ ```bash
35
+ bundle install
36
+ ```
37
+
38
+ ## Running tests
39
+
40
+ ```bash
41
+ bundle exec rspec spec
42
+ ```
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,90 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ configcat-openfeature-provider (0.1.0)
5
+ configcat (~> 8.0.1)
6
+ openfeature-sdk (~> 0.4.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ ast (2.4.3)
12
+ concurrent-ruby (1.3.5)
13
+ configcat (8.0.1)
14
+ concurrent-ruby (~> 1.1)
15
+ semantic (~> 1.6)
16
+ diff-lcs (1.6.2)
17
+ json (2.12.2)
18
+ language_server-protocol (3.17.0.5)
19
+ lint_roller (1.1.0)
20
+ openfeature-sdk (0.4.0)
21
+ parallel (1.27.0)
22
+ parser (3.3.8.0)
23
+ ast (~> 2.4.1)
24
+ racc
25
+ prism (1.4.0)
26
+ racc (1.8.1)
27
+ rainbow (3.1.1)
28
+ rake (13.2.1)
29
+ regexp_parser (2.10.0)
30
+ rspec (3.12.0)
31
+ rspec-core (~> 3.12.0)
32
+ rspec-expectations (~> 3.12.0)
33
+ rspec-mocks (~> 3.12.0)
34
+ rspec-core (3.12.3)
35
+ rspec-support (~> 3.12.0)
36
+ rspec-expectations (3.12.4)
37
+ diff-lcs (>= 1.2.0, < 2.0)
38
+ rspec-support (~> 3.12.0)
39
+ rspec-mocks (3.12.7)
40
+ diff-lcs (>= 1.2.0, < 2.0)
41
+ rspec-support (~> 3.12.0)
42
+ rspec-support (3.12.2)
43
+ rubocop (1.75.7)
44
+ json (~> 2.3)
45
+ language_server-protocol (~> 3.17.0.2)
46
+ lint_roller (~> 1.1.0)
47
+ parallel (~> 1.10)
48
+ parser (>= 3.3.0.2)
49
+ rainbow (>= 2.2.2, < 4.0)
50
+ regexp_parser (>= 2.9.3, < 3.0)
51
+ rubocop-ast (>= 1.44.0, < 2.0)
52
+ ruby-progressbar (~> 1.7)
53
+ unicode-display_width (>= 2.4.0, < 4.0)
54
+ rubocop-ast (1.44.1)
55
+ parser (>= 3.3.7.2)
56
+ prism (~> 1.4)
57
+ rubocop-performance (1.25.0)
58
+ lint_roller (~> 1.1)
59
+ rubocop (>= 1.75.0, < 2.0)
60
+ rubocop-ast (>= 1.38.0, < 2.0)
61
+ ruby-progressbar (1.13.0)
62
+ semantic (1.6.1)
63
+ standard (1.50.0)
64
+ language_server-protocol (~> 3.17.0.2)
65
+ lint_roller (~> 1.0)
66
+ rubocop (~> 1.75.5)
67
+ standard-custom (~> 1.0.0)
68
+ standard-performance (~> 1.8)
69
+ standard-custom (1.0.2)
70
+ lint_roller (~> 1.0)
71
+ rubocop (~> 1.50)
72
+ standard-performance (1.8.0)
73
+ lint_roller (~> 1.1)
74
+ rubocop-performance (~> 1.25.0)
75
+ unicode-display_width (3.1.4)
76
+ unicode-emoji (~> 4.0, >= 4.0.4)
77
+ unicode-emoji (4.0.4)
78
+
79
+ PLATFORMS
80
+ x64-mingw-ucrt
81
+
82
+ DEPENDENCIES
83
+ configcat-openfeature-provider!
84
+ rake (~> 13.0)
85
+ rspec (~> 3.12)
86
+ standard
87
+ standard-performance
88
+
89
+ BUNDLED WITH
90
+ 2.6.9
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ConfigCat
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # ConfigCat OpenFeature Provider for Ruby
2
+
3
+ [![Build Status](https://github.com/configcat/openfeature-ruby/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/configcat/openfeature-ruby/actions/workflows/ci.yml)
4
+ [![Gem version](https://badge.fury.io/rb/configcat-openfeature-provider.svg)](https://rubygems.org/gems/configcat-openfeature-provider)
5
+
6
+ This repository contains an OpenFeature provider that allows [ConfigCat](https://configcat.com) to be used with the [OpenFeature Ruby SDK](https://github.com/open-feature/ruby-sdk).
7
+
8
+ ## Requirements
9
+ - Ruby >= 3.1
10
+
11
+ ## Installation
12
+
13
+ ```sh
14
+ gem install configcat-openfeature-provider
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ The initializer of `ConfigCat::OpenFeature::Provider` takes the SDK key and an optional `ConfigCat::ConfigCatOptions` argument containing the additional configuration options for the [ConfigCat Ruby SDK](https://github.com/configcat/ruby-sdk):
20
+
21
+ ```ruby
22
+ require "configcat-openfeature-provider"
23
+
24
+ # Configure the OpenFeature API with the ConfigCat provider.
25
+ OpenFeature::SDK.configure do |config|
26
+ config.set_provider(ConfigCat::OpenFeature::Provider.new(
27
+ sdk_key: "<YOUR-CONFIGCAT-SDK-KEY>",
28
+ # Build options for the ConfigCat SDK.
29
+ options: ConfigCat::ConfigCatOptions.new(
30
+ polling_mode: ConfigCat::PollingMode.auto_poll,
31
+ offline: false
32
+ )))
33
+ end
34
+
35
+ # Create a client.
36
+ client = OpenFeature::SDK.build_client
37
+
38
+ # Evaluate feature flag.
39
+ flag_value = client.fetch_boolean_value(
40
+ flag_key: "isMyAwesomeFeatureEnabled",
41
+ default_value: false
42
+ )
43
+ ```
44
+
45
+ For more information about all the configuration options, see the [Ruby SDK documentation](https://configcat.com/docs/sdk-reference/ruby/#creating-the-configcat-client).
46
+
47
+ ## Need help?
48
+ https://configcat.com/support
49
+
50
+ ## Contributing
51
+ Contributions are welcome. For more info please read the [Contribution Guideline](CONTRIBUTING.md).
52
+
53
+ ## About ConfigCat
54
+ ConfigCat is a feature flag and configuration management service that lets you separate releases from deployments. You can turn your features ON/OFF using <a href="https://app.configcat.com" target="_blank">ConfigCat Dashboard</a> even after they are deployed. ConfigCat lets you target specific groups of users based on region, email or any other custom user attribute.
55
+
56
+ ConfigCat is a <a href="https://configcat.com" target="_blank">hosted feature flag service</a>. Manage feature toggles across frontend, backend, mobile, desktop apps. <a href="https://configcat.com" target="_blank">Alternative to LaunchDarkly</a>. Management app + feature flag SDKs.
57
+
58
+ - [Official ConfigCat SDKs for other platforms](https://github.com/configcat)
59
+ - [Documentation](https://configcat.com/docs)
60
+ - [Blog](https://configcat.com/blog)
data/Rakefile ADDED
@@ -0,0 +1,10 @@
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
+ require "standard/rake"
9
+
10
+ task default: %i[standard spec]
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/configcat-openfeature-provider/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "configcat-openfeature-provider"
7
+ spec.version = ConfigCat::OpenFeature::VERSION
8
+ spec.authors = ["ConfigCat"]
9
+ spec.email = ["developer@configcat.com"]
10
+ spec.licenses = ["MIT"]
11
+
12
+ spec.summary = "ConfigCat OpenFeature Provider for Ruby."
13
+ spec.description = "OpenFeature Provider that allows ConfigCat to be used with the OpenFeature Ruby SDK."
14
+
15
+ spec.homepage = "https://configcat.com"
16
+
17
+ spec.required_ruby_version = ">= 3.1"
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["source_code_uri"] = "https://github.com/configcat/openfeature-ruby"
21
+ spec.metadata["changelog_uri"] = "https://github.com/configcat/openfeature-ruby/blob/main/CHANGELOG.md"
22
+ spec.metadata["bug_tracker_uri"] = "https://github.com/configcat/openfeature-ruby/issues"
23
+ spec.metadata["documentation_uri"] = "https://configcat.com/docs/sdk-reference/openfeature/ruby"
24
+
25
+ # Specify which files should be added to the gem when it is released.
26
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
27
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
28
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
29
+ end
30
+ spec.bindir = "exe"
31
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ spec.add_dependency "configcat", "~> 8.0.1"
35
+ spec.add_dependency "openfeature-sdk", "~> 0.4.0"
36
+
37
+ spec.add_development_dependency "rake", "~> 13.0"
38
+ spec.add_development_dependency "rspec", "~> 3.12"
39
+ spec.add_development_dependency "standard"
40
+ spec.add_development_dependency "standard-performance"
41
+ end
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open_feature/sdk"
4
+ require "configcat"
5
+
6
+ module ConfigCat
7
+ module OpenFeature
8
+ class Provider
9
+ PROVIDER_NAME = "ConfigCatProvider"
10
+ attr_reader :metadata
11
+
12
+ def initialize(sdk_key:, options: ConfigCatOptions.new)
13
+ @metadata = ::OpenFeature::SDK::Provider::ProviderMetadata.new(name: PROVIDER_NAME)
14
+ @client = ConfigCatClient.get(sdk_key, options)
15
+ end
16
+
17
+ def fetch_boolean_value(flag_key:, default_value:, evaluation_context: nil)
18
+ user = ctx_to_user(evaluation_context)
19
+ evaluation_detail = @client.get_value_details(flag_key, default_value, user)
20
+
21
+ unless [true, false].include?(evaluation_detail.value)
22
+ return type_mismatch(default_value)
23
+ end
24
+
25
+ produce_result(evaluation_detail, default_value)
26
+ end
27
+
28
+ def fetch_string_value(flag_key:, default_value:, evaluation_context: nil)
29
+ user = ctx_to_user(evaluation_context)
30
+ evaluation_detail = @client.get_value_details(flag_key, default_value, user)
31
+
32
+ unless evaluation_detail.value.is_a?(String)
33
+ return type_mismatch(default_value)
34
+ end
35
+
36
+ produce_result(evaluation_detail, default_value)
37
+ end
38
+
39
+ def fetch_number_value(flag_key:, default_value:, evaluation_context: nil)
40
+ user = ctx_to_user(evaluation_context)
41
+ evaluation_detail = @client.get_value_details(flag_key, default_value, user)
42
+
43
+ unless evaluation_detail.value.is_a?(Numeric)
44
+ return type_mismatch(default_value)
45
+ end
46
+
47
+ produce_numeric_result(evaluation_detail, default_value, Numeric)
48
+ end
49
+
50
+ def fetch_integer_value(flag_key:, default_value:, evaluation_context: nil)
51
+ user = ctx_to_user(evaluation_context)
52
+ evaluation_detail = @client.get_value_details(flag_key, default_value, user)
53
+
54
+ unless evaluation_detail.value.is_a?(Numeric)
55
+ return type_mismatch(default_value)
56
+ end
57
+
58
+ produce_numeric_result(evaluation_detail, default_value, Integer)
59
+ end
60
+
61
+ def fetch_float_value(flag_key:, default_value:, evaluation_context: nil)
62
+ user = ctx_to_user(evaluation_context)
63
+ evaluation_detail = @client.get_value_details(flag_key, default_value, user)
64
+
65
+ unless evaluation_detail.value.is_a?(Numeric)
66
+ return type_mismatch(default_value)
67
+ end
68
+
69
+ produce_numeric_result(evaluation_detail, default_value, Float)
70
+ end
71
+
72
+ def fetch_object_value(flag_key:, default_value:, evaluation_context: nil)
73
+ user = ctx_to_user(evaluation_context)
74
+ evaluation_detail = @client.get_value_details(flag_key, "", user)
75
+
76
+ unless evaluation_detail.value.is_a?(String)
77
+ return type_mismatch(default_value)
78
+ end
79
+
80
+ result = produce_result(evaluation_detail, default_value)
81
+ begin
82
+ result.value = JSON.parse(result.value)
83
+ rescue JSON::ParserError, TypeError
84
+ return ::OpenFeature::SDK::Provider::ResolutionDetails.new(
85
+ value: default_value,
86
+ error_code: ::OpenFeature::SDK::Provider::ErrorCode::TYPE_MISMATCH,
87
+ error_message: "Could not parse '#{result.value}' as JSON",
88
+ reason: ::OpenFeature::SDK::Provider::Reason::ERROR
89
+ )
90
+ end
91
+ result
92
+ end
93
+
94
+ # @param evaluation_context [::OpenFeature::SDK::EvaluationContext, nil]
95
+ #
96
+ # @return [ConfigCat::User, nil]
97
+ private def ctx_to_user(evaluation_context)
98
+ if evaluation_context.nil? || evaluation_context.fields.nil? || evaluation_context.fields.empty?
99
+ return nil
100
+ end
101
+
102
+ email = evaluation_context.field("Email")
103
+ country = evaluation_context.field("Country")
104
+
105
+ ConfigCat::User.new(evaluation_context.targeting_key, email: email, country: country, custom: evaluation_context.fields)
106
+ end
107
+
108
+ private def type_mismatch(default_value)
109
+ ::OpenFeature::SDK::Provider::ResolutionDetails.new(
110
+ value: default_value,
111
+ reason: ::OpenFeature::SDK::Provider::Reason::ERROR,
112
+ error_code: ::OpenFeature::SDK::Provider::ErrorCode::TYPE_MISMATCH
113
+ )
114
+ end
115
+
116
+ # @param evaluation_detail [ConfigCat::EvaluationDetails]
117
+ # @param default_value [any]
118
+ #
119
+ # @return [::OpenFeature::SDK::ResolutionDetails]
120
+ private def produce_result(evaluation_detail, default_value)
121
+ unless evaluation_detail.error.nil?
122
+ error_code = evaluation_detail.error.include?("key was not found in config JSON") ? ::OpenFeature::SDK::Provider::ErrorCode::FLAG_NOT_FOUND : ::OpenFeature::SDK::Provider::ErrorCode::GENERAL
123
+ return ::OpenFeature::SDK::Provider::ResolutionDetails.new(
124
+ value: default_value,
125
+ reason: ::OpenFeature::SDK::Provider::Reason::ERROR,
126
+ error_code: error_code,
127
+ error_message: evaluation_detail.error
128
+ )
129
+ end
130
+
131
+ ::OpenFeature::SDK::Provider::ResolutionDetails.new(
132
+ value: evaluation_detail.value,
133
+ variant: evaluation_detail.variation_id,
134
+ reason: produce_reason(evaluation_detail)
135
+ )
136
+ end
137
+
138
+ # @param evaluation_detail [ConfigCat::EvaluationDetails]
139
+ # @param default_value [any]
140
+ #
141
+ # @return [::OpenFeature::SDK::ResolutionDetails]
142
+ private def produce_numeric_result(evaluation_detail, default_value, type)
143
+ result = produce_result(evaluation_detail, default_value)
144
+ unless result.error_code.nil?
145
+ return result
146
+ end
147
+
148
+ if type == Integer
149
+ result.value = result.value.to_i
150
+ elsif type == Float
151
+ result.value = result.value.to_f
152
+ end
153
+
154
+ result
155
+ end
156
+
157
+ # @param evaluation_detail [ConfigCat::EvaluationDetails]
158
+ #
159
+ # @return [String]
160
+ private def produce_reason(evaluation_detail)
161
+ unless evaluation_detail.error.nil?
162
+ return ::OpenFeature::SDK::Provider::Reason::ERROR
163
+ end
164
+
165
+ if !evaluation_detail.matched_targeting_rule.nil? || !evaluation_detail.matched_percentage_option.nil?
166
+ return ::OpenFeature::SDK::Provider::Reason::TARGETING_MATCH
167
+ end
168
+
169
+ ::OpenFeature::SDK::Provider::Reason::DEFAULT
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ConfigCat
4
+ module OpenFeature
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ require_relative "configcat-openfeature-provider/provider"
2
+ require_relative "configcat-openfeature-provider/version"
3
+
4
+ module ConfigCat
5
+ module OpenFeature
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "configcat-openfeature-provider", path: "../../../"
@@ -0,0 +1,25 @@
1
+ PATH
2
+ remote: ../../..
3
+ specs:
4
+ configcat (8.0.1)
5
+ concurrent-ruby (~> 1.1)
6
+ semantic (~> 1.6)
7
+ configcat-openfeature-provider (0.1.0)
8
+ configcat (~> 8.0.1)
9
+ openfeature-sdk (~> 0.4.0)
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ concurrent-ruby (1.3.5)
15
+ openfeature-sdk (0.4.0)
16
+ semantic (1.6.1)
17
+
18
+ PLATFORMS
19
+ x64-mingw-ucrt
20
+
21
+ DEPENDENCIES
22
+ configcat-openfeature-provider!
23
+
24
+ BUNDLED WITH
25
+ 2.6.9
@@ -0,0 +1,38 @@
1
+ require "configcat-openfeature-provider"
2
+ require "date"
3
+
4
+ # Info level logging helps to inspect the feature flag evaluation process.
5
+ # Use the default Warning level to avoid too detailed logging in your application.
6
+ ConfigCat.logger.level = Logger::INFO
7
+
8
+ # Configure the OpenFeature API with the ConfigCat provider.
9
+ OpenFeature::SDK.configure do |config|
10
+ config.set_provider(ConfigCat::OpenFeature::Provider.new(
11
+ sdk_key: "PKDVCLf-Hq-h-kCzMp-L7Q/HhOWfwVtZ0mb30i9wi17GQ",
12
+ # Configure the ConfigCat SDK.
13
+ options: ConfigCat::ConfigCatOptions.new(
14
+ polling_mode: ConfigCat::PollingMode.auto_poll,
15
+ offline: false
16
+ )
17
+ ))
18
+ end
19
+
20
+ # Create a client.
21
+ client = OpenFeature::SDK.build_client
22
+
23
+ # Create evaluation context.
24
+ evaluation_context = OpenFeature::SDK::EvaluationContext.new(
25
+ OpenFeature::SDK::EvaluationContext::TARGETING_KEY => "<SOME USERID>",
26
+ "Email" => "configcat@example.com",
27
+ "Country" => "CountryID",
28
+ "Version" => "1.0.0"
29
+ )
30
+
31
+ # Evaluate feature flag.
32
+ flag_details = client.fetch_boolean_details(
33
+ flag_key: "isPOCFeatureEnabled",
34
+ default_value: false,
35
+ evaluation_context: evaluation_context
36
+ )
37
+
38
+ puts(JSON.dump(flag_details))
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: configcat-openfeature-provider
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - ConfigCat
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-06-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: configcat
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 8.0.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 8.0.1
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.4.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.4.0
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'
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'
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: standard-performance
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: OpenFeature Provider that allows ConfigCat to be used with the OpenFeature
98
+ Ruby SDK.
99
+ email:
100
+ - developer@configcat.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".github/CODEOWNERS"
106
+ - ".github/dependabot.yml"
107
+ - ".github/workflows/ci.yml"
108
+ - ".github/workflows/publish.yml"
109
+ - ".github/workflows/stale.yml"
110
+ - ".gitignore"
111
+ - ".rspec"
112
+ - ".standard.yml"
113
+ - CHANGELOG.md
114
+ - CONTRIBUTING.md
115
+ - Gemfile
116
+ - Gemfile.lock
117
+ - LICENSE
118
+ - README.md
119
+ - Rakefile
120
+ - configcat-openfeature-provider.gemspec
121
+ - lib/configcat-openfeature-provider.rb
122
+ - lib/configcat-openfeature-provider/provider.rb
123
+ - lib/configcat-openfeature-provider/version.rb
124
+ - samples/provider-sample/Gemfile
125
+ - samples/provider-sample/Gemfile.lock
126
+ - samples/provider-sample/main.rb
127
+ homepage: https://configcat.com
128
+ licenses:
129
+ - MIT
130
+ metadata:
131
+ homepage_uri: https://configcat.com
132
+ source_code_uri: https://github.com/configcat/openfeature-ruby
133
+ changelog_uri: https://github.com/configcat/openfeature-ruby/blob/main/CHANGELOG.md
134
+ bug_tracker_uri: https://github.com/configcat/openfeature-ruby/issues
135
+ documentation_uri: https://configcat.com/docs/sdk-reference/openfeature/ruby
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '3.1'
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubygems_version: 3.4.19
152
+ signing_key:
153
+ specification_version: 4
154
+ summary: ConfigCat OpenFeature Provider for Ruby.
155
+ test_files: []