simple_feature_flags 1.2.0 → 1.3.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 +4 -4
- data/.github/workflows/ci.yml +74 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +14 -60
- data/.ruby-version +1 -1
- data/.vscode/settings.json +5 -1
- data/Gemfile +11 -1
- data/Gemfile.lock +79 -69
- data/Rakefile +5 -5
- data/bin/tapioca +27 -0
- data/bin/test +8 -0
- data/lib/example_files/config/initializers/simple_feature_flags.rb +4 -3
- data/lib/simple_feature_flags/base_storage.rb +296 -0
- data/lib/simple_feature_flags/cli/command/generate.rb +33 -6
- data/lib/simple_feature_flags/cli/command.rb +3 -1
- data/lib/simple_feature_flags/cli/options.rb +19 -3
- data/lib/simple_feature_flags/cli/runner.rb +13 -5
- data/lib/simple_feature_flags/cli.rb +3 -1
- data/lib/simple_feature_flags/configuration.rb +6 -0
- data/lib/simple_feature_flags/ram_storage.rb +253 -79
- data/lib/simple_feature_flags/redis_storage.rb +243 -62
- data/lib/simple_feature_flags/test_ram_storage.rb +7 -1
- data/lib/simple_feature_flags/version.rb +1 -1
- data/lib/simple_feature_flags.rb +22 -9
- data/simple_feature_flags.gemspec +17 -22
- metadata +19 -125
- data/.travis.yml +0 -6
@@ -1,11 +1,21 @@
|
|
1
|
+
# typed: true
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'yaml'
|
4
5
|
|
5
6
|
module SimpleFeatureFlags
|
6
|
-
|
7
|
-
|
7
|
+
# Stores feature flags in Redis.
|
8
|
+
class RedisStorage < BaseStorage
|
9
|
+
sig { override.returns(String) }
|
10
|
+
attr_reader :file
|
8
11
|
|
12
|
+
sig { override.returns(T::Array[String]) }
|
13
|
+
attr_reader :mandatory_flags
|
14
|
+
|
15
|
+
sig { returns(T.any(::Redis, ::Redis::Namespace)) }
|
16
|
+
attr_reader :redis
|
17
|
+
|
18
|
+
sig { params(redis: T.any(::Redis, ::Redis::Namespace), file: String).void }
|
9
19
|
def initialize(redis, file)
|
10
20
|
@file = file
|
11
21
|
@redis = redis
|
@@ -14,46 +24,70 @@ module SimpleFeatureFlags
|
|
14
24
|
import_flags_from_file
|
15
25
|
end
|
16
26
|
|
27
|
+
# Checks whether the flag is active. Returns `true`, `false`, `:globally` or `:partially`
|
28
|
+
sig { override.params(feature: T.any(Symbol, String)).returns(T.any(Symbol, T::Boolean)) }
|
17
29
|
def active(feature)
|
18
30
|
case redis.hget(feature.to_s, 'active')
|
19
31
|
when 'globally'
|
20
32
|
:globally
|
21
33
|
when 'partially'
|
22
34
|
:partially
|
23
|
-
when 'true'
|
35
|
+
when 'true', true
|
24
36
|
true
|
25
|
-
|
37
|
+
else
|
26
38
|
false
|
27
39
|
end
|
28
40
|
end
|
29
41
|
|
42
|
+
# Checks whether the flag is active.
|
43
|
+
sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
|
30
44
|
def active?(feature)
|
31
45
|
return true if active(feature)
|
32
46
|
|
33
47
|
false
|
34
48
|
end
|
35
49
|
|
50
|
+
# Checks whether the flag is inactive.
|
51
|
+
sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
|
36
52
|
def inactive?(feature)
|
37
53
|
!active?(feature)
|
38
54
|
end
|
39
55
|
|
56
|
+
# Checks whether the flag is active globally, for every object.
|
57
|
+
sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
|
40
58
|
def active_globally?(feature)
|
41
59
|
ACTIVE_GLOBALLY.include? redis.hget(feature.to_s, 'active')
|
42
60
|
end
|
43
61
|
|
62
|
+
# Checks whether the flag is inactive globally, for every object.
|
63
|
+
sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
|
44
64
|
def inactive_globally?(feature)
|
45
65
|
!active_globally?(feature)
|
46
66
|
end
|
47
67
|
|
68
|
+
# Checks whether the flag is active partially, only for certain objects.
|
69
|
+
sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
|
48
70
|
def active_partially?(feature)
|
49
71
|
ACTIVE_PARTIALLY.include? redis.hget(feature.to_s, 'active')
|
50
72
|
end
|
51
73
|
|
74
|
+
# Checks whether the flag is inactive partially, only for certain objects.
|
75
|
+
sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
|
52
76
|
def inactive_partially?(feature)
|
53
77
|
!active_partially?(feature)
|
54
78
|
end
|
55
79
|
|
56
|
-
|
80
|
+
# Checks whether the flag is active for the given object.
|
81
|
+
sig do
|
82
|
+
override
|
83
|
+
.params(
|
84
|
+
feature: T.any(Symbol, String),
|
85
|
+
object: Object,
|
86
|
+
object_id_method: Symbol,
|
87
|
+
)
|
88
|
+
.returns(T::Boolean)
|
89
|
+
end
|
90
|
+
def active_for?(feature, object, object_id_method: CONFIG.default_id_method)
|
57
91
|
return false unless active?(feature)
|
58
92
|
return true if active_globally?(feature)
|
59
93
|
|
@@ -65,68 +99,152 @@ module SimpleFeatureFlags
|
|
65
99
|
active_ids.include? object.public_send(object_id_method)
|
66
100
|
end
|
67
101
|
|
68
|
-
|
69
|
-
|
102
|
+
# Checks whether the flag is inactive for the given object.
|
103
|
+
sig do
|
104
|
+
override
|
105
|
+
.params(
|
106
|
+
feature: T.any(Symbol, String),
|
107
|
+
object: Object,
|
108
|
+
object_id_method: Symbol,
|
109
|
+
)
|
110
|
+
.returns(T::Boolean)
|
111
|
+
end
|
112
|
+
def inactive_for?(feature, object, object_id_method: CONFIG.default_id_method)
|
113
|
+
!active_for?(feature, object, object_id_method: object_id_method)
|
70
114
|
end
|
71
115
|
|
116
|
+
# Checks whether the flag exists.
|
117
|
+
sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
|
72
118
|
def exists?(feature)
|
73
119
|
return false if [nil, ''].include? redis.hget(feature.to_s, 'name')
|
74
120
|
|
75
121
|
true
|
76
122
|
end
|
77
123
|
|
124
|
+
# Returns the description of the flag if it exists.
|
125
|
+
sig { override.params(feature: T.any(Symbol, String)).returns(T.nilable(String)) }
|
78
126
|
def description(feature)
|
79
127
|
redis.hget(feature.to_s, 'description')
|
80
128
|
end
|
81
129
|
|
82
|
-
|
130
|
+
# Calls the given block if the flag is active.
|
131
|
+
sig do
|
132
|
+
override
|
133
|
+
.params(
|
134
|
+
feature: T.any(Symbol, String),
|
135
|
+
block: T.proc.void,
|
136
|
+
).void
|
137
|
+
end
|
138
|
+
def when_active(feature, &block)
|
83
139
|
return unless active?(feature)
|
84
140
|
|
85
|
-
|
141
|
+
block.call
|
86
142
|
end
|
87
143
|
|
88
|
-
|
144
|
+
# Calls the given block if the flag is inactive.
|
145
|
+
sig do
|
146
|
+
override
|
147
|
+
.params(
|
148
|
+
feature: T.any(Symbol, String),
|
149
|
+
block: T.proc.void,
|
150
|
+
).void
|
151
|
+
end
|
152
|
+
def when_inactive(feature, &block)
|
89
153
|
return unless inactive?(feature)
|
90
154
|
|
91
|
-
|
155
|
+
block.call
|
92
156
|
end
|
93
157
|
|
94
|
-
|
158
|
+
# Calls the given block if the flag is active globally.
|
159
|
+
sig do
|
160
|
+
override
|
161
|
+
.params(
|
162
|
+
feature: T.any(Symbol, String),
|
163
|
+
block: T.proc.void,
|
164
|
+
).void
|
165
|
+
end
|
166
|
+
def when_active_globally(feature, &block)
|
95
167
|
return unless active_globally?(feature)
|
96
168
|
|
97
|
-
|
169
|
+
block.call
|
98
170
|
end
|
99
171
|
|
100
|
-
|
172
|
+
# Calls the given block if the flag is inactive globally.
|
173
|
+
sig do
|
174
|
+
override
|
175
|
+
.params(
|
176
|
+
feature: T.any(Symbol, String),
|
177
|
+
block: T.proc.void,
|
178
|
+
).void
|
179
|
+
end
|
180
|
+
def when_inactive_globally(feature, &block)
|
101
181
|
return unless inactive_globally?(feature)
|
102
182
|
|
103
|
-
|
183
|
+
block.call
|
104
184
|
end
|
105
185
|
|
106
|
-
|
186
|
+
# Calls the given block if the flag is active partially.
|
187
|
+
sig do
|
188
|
+
override
|
189
|
+
.params(
|
190
|
+
feature: T.any(Symbol, String),
|
191
|
+
block: T.proc.void,
|
192
|
+
).void
|
193
|
+
end
|
194
|
+
def when_active_partially(feature, &block)
|
107
195
|
return unless active_partially?(feature)
|
108
196
|
|
109
|
-
|
197
|
+
block.call
|
110
198
|
end
|
111
199
|
|
112
|
-
|
200
|
+
# Calls the given block if the flag is inactive partially.
|
201
|
+
sig do
|
202
|
+
override
|
203
|
+
.params(
|
204
|
+
feature: T.any(Symbol, String),
|
205
|
+
block: T.proc.void,
|
206
|
+
).void
|
207
|
+
end
|
208
|
+
def when_inactive_partially(feature, &block)
|
113
209
|
return unless inactive_partially?(feature)
|
114
210
|
|
115
|
-
|
211
|
+
block.call
|
116
212
|
end
|
117
213
|
|
118
|
-
|
119
|
-
|
214
|
+
# Calls the given block if the flag is active for the given object.
|
215
|
+
sig do
|
216
|
+
override
|
217
|
+
.params(
|
218
|
+
feature: T.any(Symbol, String),
|
219
|
+
object: Object,
|
220
|
+
object_id_method: Symbol,
|
221
|
+
block: T.proc.void,
|
222
|
+
).void
|
223
|
+
end
|
224
|
+
def when_active_for(feature, object, object_id_method: CONFIG.default_id_method, &block)
|
225
|
+
return unless active_for?(feature, object, object_id_method: object_id_method)
|
120
226
|
|
121
|
-
|
227
|
+
block.call
|
122
228
|
end
|
123
229
|
|
124
|
-
|
125
|
-
|
230
|
+
# Calls the given block if the flag is inactive for the given object.
|
231
|
+
sig do
|
232
|
+
override
|
233
|
+
.params(
|
234
|
+
feature: T.any(Symbol, String),
|
235
|
+
object: Object,
|
236
|
+
object_id_method: Symbol,
|
237
|
+
block: T.proc.void,
|
238
|
+
).void
|
239
|
+
end
|
240
|
+
def when_inactive_for(feature, object, object_id_method: CONFIG.default_id_method, &block)
|
241
|
+
return unless inactive_for?(feature, object, object_id_method: object_id_method)
|
126
242
|
|
127
|
-
|
243
|
+
block.call
|
128
244
|
end
|
129
245
|
|
246
|
+
# Activates the given flag. Returns `false` if it does not exist.
|
247
|
+
sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
|
130
248
|
def activate(feature)
|
131
249
|
return false unless exists?(feature)
|
132
250
|
|
@@ -137,6 +255,8 @@ module SimpleFeatureFlags
|
|
137
255
|
|
138
256
|
alias activate_globally activate
|
139
257
|
|
258
|
+
# Activates the given flag partially. Returns `false` if it does not exist.
|
259
|
+
sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
|
140
260
|
def activate_partially(feature)
|
141
261
|
return false unless exists?(feature)
|
142
262
|
|
@@ -145,17 +265,25 @@ module SimpleFeatureFlags
|
|
145
265
|
true
|
146
266
|
end
|
147
267
|
|
148
|
-
|
268
|
+
# Activates the given flag for the given objects. Returns `false` if it does not exist.
|
269
|
+
sig do
|
270
|
+
override
|
271
|
+
.params(
|
272
|
+
feature: T.any(Symbol, String),
|
273
|
+
objects: Object,
|
274
|
+
object_id_method: Symbol,
|
275
|
+
).void
|
276
|
+
end
|
277
|
+
def activate_for(feature, *objects, object_id_method: CONFIG.default_id_method)
|
149
278
|
return false unless exists?(feature)
|
150
279
|
|
151
|
-
|
152
|
-
to_activate_hash = objects_to_hash(objects, object_id_method)
|
280
|
+
to_activate_hash = objects_to_hash(objects, object_id_method: object_id_method)
|
153
281
|
active_objects_hash = active_objects(feature)
|
154
282
|
|
155
283
|
to_activate_hash.each do |klass, ids|
|
156
284
|
(active_objects_hash[klass] = ids) && next unless active_objects_hash[klass]
|
157
285
|
|
158
|
-
active_objects_hash[klass]
|
286
|
+
active_objects_hash[klass]&.concat(ids)&.uniq!&.sort! # rubocop:disable Style/SafeNavigationChainLength
|
159
287
|
end
|
160
288
|
|
161
289
|
redis.hset(feature.to_s, 'active_for_objects', active_objects_hash.to_json)
|
@@ -163,12 +291,26 @@ module SimpleFeatureFlags
|
|
163
291
|
true
|
164
292
|
end
|
165
293
|
|
166
|
-
|
167
|
-
|
294
|
+
# Activates the given flag for the given objects and sets the flag as partially active.
|
295
|
+
# Returns `false` if it does not exist.
|
296
|
+
sig do
|
297
|
+
override
|
298
|
+
.params(
|
299
|
+
feature: T.any(Symbol, String),
|
300
|
+
objects: Object,
|
301
|
+
object_id_method: Symbol,
|
302
|
+
).void
|
303
|
+
end
|
304
|
+
def activate_for!(feature, *objects, object_id_method: CONFIG.default_id_method)
|
305
|
+
return false unless T.unsafe(self).activate_for(feature, *objects, object_id_method: object_id_method)
|
168
306
|
|
169
307
|
activate_partially(feature)
|
170
308
|
end
|
171
309
|
|
310
|
+
# Deactivates the given flag for all objects.
|
311
|
+
# Resets the list of objects that this flag has been turned on for.
|
312
|
+
# Returns `false` if it does not exist.
|
313
|
+
sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
|
172
314
|
def deactivate!(feature)
|
173
315
|
return false unless exists?(feature)
|
174
316
|
|
@@ -178,6 +320,10 @@ module SimpleFeatureFlags
|
|
178
320
|
true
|
179
321
|
end
|
180
322
|
|
323
|
+
# Deactivates the given flag globally.
|
324
|
+
# Does not reset the list of objects that this flag has been turned on for.
|
325
|
+
# Returns `false` if it does not exist.
|
326
|
+
sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
|
181
327
|
def deactivate(feature)
|
182
328
|
return false unless exists?(feature)
|
183
329
|
|
@@ -186,18 +332,39 @@ module SimpleFeatureFlags
|
|
186
332
|
true
|
187
333
|
end
|
188
334
|
|
335
|
+
# Returns a hash of Objects that the given flag is turned on for.
|
336
|
+
# The keys are class/model names, values are arrays of IDs of instances/records.
|
337
|
+
#
|
338
|
+
# looks like this:
|
339
|
+
#
|
340
|
+
# { "Page" => [25, 89], "Book" => [152] }
|
341
|
+
#
|
342
|
+
sig do
|
343
|
+
override
|
344
|
+
.params(feature: T.any(Symbol, String))
|
345
|
+
.returns(T::Hash[String, T::Array[Object]])
|
346
|
+
end
|
189
347
|
def active_objects(feature)
|
190
348
|
::JSON.parse(redis.hget(feature.to_s, 'active_for_objects').to_s)
|
191
349
|
rescue ::JSON::ParserError
|
192
350
|
{}
|
193
351
|
end
|
194
352
|
|
195
|
-
|
353
|
+
# Deactivates the given flag for the given objects. Returns `false` if it does not exist.
|
354
|
+
sig do
|
355
|
+
override
|
356
|
+
.params(
|
357
|
+
feature: T.any(Symbol, String),
|
358
|
+
objects: Object,
|
359
|
+
object_id_method: Symbol,
|
360
|
+
).void
|
361
|
+
end
|
362
|
+
def deactivate_for(feature, *objects, object_id_method: CONFIG.default_id_method)
|
196
363
|
return false unless exists?(feature)
|
197
364
|
|
198
365
|
active_objects_hash = active_objects(feature)
|
199
366
|
|
200
|
-
objects_to_deactivate_hash = objects_to_hash(objects, object_id_method)
|
367
|
+
objects_to_deactivate_hash = objects_to_hash(objects, object_id_method: object_id_method)
|
201
368
|
|
202
369
|
objects_to_deactivate_hash.each do |klass, ids_to_remove|
|
203
370
|
active_ids = active_objects_hash[klass]
|
@@ -211,18 +378,38 @@ module SimpleFeatureFlags
|
|
211
378
|
true
|
212
379
|
end
|
213
380
|
|
381
|
+
# Returns the data of the flag in a hash.
|
382
|
+
sig do
|
383
|
+
override
|
384
|
+
.params(
|
385
|
+
feature: T.any(Symbol, String),
|
386
|
+
).returns(T.nilable(T::Hash[String, T.anything]))
|
387
|
+
end
|
214
388
|
def get(feature)
|
215
389
|
return unless exists?(feature)
|
216
390
|
|
217
391
|
hash = redis.hgetall(feature.to_s)
|
218
392
|
hash['mandatory'] = mandatory_flags.include?(feature.to_s)
|
219
|
-
hash['active_for_objects'] =
|
393
|
+
hash['active_for_objects'] = begin
|
394
|
+
::JSON.parse(hash['active_for_objects'])
|
395
|
+
rescue StandardError
|
396
|
+
{}
|
397
|
+
end
|
220
398
|
|
221
399
|
hash
|
222
400
|
end
|
223
401
|
|
402
|
+
# Adds the given feature flag.
|
403
|
+
sig do
|
404
|
+
override
|
405
|
+
.params(
|
406
|
+
feature: T.any(Symbol, String),
|
407
|
+
description: String,
|
408
|
+
active: T.any(String, Symbol, T::Boolean, NilClass),
|
409
|
+
).returns(T.nilable(T::Hash[String, T.anything]))
|
410
|
+
end
|
224
411
|
def add(feature, description, active = 'false')
|
225
|
-
return
|
412
|
+
return if exists?(feature)
|
226
413
|
|
227
414
|
active = if ACTIVE_GLOBALLY.include?(active)
|
228
415
|
'globally'
|
@@ -233,17 +420,25 @@ module SimpleFeatureFlags
|
|
233
420
|
end
|
234
421
|
|
235
422
|
hash = {
|
236
|
-
'name'
|
237
|
-
'active'
|
238
|
-
'description' => description
|
423
|
+
'name' => feature.to_s,
|
424
|
+
'active' => active,
|
425
|
+
'description' => description,
|
239
426
|
}
|
240
427
|
|
241
428
|
redis.hset(feature.to_s, hash)
|
242
429
|
hash
|
243
430
|
end
|
244
431
|
|
432
|
+
# Removes the given feature flag.
|
433
|
+
# Returns its data or nil if it does not exist.
|
434
|
+
sig do
|
435
|
+
override
|
436
|
+
.params(
|
437
|
+
feature: T.any(Symbol, String),
|
438
|
+
).returns(T.nilable(T::Hash[String, T.anything]))
|
439
|
+
end
|
245
440
|
def remove(feature)
|
246
|
-
return
|
441
|
+
return unless exists?(feature)
|
247
442
|
|
248
443
|
removed = get(feature)
|
249
444
|
redis.del(feature.to_s)
|
@@ -251,10 +446,14 @@ module SimpleFeatureFlags
|
|
251
446
|
removed
|
252
447
|
end
|
253
448
|
|
449
|
+
# Returns the data of all feature flags.
|
450
|
+
sig do
|
451
|
+
override.returns(T::Array[T::Hash[String, T.anything]])
|
452
|
+
end
|
254
453
|
def all
|
255
454
|
keys = []
|
256
455
|
hashes = []
|
257
|
-
redis.scan_each(match:
|
456
|
+
redis.scan_each(match: '*') do |key|
|
258
457
|
next if keys.include?(key)
|
259
458
|
|
260
459
|
keys << key
|
@@ -264,30 +463,12 @@ module SimpleFeatureFlags
|
|
264
463
|
hashes
|
265
464
|
end
|
266
465
|
|
466
|
+
sig { returns(T.nilable(Redis::Namespace)) }
|
267
467
|
def namespaced_redis
|
268
|
-
redis
|
269
|
-
|
468
|
+
r = redis
|
469
|
+
return unless r.is_a?(Redis::Namespace)
|
270
470
|
|
271
|
-
|
272
|
-
|
273
|
-
def objects_to_hash(objects, object_id_method = CONFIG.default_id_method)
|
274
|
-
objects = [objects] unless objects.is_a? ::Array
|
275
|
-
|
276
|
-
objects.group_by { |ob| ob.class.to_s }.transform_values { |arr| arr.map(&object_id_method) }
|
277
|
-
end
|
278
|
-
|
279
|
-
def import_flags_from_file
|
280
|
-
changes = ::YAML.load_file(file)
|
281
|
-
changes = { mandatory: [], remove: [] } unless changes.is_a? ::Hash
|
282
|
-
|
283
|
-
changes[:mandatory].each do |el|
|
284
|
-
mandatory_flags << el['name']
|
285
|
-
add(el['name'], el['description'], el['active'])
|
286
|
-
end
|
287
|
-
|
288
|
-
changes[:remove].each do |el|
|
289
|
-
remove(el)
|
290
|
-
end
|
471
|
+
r
|
291
472
|
end
|
292
473
|
end
|
293
474
|
end
|
@@ -1,9 +1,15 @@
|
|
1
|
+
# typed: true
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module SimpleFeatureFlags
|
5
|
+
# Used in tests
|
4
6
|
class TestRamStorage < RamStorage
|
7
|
+
sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
|
5
8
|
def active?(feature)
|
6
|
-
|
9
|
+
unless mandatory_flags.include?(feature.to_s)
|
10
|
+
raise(FlagNotDefinedError,
|
11
|
+
"Feature Flag `#{feature}` is not defined as mandatory in #{file}",)
|
12
|
+
end
|
7
13
|
|
8
14
|
super
|
9
15
|
end
|
data/lib/simple_feature_flags.rb
CHANGED
@@ -1,17 +1,24 @@
|
|
1
|
+
# typed: true
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'json'
|
5
|
+
require 'set'
|
6
|
+
require 'sorbet-runtime'
|
4
7
|
|
5
|
-
Dir[File.expand_path('simple_feature_flags/*.rb', __dir__)].
|
8
|
+
Dir[File.expand_path('simple_feature_flags/*.rb', __dir__)].each { |file| require file }
|
6
9
|
|
10
|
+
# Tha main namespace of the `simple_feature_flags` gem.
|
7
11
|
module SimpleFeatureFlags
|
12
|
+
extend T::Sig
|
13
|
+
|
8
14
|
NOT_PRESENT = ::Object.new.freeze
|
9
|
-
UI_GEM = 'simple_feature_flags-ui'
|
10
|
-
UI_CLASS_NAME = '::SimpleFeatureFlags::Ui'
|
11
|
-
WEB_UI_CLASS_NAME = '::SimpleFeatureFlags::Ui::Web'
|
15
|
+
UI_GEM = T.let('simple_feature_flags-ui', String)
|
16
|
+
UI_CLASS_NAME = T.let('::SimpleFeatureFlags::Ui', String)
|
17
|
+
WEB_UI_CLASS_NAME = T.let('::SimpleFeatureFlags::Ui::Web', String)
|
12
18
|
|
13
|
-
ACTIVE_GLOBALLY = ::Set['globally', :globally, 'true', true].freeze
|
14
|
-
|
19
|
+
ACTIVE_GLOBALLY = T.let(::Set['globally', :globally, 'true', true].freeze,
|
20
|
+
T::Set[T.any(String, Symbol, T::Boolean, NilClass)],)
|
21
|
+
ACTIVE_PARTIALLY = T.let(::Set['partially', :partially].freeze, T::Set[T.any(String, Symbol, T::Boolean, NilClass)])
|
15
22
|
|
16
23
|
class NoSuchCommandError < StandardError; end
|
17
24
|
|
@@ -19,9 +26,15 @@ module SimpleFeatureFlags
|
|
19
26
|
|
20
27
|
class FlagNotDefinedError < StandardError; end
|
21
28
|
|
22
|
-
CONFIG = Configuration.new
|
29
|
+
CONFIG = T.let(Configuration.new, Configuration)
|
30
|
+
|
31
|
+
class << self
|
32
|
+
extend T::Sig
|
23
33
|
|
24
|
-
|
25
|
-
block
|
34
|
+
sig { params(block: T.proc.params(arg0: Configuration).void).returns(Configuration) }
|
35
|
+
def configure(&block)
|
36
|
+
block.call(CONFIG)
|
37
|
+
CONFIG
|
38
|
+
end
|
26
39
|
end
|
27
40
|
end
|
@@ -3,36 +3,31 @@
|
|
3
3
|
require_relative 'lib/simple_feature_flags/version'
|
4
4
|
|
5
5
|
::Gem::Specification.new do |spec|
|
6
|
-
spec.name =
|
6
|
+
spec.name = 'simple_feature_flags'
|
7
7
|
spec.version = ::SimpleFeatureFlags::VERSION
|
8
|
-
spec.authors = [
|
9
|
-
spec.email = [
|
8
|
+
spec.authors = ['Espago', 'Mateusz Drewniak']
|
9
|
+
spec.email = ['m.drewniak@espago.com']
|
10
10
|
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
|
14
|
-
|
15
|
-
spec.
|
11
|
+
spec.summary = 'Simple feature flag functionality for your Ruby/Rails/Sinatra app!'
|
12
|
+
spec.description = <<~DESC
|
13
|
+
A simple Ruby gem which lets you dynamically enable/disable parts of your code using Redis or your server's RAM!
|
14
|
+
DESC
|
15
|
+
spec.homepage = 'https://github.com/espago/simple_feature_flags'
|
16
|
+
spec.license = 'MIT'
|
17
|
+
spec.required_ruby_version = '>= 3.1.0'
|
16
18
|
|
17
|
-
spec.metadata[
|
18
|
-
spec.metadata[
|
19
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
20
|
+
spec.metadata['source_code_uri'] = 'https://github.com/espago/simple_feature_flags'
|
19
21
|
|
20
22
|
# Specify which files should be added to the gem when it is released.
|
21
23
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
24
|
spec.files = ::Dir.chdir(::File.expand_path(__dir__)) do
|
23
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|sorbet)/}) }
|
24
26
|
end
|
25
|
-
spec.bindir =
|
27
|
+
spec.bindir = 'exe'
|
26
28
|
spec.executables = ['simple_feature_flags']
|
27
|
-
spec.require_paths = [
|
29
|
+
spec.require_paths = ['lib']
|
28
30
|
|
29
|
-
spec.
|
30
|
-
spec.
|
31
|
-
spec.add_development_dependency 'byebug'
|
32
|
-
spec.add_development_dependency 'minitest', '~> 5.0'
|
33
|
-
spec.add_development_dependency 'rake', '~> 12.0'
|
34
|
-
spec.add_development_dependency 'redis'
|
35
|
-
spec.add_development_dependency 'redis-namespace'
|
36
|
-
spec.add_development_dependency 'rubocop'
|
37
|
-
spec.add_development_dependency 'solargraph'
|
31
|
+
spec.add_dependency 'sorbet-runtime', '> 0.5'
|
32
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
38
33
|
end
|