openfeature-flagsmith-provider 0.1.1
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 +7 -0
- data/.context.md +316 -0
- data/.gitignore +11 -0
- data/.rspec +4 -0
- data/.rubocop.yml +5 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +22 -0
- data/FLAGSMITH_PROVIDER_DESIGN.md +393 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +126 -0
- data/README.md +324 -0
- data/Rakefile +6 -0
- data/lib/openfeature/flagsmith/error/errors.rb +78 -0
- data/lib/openfeature/flagsmith/options.rb +82 -0
- data/lib/openfeature/flagsmith/provider.rb +265 -0
- data/lib/openfeature/flagsmith/version.rb +7 -0
- data/openfeature-flagsmith-provider.gemspec +38 -0
- metadata +176 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
# Flagsmith OpenFeature Provider - Design Document
|
|
2
|
+
|
|
3
|
+
**Created:** 2025-11-17
|
|
4
|
+
**Status:** Design Phase
|
|
5
|
+
**Target:** OpenFeature Ruby SDK integration with Flagsmith
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Research Summary
|
|
10
|
+
|
|
11
|
+
### 1.1 Flagsmith Ruby SDK Details
|
|
12
|
+
|
|
13
|
+
**Gem Name:** `flagsmith`
|
|
14
|
+
**Latest Version:** v4.3.0 (as of December 2024)
|
|
15
|
+
**Ruby Version:** Requires Ruby 2.4+
|
|
16
|
+
**GitHub:** https://github.com/Flagsmith/flagsmith-ruby-client
|
|
17
|
+
**Documentation:** https://docs.flagsmith.com/clients/server-side
|
|
18
|
+
|
|
19
|
+
#### Installation
|
|
20
|
+
```ruby
|
|
21
|
+
gem install flagsmith
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
#### Basic Initialization
|
|
25
|
+
```ruby
|
|
26
|
+
require "flagsmith"
|
|
27
|
+
$flagsmith = Flagsmith::Client.new(
|
|
28
|
+
environment_key: 'FLAGSMITH_SERVER_SIDE_ENVIRONMENT_KEY'
|
|
29
|
+
)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
#### Configuration Options
|
|
33
|
+
|
|
34
|
+
| Option | Type | Default | Description |
|
|
35
|
+
|--------|------|---------|-------------|
|
|
36
|
+
| `environment_key` | String | **Required** | Server-side authentication token |
|
|
37
|
+
| `api_url` | String | "https://edge.api.flagsmith.com/api/v1/" | Custom self-hosted endpoint |
|
|
38
|
+
| `enable_local_evaluation` | Boolean | false | Local vs. remote flag evaluation mode |
|
|
39
|
+
| `request_timeout_seconds` | Integer | 10 | Network request timeout |
|
|
40
|
+
| `environment_refresh_interval_seconds` | Integer | 60 | Polling interval in local mode |
|
|
41
|
+
| `enable_analytics` | Boolean | false | Send usage analytics to Flagsmith |
|
|
42
|
+
| `default_flag_handler` | Lambda | nil | Fallback for missing/failed flags |
|
|
43
|
+
|
|
44
|
+
#### Flag Evaluation Methods
|
|
45
|
+
|
|
46
|
+
**Environment-level (no user context):**
|
|
47
|
+
```ruby
|
|
48
|
+
flags = $flagsmith.get_environment_flags()
|
|
49
|
+
show_button = flags.is_feature_enabled('secret_button')
|
|
50
|
+
button_data = flags.get_feature_value('secret_button')
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Identity-specific (with user context):**
|
|
54
|
+
```ruby
|
|
55
|
+
identifier = 'user@example.com'
|
|
56
|
+
traits = {'car_type': 'sedan', 'age': 30}
|
|
57
|
+
flags = $flagsmith.get_identity_flags(identifier, **traits)
|
|
58
|
+
show_button = flags.is_feature_enabled('secret_button')
|
|
59
|
+
value = flags.get_feature_value('secret_button')
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### Evaluation Modes
|
|
63
|
+
- **Remote Evaluation** (default): Blocking HTTP requests per flag fetch
|
|
64
|
+
- **Local Evaluation**: Asynchronous polling (~60 sec intervals)
|
|
65
|
+
- **Offline Mode**: Requires custom `offline_handler`
|
|
66
|
+
|
|
67
|
+
#### Default Flag Handler Pattern
|
|
68
|
+
```ruby
|
|
69
|
+
$flagsmith = Flagsmith::Client.new(
|
|
70
|
+
environment_key: '<KEY>',
|
|
71
|
+
default_flag_handler: lambda { |feature_name|
|
|
72
|
+
Flagsmith::Flags::DefaultFlag.new(
|
|
73
|
+
enabled: false,
|
|
74
|
+
value: {'colour': '#ababab'}.to_json
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 2. OpenFeature Provider Patterns (from repo analysis)
|
|
83
|
+
|
|
84
|
+
### 2.1 Required Provider Interface
|
|
85
|
+
|
|
86
|
+
All providers must implement:
|
|
87
|
+
```ruby
|
|
88
|
+
class Provider
|
|
89
|
+
attr_reader :metadata # Returns ProviderMetadata with name
|
|
90
|
+
|
|
91
|
+
# Lifecycle (optional)
|
|
92
|
+
def init
|
|
93
|
+
def shutdown
|
|
94
|
+
|
|
95
|
+
# Required evaluation methods
|
|
96
|
+
def fetch_boolean_value(flag_key:, default_value:, evaluation_context: nil)
|
|
97
|
+
def fetch_string_value(flag_key:, default_value:, evaluation_context: nil)
|
|
98
|
+
def fetch_number_value(flag_key:, default_value:, evaluation_context: nil)
|
|
99
|
+
def fetch_integer_value(flag_key:, default_value:, evaluation_context: nil)
|
|
100
|
+
def fetch_float_value(flag_key:, default_value:, evaluation_context: nil)
|
|
101
|
+
def fetch_object_value(flag_key:, default_value:, evaluation_context: nil)
|
|
102
|
+
end
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 2.2 Return Type: ResolutionDetails
|
|
106
|
+
|
|
107
|
+
All fetch_* methods must return:
|
|
108
|
+
```ruby
|
|
109
|
+
OpenFeature::SDK::Provider::ResolutionDetails.new(
|
|
110
|
+
value: <evaluated_value>, # The flag value
|
|
111
|
+
reason: <Reason constant>, # TARGETING_MATCH, DEFAULT, DISABLED, ERROR, etc.
|
|
112
|
+
variant: "variant_key", # Optional variant identifier
|
|
113
|
+
flag_metadata: { ... }, # Optional metadata
|
|
114
|
+
error_code: <ErrorCode constant>, # If error occurred
|
|
115
|
+
error_message: "Error details" # If error occurred
|
|
116
|
+
)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### OpenFeature Reason Constants
|
|
120
|
+
- `TARGETING_MATCH` - Flag evaluated with targeting rules
|
|
121
|
+
- `DEFAULT` - Default value used
|
|
122
|
+
- `DISABLED` - Feature is disabled
|
|
123
|
+
- `ERROR` - Error during evaluation
|
|
124
|
+
- `STATIC` - Static value
|
|
125
|
+
|
|
126
|
+
#### OpenFeature ErrorCode Constants
|
|
127
|
+
- `PROVIDER_NOT_READY`
|
|
128
|
+
- `FLAG_NOT_FOUND`
|
|
129
|
+
- `TYPE_MISMATCH`
|
|
130
|
+
- `PARSE_ERROR`
|
|
131
|
+
- `TARGETING_KEY_MISSING`
|
|
132
|
+
- `INVALID_CONTEXT`
|
|
133
|
+
- `GENERAL`
|
|
134
|
+
|
|
135
|
+
### 2.3 Configuration Patterns Used in Repo
|
|
136
|
+
|
|
137
|
+
**Pattern 1: Options Object** (Used by GO Feature Flag provider)
|
|
138
|
+
```ruby
|
|
139
|
+
class Options
|
|
140
|
+
def initialize(endpoint:, headers: {}, ...)
|
|
141
|
+
validate_endpoint(endpoint)
|
|
142
|
+
@endpoint = endpoint
|
|
143
|
+
@headers = headers
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Pattern 2: Block-Based Configuration** (Used by flagd provider)
|
|
149
|
+
```ruby
|
|
150
|
+
OpenFeature::Flagd::Provider.configure do |config|
|
|
151
|
+
config.host = "localhost"
|
|
152
|
+
config.port = 8013
|
|
153
|
+
end
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 2.4 Error Handling Pattern
|
|
157
|
+
|
|
158
|
+
Create custom exception hierarchy:
|
|
159
|
+
```ruby
|
|
160
|
+
class FlagsmithError < StandardError
|
|
161
|
+
attr_reader :error_code, :error_message
|
|
162
|
+
|
|
163
|
+
def initialize(error_code, error_message)
|
|
164
|
+
@error_code = error_code # Maps to SDK::Provider::ErrorCode
|
|
165
|
+
@error_message = error_message
|
|
166
|
+
super(error_message)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
class FlagNotFoundError < FlagsmithError
|
|
171
|
+
class TypeMismatchError < FlagsmithError
|
|
172
|
+
class ConfigurationError < FlagsmithError
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### 2.5 Type Validation Pattern
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
def evaluate(flag_key:, default_value:, allowed_classes:, evaluation_context: nil)
|
|
179
|
+
# ... evaluation logic ...
|
|
180
|
+
|
|
181
|
+
unless allowed_classes.include?(value.class)
|
|
182
|
+
return SDK::Provider::ResolutionDetails.new(
|
|
183
|
+
value: default_value,
|
|
184
|
+
error_code: SDK::Provider::ErrorCode::TYPE_MISMATCH,
|
|
185
|
+
error_message: "flag type #{value.class} does not match allowed types #{allowed_classes}",
|
|
186
|
+
reason: SDK::Provider::Reason::ERROR
|
|
187
|
+
)
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 3. Proposed Flagsmith Provider Architecture
|
|
195
|
+
|
|
196
|
+
### 3.1 Directory Structure
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
providers/openfeature-flagsmith-provider/
|
|
200
|
+
├── lib/
|
|
201
|
+
│ └── openfeature/
|
|
202
|
+
│ └── flagsmith/
|
|
203
|
+
│ ├── provider.rb # Main provider class
|
|
204
|
+
│ ├── configuration.rb # Configuration/options class
|
|
205
|
+
│ ├── error/
|
|
206
|
+
│ │ └── errors.rb # Custom exception hierarchy
|
|
207
|
+
│ └── version.rb # Version constant
|
|
208
|
+
├── spec/
|
|
209
|
+
│ ├── spec_helper.rb
|
|
210
|
+
│ ├── provider_spec.rb
|
|
211
|
+
│ ├── configuration_spec.rb
|
|
212
|
+
│ └── fixtures/ # Mock responses
|
|
213
|
+
├── openfeature-flagsmith-provider.gemspec
|
|
214
|
+
├── README.md
|
|
215
|
+
├── CHANGELOG.md
|
|
216
|
+
├── Gemfile
|
|
217
|
+
└── Rakefile
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### 3.2 Key Design Decisions
|
|
221
|
+
|
|
222
|
+
#### Configuration Strategy
|
|
223
|
+
**Chosen: Options Object Pattern**
|
|
224
|
+
|
|
225
|
+
Reasoning:
|
|
226
|
+
- Flagsmith has many configuration options (api_url, timeouts, evaluation mode, etc.)
|
|
227
|
+
- Options object provides clear validation
|
|
228
|
+
- Aligns with GO Feature Flag provider pattern (most similar use case)
|
|
229
|
+
|
|
230
|
+
```ruby
|
|
231
|
+
options = OpenFeature::Flagsmith::Configuration.new(
|
|
232
|
+
environment_key: "your_key",
|
|
233
|
+
api_url: "https://edge.api.flagsmith.com/api/v1/",
|
|
234
|
+
enable_local_evaluation: false,
|
|
235
|
+
request_timeout_seconds: 10,
|
|
236
|
+
enable_analytics: false
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
provider = OpenFeature::Flagsmith::Provider.new(configuration: options)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
#### Evaluation Context Mapping
|
|
243
|
+
|
|
244
|
+
OpenFeature EvaluationContext → Flagsmith Identity + Traits:
|
|
245
|
+
- `evaluation_context.targeting_key` → Flagsmith identity identifier
|
|
246
|
+
- All other `evaluation_context.fields` → Flagsmith traits
|
|
247
|
+
|
|
248
|
+
```ruby
|
|
249
|
+
def map_context_to_identity(evaluation_context)
|
|
250
|
+
return [nil, {}] if evaluation_context.nil?
|
|
251
|
+
|
|
252
|
+
identifier = evaluation_context.targeting_key
|
|
253
|
+
traits = evaluation_context.fields.reject { |k, _v| k == :targeting_key }
|
|
254
|
+
|
|
255
|
+
[identifier, traits]
|
|
256
|
+
end
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
#### Flag Type Mapping
|
|
260
|
+
|
|
261
|
+
| Flagsmith Type | OpenFeature Type | Notes |
|
|
262
|
+
|----------------|------------------|-------|
|
|
263
|
+
| Boolean enabled | `fetch_boolean_value` | Use `is_feature_enabled` |
|
|
264
|
+
| String value | `fetch_string_value` | Use `get_feature_value` |
|
|
265
|
+
| Numeric value | `fetch_number_value` | Parse and validate |
|
|
266
|
+
| JSON value | `fetch_object_value` | Parse JSON string |
|
|
267
|
+
|
|
268
|
+
#### Error Handling Strategy
|
|
269
|
+
|
|
270
|
+
1. **Flagsmith errors** → Map to OpenFeature ErrorCodes
|
|
271
|
+
2. **Network errors** → `PROVIDER_NOT_READY` or `GENERAL`
|
|
272
|
+
3. **Type mismatches** → `TYPE_MISMATCH`
|
|
273
|
+
4. **Missing flags** → Return default with `FLAG_NOT_FOUND`
|
|
274
|
+
|
|
275
|
+
#### Reason Mapping
|
|
276
|
+
|
|
277
|
+
| Flagsmith State | OpenFeature Reason |
|
|
278
|
+
|-----------------|-------------------|
|
|
279
|
+
| Flag evaluated with identity | `TARGETING_MATCH` |
|
|
280
|
+
| Flag evaluated at environment level | `STATIC` |
|
|
281
|
+
| Flag not found | `DEFAULT` |
|
|
282
|
+
| Flag disabled | `DISABLED` |
|
|
283
|
+
| Error occurred | `ERROR` |
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## 4. Implementation Plan
|
|
288
|
+
|
|
289
|
+
### Phase 1: Core Structure
|
|
290
|
+
1. Create directory structure
|
|
291
|
+
2. Setup gemspec with dependencies
|
|
292
|
+
3. Create Configuration class with validation
|
|
293
|
+
4. Create Provider class skeleton with metadata
|
|
294
|
+
|
|
295
|
+
### Phase 2: Flag Evaluation
|
|
296
|
+
5. Implement `fetch_boolean_value` (simplest case)
|
|
297
|
+
6. Implement context → identity/traits mapping
|
|
298
|
+
7. Add error handling for boolean evaluation
|
|
299
|
+
8. Implement remaining fetch_* methods
|
|
300
|
+
|
|
301
|
+
### Phase 3: Advanced Features
|
|
302
|
+
9. Handle default_flag_handler integration
|
|
303
|
+
10. Support local evaluation mode
|
|
304
|
+
11. Add proper lifecycle management (init/shutdown)
|
|
305
|
+
|
|
306
|
+
### Phase 4: Testing & Documentation
|
|
307
|
+
12. Create RSpec test suite with mocked Flagsmith responses
|
|
308
|
+
13. Write comprehensive README
|
|
309
|
+
14. Add usage examples
|
|
310
|
+
15. Configure release automation
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## 5. Open Questions & Decisions Needed
|
|
315
|
+
|
|
316
|
+
### 5.1 Design Decisions - RESOLVED ✅
|
|
317
|
+
|
|
318
|
+
1. **Evaluation Mode Preference**
|
|
319
|
+
- ✅ **Default to remote evaluation** (simpler, no polling overhead)
|
|
320
|
+
- Configurable via `enable_local_evaluation` option
|
|
321
|
+
|
|
322
|
+
2. **Analytics**
|
|
323
|
+
- ✅ **Opt-in** (`enable_analytics: false` by default)
|
|
324
|
+
|
|
325
|
+
3. **Default Flag Handler**
|
|
326
|
+
- ✅ **Use OpenFeature's default_value** (matches other providers)
|
|
327
|
+
- Do NOT implement Flagsmith's `default_flag_handler`
|
|
328
|
+
- Return `default_value` with appropriate error_code/reason on failures
|
|
329
|
+
|
|
330
|
+
4. **Targeting Key Requirement**
|
|
331
|
+
- ✅ **Fall back to environment-level flags** if no targeting_key
|
|
332
|
+
- Use `get_environment_flags()` when targeting_key is nil/empty
|
|
333
|
+
- Use `get_identity_flags()` when targeting_key is present
|
|
334
|
+
|
|
335
|
+
5. **Version Compatibility**
|
|
336
|
+
- ✅ **Target upcoming version** (will be released soon)
|
|
337
|
+
- Update dependency when new version is available
|
|
338
|
+
|
|
339
|
+
### 5.2 Technical Considerations
|
|
340
|
+
|
|
341
|
+
**Type Detection Challenge:**
|
|
342
|
+
Flagsmith's `get_feature_value` returns values as strings/JSON. We need to:
|
|
343
|
+
- Parse JSON for objects
|
|
344
|
+
- Detect numeric types
|
|
345
|
+
- Handle type mismatches gracefully
|
|
346
|
+
|
|
347
|
+
**Variant Support:**
|
|
348
|
+
Flagsmith doesn't have explicit "variants" like some systems. Options:
|
|
349
|
+
- Use feature key as variant
|
|
350
|
+
- Leave variant nil
|
|
351
|
+
- Use enabled/disabled as variant
|
|
352
|
+
|
|
353
|
+
**Metadata:**
|
|
354
|
+
Flagsmith flags don't inherently have metadata beyond enabled/value. We could:
|
|
355
|
+
- Include trait data as flag_metadata
|
|
356
|
+
- Leave empty
|
|
357
|
+
- Add custom metadata extraction
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## 6. Dependencies
|
|
362
|
+
|
|
363
|
+
### Runtime
|
|
364
|
+
- `openfeature-sdk` (~> 0.3.1)
|
|
365
|
+
- `flagsmith` (~> 4.3.0)
|
|
366
|
+
|
|
367
|
+
### Development
|
|
368
|
+
- `rake` (~> 13.0)
|
|
369
|
+
- `rspec` (~> 3.12.0)
|
|
370
|
+
- `webmock` (~> 3.0) - for mocking Flagsmith HTTP calls
|
|
371
|
+
- `standard` - Ruby linter
|
|
372
|
+
- `rubocop` - Code style
|
|
373
|
+
- `simplecov` - Test coverage
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## 7. Next Steps
|
|
378
|
+
|
|
379
|
+
1. **User Decisions** - Get answers to open questions above
|
|
380
|
+
2. **Proof of Concept** - Build minimal provider with boolean support
|
|
381
|
+
3. **Validate Approach** - Test with real Flagsmith instance
|
|
382
|
+
4. **Expand** - Add remaining types and features
|
|
383
|
+
5. **Polish** - Tests, docs, release config
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## 8. References
|
|
388
|
+
|
|
389
|
+
- OpenFeature Specification: https://openfeature.dev/specification/
|
|
390
|
+
- Flagsmith Docs: https://docs.flagsmith.com/clients/server-side
|
|
391
|
+
- Flagsmith Ruby Client: https://github.com/Flagsmith/flagsmith-ruby-client
|
|
392
|
+
- GO Feature Flag Provider (reference impl): `providers/openfeature-go-feature-flag-provider/`
|
|
393
|
+
- flagd Provider (reference impl): `providers/openfeature-flagd-provider/`
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
openfeature-flagsmith-provider (0.1.1)
|
|
5
|
+
flagsmith (~> 4.3)
|
|
6
|
+
openfeature-sdk (~> 0.3.1)
|
|
7
|
+
|
|
8
|
+
GEM
|
|
9
|
+
remote: https://rubygems.org/
|
|
10
|
+
specs:
|
|
11
|
+
addressable (2.8.7)
|
|
12
|
+
public_suffix (>= 2.0.2, < 7.0)
|
|
13
|
+
ast (2.4.3)
|
|
14
|
+
bigdecimal (3.3.1)
|
|
15
|
+
crack (1.0.1)
|
|
16
|
+
bigdecimal
|
|
17
|
+
rexml
|
|
18
|
+
diff-lcs (1.6.2)
|
|
19
|
+
docile (1.4.1)
|
|
20
|
+
faraday (2.14.0)
|
|
21
|
+
faraday-net_http (>= 2.0, < 3.5)
|
|
22
|
+
json
|
|
23
|
+
logger
|
|
24
|
+
faraday-net_http (3.4.2)
|
|
25
|
+
net-http (~> 0.5)
|
|
26
|
+
faraday-retry (2.3.2)
|
|
27
|
+
faraday (~> 2.0)
|
|
28
|
+
flagsmith (4.3.0)
|
|
29
|
+
faraday (>= 2.0.1)
|
|
30
|
+
faraday-retry
|
|
31
|
+
semantic
|
|
32
|
+
hashdiff (1.2.1)
|
|
33
|
+
json (2.16.0)
|
|
34
|
+
language_server-protocol (3.17.0.5)
|
|
35
|
+
lint_roller (1.1.0)
|
|
36
|
+
logger (1.7.0)
|
|
37
|
+
net-http (0.8.0)
|
|
38
|
+
uri (>= 0.11.1)
|
|
39
|
+
openfeature-sdk (0.3.1)
|
|
40
|
+
parallel (1.27.0)
|
|
41
|
+
parser (3.3.10.0)
|
|
42
|
+
ast (~> 2.4.1)
|
|
43
|
+
racc
|
|
44
|
+
prism (1.6.0)
|
|
45
|
+
public_suffix (6.0.2)
|
|
46
|
+
racc (1.8.1)
|
|
47
|
+
rainbow (3.1.1)
|
|
48
|
+
rake (13.3.1)
|
|
49
|
+
regexp_parser (2.11.3)
|
|
50
|
+
rexml (3.4.4)
|
|
51
|
+
rspec (3.12.0)
|
|
52
|
+
rspec-core (~> 3.12.0)
|
|
53
|
+
rspec-expectations (~> 3.12.0)
|
|
54
|
+
rspec-mocks (~> 3.12.0)
|
|
55
|
+
rspec-core (3.12.3)
|
|
56
|
+
rspec-support (~> 3.12.0)
|
|
57
|
+
rspec-expectations (3.12.4)
|
|
58
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
59
|
+
rspec-support (~> 3.12.0)
|
|
60
|
+
rspec-mocks (3.12.7)
|
|
61
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
62
|
+
rspec-support (~> 3.12.0)
|
|
63
|
+
rspec-support (3.12.2)
|
|
64
|
+
rubocop (1.81.7)
|
|
65
|
+
json (~> 2.3)
|
|
66
|
+
language_server-protocol (~> 3.17.0.2)
|
|
67
|
+
lint_roller (~> 1.1.0)
|
|
68
|
+
parallel (~> 1.10)
|
|
69
|
+
parser (>= 3.3.0.2)
|
|
70
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
71
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
72
|
+
rubocop-ast (>= 1.47.1, < 2.0)
|
|
73
|
+
ruby-progressbar (~> 1.7)
|
|
74
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
75
|
+
rubocop-ast (1.48.0)
|
|
76
|
+
parser (>= 3.3.7.2)
|
|
77
|
+
prism (~> 1.4)
|
|
78
|
+
rubocop-performance (1.25.0)
|
|
79
|
+
lint_roller (~> 1.1)
|
|
80
|
+
rubocop (>= 1.75.0, < 2.0)
|
|
81
|
+
rubocop-ast (>= 1.38.0, < 2.0)
|
|
82
|
+
ruby-progressbar (1.13.0)
|
|
83
|
+
semantic (1.6.1)
|
|
84
|
+
simplecov (0.22.0)
|
|
85
|
+
docile (~> 1.1)
|
|
86
|
+
simplecov-html (~> 0.11)
|
|
87
|
+
simplecov_json_formatter (~> 0.1)
|
|
88
|
+
simplecov-html (0.13.2)
|
|
89
|
+
simplecov_json_formatter (0.1.4)
|
|
90
|
+
standard (1.35.0.1)
|
|
91
|
+
language_server-protocol (~> 3.17.0.2)
|
|
92
|
+
lint_roller (~> 1.0)
|
|
93
|
+
rubocop (~> 1.62)
|
|
94
|
+
standard-custom (~> 1.0.0)
|
|
95
|
+
standard-performance (~> 1.3)
|
|
96
|
+
standard-custom (1.0.2)
|
|
97
|
+
lint_roller (~> 1.0)
|
|
98
|
+
rubocop (~> 1.50)
|
|
99
|
+
standard-performance (1.8.0)
|
|
100
|
+
lint_roller (~> 1.1)
|
|
101
|
+
rubocop-performance (~> 1.25.0)
|
|
102
|
+
unicode-display_width (3.2.0)
|
|
103
|
+
unicode-emoji (~> 4.1)
|
|
104
|
+
unicode-emoji (4.1.0)
|
|
105
|
+
uri (1.1.1)
|
|
106
|
+
webmock (3.26.1)
|
|
107
|
+
addressable (>= 2.8.0)
|
|
108
|
+
crack (>= 0.3.2)
|
|
109
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
|
110
|
+
|
|
111
|
+
PLATFORMS
|
|
112
|
+
arm64-darwin-24
|
|
113
|
+
ruby
|
|
114
|
+
|
|
115
|
+
DEPENDENCIES
|
|
116
|
+
flagsmith (~> 4.3)
|
|
117
|
+
openfeature-flagsmith-provider!
|
|
118
|
+
rake (~> 13.0)
|
|
119
|
+
rspec (~> 3.12.0)
|
|
120
|
+
rubocop (~> 1.0)
|
|
121
|
+
simplecov (~> 0.22)
|
|
122
|
+
standard (~> 1.0)
|
|
123
|
+
webmock (~> 3.0)
|
|
124
|
+
|
|
125
|
+
BUNDLED WITH
|
|
126
|
+
2.6.9
|