simple_feature_flags 1.4.0 → 1.4.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 +4 -4
- data/Gemfile +2 -2
- data/Gemfile.lock +32 -20
- data/README.md +30 -0
- data/lib/simple_feature_flags/base_storage.rb +15 -5
- data/lib/simple_feature_flags/cli/command/generate.rb +15 -21
- data/lib/simple_feature_flags/cli/options.rb +8 -8
- data/lib/simple_feature_flags/cli/runner.rb +3 -3
- data/lib/simple_feature_flags/configuration.rb +2 -2
- data/lib/simple_feature_flags/ram_storage.rb +91 -173
- data/lib/simple_feature_flags/redis_storage.rb +84 -166
- data/lib/simple_feature_flags/test_ram_storage.rb +2 -1
- data/lib/simple_feature_flags/version.rb +2 -1
- data/lib/simple_feature_flags.rb +4 -14
- metadata +1 -1
@@ -6,16 +6,18 @@ require 'yaml'
|
|
6
6
|
module SimpleFeatureFlags
|
7
7
|
# Stores feature flags in memory.
|
8
8
|
class RamStorage < BaseStorage
|
9
|
-
|
9
|
+
# @override
|
10
|
+
#: String
|
10
11
|
attr_reader :file
|
11
12
|
|
12
|
-
|
13
|
+
# @override
|
14
|
+
#: Array[String]
|
13
15
|
attr_reader :mandatory_flags
|
14
16
|
|
15
|
-
|
17
|
+
#: Hash[Symbol, Hash[String, Object]]
|
16
18
|
attr_reader :flags
|
17
19
|
|
18
|
-
|
20
|
+
#: (String file) -> void
|
19
21
|
def initialize(file)
|
20
22
|
@file = file
|
21
23
|
@mandatory_flags = []
|
@@ -25,7 +27,8 @@ module SimpleFeatureFlags
|
|
25
27
|
end
|
26
28
|
|
27
29
|
# Checks whether the flag is active. Returns `true`, `false`, `:globally` or `:partially`
|
28
|
-
|
30
|
+
# @override
|
31
|
+
#: ((Symbol | String) feature) -> (Symbol | bool)
|
29
32
|
def active(feature)
|
30
33
|
case flags.dig(feature.to_sym, 'active')
|
31
34
|
when 'globally', :globally
|
@@ -40,7 +43,8 @@ module SimpleFeatureFlags
|
|
40
43
|
end
|
41
44
|
|
42
45
|
# Checks whether the flag is active.
|
43
|
-
|
46
|
+
# @override
|
47
|
+
#: ((Symbol | String) feature) -> bool
|
44
48
|
def active?(feature)
|
45
49
|
return true if active(feature)
|
46
50
|
|
@@ -48,45 +52,43 @@ module SimpleFeatureFlags
|
|
48
52
|
end
|
49
53
|
|
50
54
|
# Checks whether the flag is inactive.
|
51
|
-
|
55
|
+
# @override
|
56
|
+
#: ((Symbol | String) feature) -> bool
|
52
57
|
def inactive?(feature)
|
53
58
|
!active?(feature)
|
54
59
|
end
|
55
60
|
|
56
61
|
# Checks whether the flag is active globally, for every object.
|
57
|
-
|
62
|
+
# @override
|
63
|
+
#: ((Symbol | String) feature) -> bool
|
58
64
|
def active_globally?(feature)
|
59
65
|
ACTIVE_GLOBALLY.include? T.unsafe(flags.dig(feature.to_sym, 'active'))
|
60
66
|
end
|
61
67
|
|
62
68
|
# Checks whether the flag is inactive globally, for every object.
|
63
|
-
|
69
|
+
# @override
|
70
|
+
#: ((Symbol | String) feature) -> bool
|
64
71
|
def inactive_globally?(feature)
|
65
72
|
!active_globally?(feature)
|
66
73
|
end
|
67
74
|
|
68
75
|
# Checks whether the flag is active partially, only for certain objects.
|
69
|
-
|
76
|
+
# @override
|
77
|
+
#: ((Symbol | String) feature) -> bool
|
70
78
|
def active_partially?(feature)
|
71
79
|
ACTIVE_PARTIALLY.include? T.unsafe(flags.dig(feature.to_sym, 'active'))
|
72
80
|
end
|
73
81
|
|
74
82
|
# Checks whether the flag is inactive partially, only for certain objects.
|
75
|
-
|
83
|
+
# @override
|
84
|
+
#: ((Symbol | String) feature) -> bool
|
76
85
|
def inactive_partially?(feature)
|
77
86
|
!active_partially?(feature)
|
78
87
|
end
|
79
88
|
|
80
89
|
# Checks whether the flag is active for the given object.
|
81
|
-
|
82
|
-
|
83
|
-
.params(
|
84
|
-
feature: T.any(Symbol, String),
|
85
|
-
object: Object,
|
86
|
-
object_id_method: Symbol,
|
87
|
-
)
|
88
|
-
.returns(T::Boolean)
|
89
|
-
end
|
90
|
+
# @override
|
91
|
+
#: ((Symbol | String) feature, Object object, ?object_id_method: Symbol) -> bool
|
90
92
|
def active_for?(feature, object, object_id_method: CONFIG.default_id_method)
|
91
93
|
return false unless active?(feature)
|
92
94
|
return true if active_globally?(feature)
|
@@ -100,21 +102,15 @@ module SimpleFeatureFlags
|
|
100
102
|
end
|
101
103
|
|
102
104
|
# Checks whether the flag is inactive for the given object.
|
103
|
-
|
104
|
-
|
105
|
-
.params(
|
106
|
-
feature: T.any(Symbol, String),
|
107
|
-
object: Object,
|
108
|
-
object_id_method: Symbol,
|
109
|
-
)
|
110
|
-
.returns(T::Boolean)
|
111
|
-
end
|
105
|
+
# @override
|
106
|
+
#: ((Symbol | String) feature, Object object, ?object_id_method: Symbol) -> bool
|
112
107
|
def inactive_for?(feature, object, object_id_method: CONFIG.default_id_method)
|
113
108
|
!active_for?(feature, object, object_id_method: object_id_method)
|
114
109
|
end
|
115
110
|
|
116
111
|
# Checks whether the flag exists.
|
117
|
-
|
112
|
+
# @override
|
113
|
+
#: ((Symbol | String) feature) -> bool
|
118
114
|
def exists?(feature)
|
119
115
|
return false if [nil, ''].include? flags[feature.to_sym]
|
120
116
|
|
@@ -122,19 +118,15 @@ module SimpleFeatureFlags
|
|
122
118
|
end
|
123
119
|
|
124
120
|
# Returns the description of the flag if it exists.
|
125
|
-
|
121
|
+
# @override
|
122
|
+
#: ((Symbol | String) feature) -> String?
|
126
123
|
def description(feature)
|
127
|
-
|
124
|
+
flags.dig(feature.to_sym, 'description') #: as untyped
|
128
125
|
end
|
129
126
|
|
130
127
|
# Calls the given block if the flag is active.
|
131
|
-
|
132
|
-
|
133
|
-
.params(
|
134
|
-
feature: T.any(Symbol, String),
|
135
|
-
block: T.proc.void,
|
136
|
-
).void
|
137
|
-
end
|
128
|
+
# @override
|
129
|
+
#: ((Symbol | String) feature) { -> void } -> void
|
138
130
|
def when_active(feature, &block)
|
139
131
|
return unless active?(feature)
|
140
132
|
|
@@ -142,13 +134,8 @@ module SimpleFeatureFlags
|
|
142
134
|
end
|
143
135
|
|
144
136
|
# Calls the given block if the flag is inactive.
|
145
|
-
|
146
|
-
|
147
|
-
.params(
|
148
|
-
feature: T.any(Symbol, String),
|
149
|
-
block: T.proc.void,
|
150
|
-
).void
|
151
|
-
end
|
137
|
+
# @override
|
138
|
+
#: ((Symbol | String) feature) { -> void } -> void
|
152
139
|
def when_inactive(feature, &block)
|
153
140
|
return unless inactive?(feature)
|
154
141
|
|
@@ -156,13 +143,8 @@ module SimpleFeatureFlags
|
|
156
143
|
end
|
157
144
|
|
158
145
|
# Calls the given block if the flag is active globally.
|
159
|
-
|
160
|
-
|
161
|
-
.params(
|
162
|
-
feature: T.any(Symbol, String),
|
163
|
-
block: T.proc.void,
|
164
|
-
).void
|
165
|
-
end
|
146
|
+
# @override
|
147
|
+
#: ((Symbol | String) feature) { -> void } -> void
|
166
148
|
def when_active_globally(feature, &block)
|
167
149
|
return unless active_globally?(feature)
|
168
150
|
|
@@ -170,13 +152,8 @@ module SimpleFeatureFlags
|
|
170
152
|
end
|
171
153
|
|
172
154
|
# Calls the given block if the flag is inactive globally.
|
173
|
-
|
174
|
-
|
175
|
-
.params(
|
176
|
-
feature: T.any(Symbol, String),
|
177
|
-
block: T.proc.void,
|
178
|
-
).void
|
179
|
-
end
|
155
|
+
# @override
|
156
|
+
#: ((Symbol | String) feature) { -> void } -> void
|
180
157
|
def when_inactive_globally(feature, &block)
|
181
158
|
return unless inactive_globally?(feature)
|
182
159
|
|
@@ -184,13 +161,8 @@ module SimpleFeatureFlags
|
|
184
161
|
end
|
185
162
|
|
186
163
|
# Calls the given block if the flag is active partially.
|
187
|
-
|
188
|
-
|
189
|
-
.params(
|
190
|
-
feature: T.any(Symbol, String),
|
191
|
-
block: T.proc.void,
|
192
|
-
).void
|
193
|
-
end
|
164
|
+
# @override
|
165
|
+
#: ((Symbol | String) feature) { -> void } -> void
|
194
166
|
def when_active_partially(feature, &block)
|
195
167
|
return unless active_partially?(feature)
|
196
168
|
|
@@ -198,13 +170,8 @@ module SimpleFeatureFlags
|
|
198
170
|
end
|
199
171
|
|
200
172
|
# Calls the given block if the flag is inactive partially.
|
201
|
-
|
202
|
-
|
203
|
-
.params(
|
204
|
-
feature: T.any(Symbol, String),
|
205
|
-
block: T.proc.void,
|
206
|
-
).void
|
207
|
-
end
|
173
|
+
# @override
|
174
|
+
#: ((Symbol | String) feature) { -> void } -> void
|
208
175
|
def when_inactive_partially(feature, &block)
|
209
176
|
return unless inactive_partially?(feature)
|
210
177
|
|
@@ -212,15 +179,8 @@ module SimpleFeatureFlags
|
|
212
179
|
end
|
213
180
|
|
214
181
|
# Calls the given block if the flag is active for the given object.
|
215
|
-
|
216
|
-
|
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
|
182
|
+
# @override
|
183
|
+
#: ((Symbol | String) feature, Object object, ?object_id_method: Symbol) { -> void } -> void
|
224
184
|
def when_active_for(feature, object, object_id_method: CONFIG.default_id_method, &block)
|
225
185
|
return unless active_for?(feature, object, object_id_method: object_id_method)
|
226
186
|
|
@@ -228,15 +188,8 @@ module SimpleFeatureFlags
|
|
228
188
|
end
|
229
189
|
|
230
190
|
# Calls the given block if the flag is inactive for the given object.
|
231
|
-
|
232
|
-
|
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
|
191
|
+
# @override
|
192
|
+
#: ((Symbol | String) feature, Object object, ?object_id_method: Symbol) { -> void } -> void
|
240
193
|
def when_inactive_for(feature, object, object_id_method: CONFIG.default_id_method, &block)
|
241
194
|
return unless inactive_for?(feature, object, object_id_method: object_id_method)
|
242
195
|
|
@@ -244,11 +197,12 @@ module SimpleFeatureFlags
|
|
244
197
|
end
|
245
198
|
|
246
199
|
# Activates the given flag. Returns `false` if it does not exist.
|
247
|
-
|
200
|
+
# @override
|
201
|
+
#: ((Symbol | String) feature) -> bool
|
248
202
|
def activate(feature)
|
249
203
|
return false unless exists?(feature)
|
250
204
|
|
251
|
-
flag =
|
205
|
+
flag = flags[feature.to_sym] #: as !nil
|
252
206
|
flag['active'] = 'globally'
|
253
207
|
|
254
208
|
true
|
@@ -256,15 +210,8 @@ module SimpleFeatureFlags
|
|
256
210
|
|
257
211
|
alias activate_globally activate
|
258
212
|
|
259
|
-
|
260
|
-
|
261
|
-
.type_parameters(:R)
|
262
|
-
.params(
|
263
|
-
feature: T.any(Symbol, String),
|
264
|
-
block: T.proc.returns(T.type_parameter(:R)),
|
265
|
-
)
|
266
|
-
.returns(T.type_parameter(:R))
|
267
|
-
end
|
213
|
+
# @override
|
214
|
+
#: [R] ((Symbol | String) feature) { -> R } -> R
|
268
215
|
def do_activate(feature, &block)
|
269
216
|
feature = feature.to_sym
|
270
217
|
prev_value = flags.dig(feature, 'active')
|
@@ -277,25 +224,19 @@ module SimpleFeatureFlags
|
|
277
224
|
alias do_activate_globally do_activate
|
278
225
|
|
279
226
|
# Activates the given flag partially. Returns `false` if it does not exist.
|
280
|
-
|
227
|
+
# @override
|
228
|
+
#: ((Symbol | String) feature) -> bool
|
281
229
|
def activate_partially(feature)
|
282
230
|
return false unless exists?(feature)
|
283
231
|
|
284
|
-
flag =
|
232
|
+
flag = flags[feature.to_sym] #: as !nil
|
285
233
|
flag['active'] = 'partially'
|
286
234
|
|
287
235
|
true
|
288
236
|
end
|
289
237
|
|
290
|
-
|
291
|
-
|
292
|
-
.type_parameters(:R)
|
293
|
-
.params(
|
294
|
-
feature: T.any(Symbol, String),
|
295
|
-
block: T.proc.returns(T.type_parameter(:R)),
|
296
|
-
)
|
297
|
-
.returns(T.type_parameter(:R))
|
298
|
-
end
|
238
|
+
# @override
|
239
|
+
#: [R] ((Symbol | String) feature) { -> R } -> R
|
299
240
|
def do_activate_partially(feature, &block)
|
300
241
|
feature = feature.to_sym
|
301
242
|
prev_value = flags.dig(feature, 'active')
|
@@ -306,14 +247,8 @@ module SimpleFeatureFlags
|
|
306
247
|
end
|
307
248
|
|
308
249
|
# Activates the given flag for the given objects. Returns `false` if it does not exist.
|
309
|
-
|
310
|
-
|
311
|
-
.params(
|
312
|
-
feature: T.any(Symbol, String),
|
313
|
-
objects: Object,
|
314
|
-
object_id_method: Symbol,
|
315
|
-
).void
|
316
|
-
end
|
250
|
+
# @override
|
251
|
+
#: ((Symbol | String) feature, *Object objects, ?object_id_method: Symbol) -> void
|
317
252
|
def activate_for(feature, *objects, object_id_method: CONFIG.default_id_method)
|
318
253
|
return false unless exists?(feature)
|
319
254
|
|
@@ -326,7 +261,7 @@ module SimpleFeatureFlags
|
|
326
261
|
active_objects_hash[klass]&.concat(ids)&.uniq!&.sort! # rubocop:disable Style/SafeNavigationChainLength
|
327
262
|
end
|
328
263
|
|
329
|
-
flag =
|
264
|
+
flag = flags[feature.to_sym] #: as !nil
|
330
265
|
flag['active_for_objects'] = active_objects_hash
|
331
266
|
|
332
267
|
true
|
@@ -334,14 +269,8 @@ module SimpleFeatureFlags
|
|
334
269
|
|
335
270
|
# Activates the given flag for the given objects and sets the flag as partially active.
|
336
271
|
# Returns `false` if it does not exist.
|
337
|
-
|
338
|
-
|
339
|
-
.params(
|
340
|
-
feature: T.any(Symbol, String),
|
341
|
-
objects: Object,
|
342
|
-
object_id_method: Symbol,
|
343
|
-
).void
|
344
|
-
end
|
272
|
+
# @override
|
273
|
+
#: ((Symbol | String) feature, *Object objects, ?object_id_method: Symbol) -> void
|
345
274
|
def activate_for!(feature, *objects, object_id_method: CONFIG.default_id_method)
|
346
275
|
return false unless T.unsafe(self).activate_for(feature, *objects, object_id_method: object_id_method)
|
347
276
|
|
@@ -351,11 +280,12 @@ module SimpleFeatureFlags
|
|
351
280
|
# Deactivates the given flag for all objects.
|
352
281
|
# Resets the list of objects that this flag has been turned on for.
|
353
282
|
# Returns `false` if it does not exist.
|
354
|
-
|
283
|
+
# @override
|
284
|
+
#: ((Symbol | String) feature) -> bool
|
355
285
|
def deactivate!(feature)
|
356
286
|
return false unless exists?(feature)
|
357
287
|
|
358
|
-
flag =
|
288
|
+
flag = flags[feature.to_sym] #: as !nil
|
359
289
|
flag['active'] = 'false'
|
360
290
|
flag['active_for_objects'] = nil
|
361
291
|
|
@@ -365,16 +295,28 @@ module SimpleFeatureFlags
|
|
365
295
|
# Deactivates the given flag globally.
|
366
296
|
# Does not reset the list of objects that this flag has been turned on for.
|
367
297
|
# Returns `false` if it does not exist.
|
368
|
-
|
298
|
+
# @override
|
299
|
+
#: ((Symbol | String) feature) -> bool
|
369
300
|
def deactivate(feature)
|
370
301
|
return false unless exists?(feature)
|
371
302
|
|
372
|
-
flag =
|
303
|
+
flag = flags[feature.to_sym] #: as !nil
|
373
304
|
flag['active'] = 'false'
|
374
305
|
|
375
306
|
true
|
376
307
|
end
|
377
308
|
|
309
|
+
# @override
|
310
|
+
#: [R] ((Symbol | String) feature) { -> R } -> R
|
311
|
+
def do_deactivate(feature, &block)
|
312
|
+
feature = feature.to_sym
|
313
|
+
prev_value = flags.dig(feature, 'active')
|
314
|
+
deactivate(feature)
|
315
|
+
block.call
|
316
|
+
ensure
|
317
|
+
T.unsafe(flags)[feature]['active'] = prev_value
|
318
|
+
end
|
319
|
+
|
378
320
|
# Returns a hash of Objects that the given flag is turned on for.
|
379
321
|
# The keys are class/model names, values are arrays of IDs of instances/records.
|
380
322
|
#
|
@@ -382,24 +324,15 @@ module SimpleFeatureFlags
|
|
382
324
|
#
|
383
325
|
# { "Page" => [25, 89], "Book" => [152] }
|
384
326
|
#
|
385
|
-
|
386
|
-
|
387
|
-
.params(feature: T.any(Symbol, String))
|
388
|
-
.returns(T::Hash[String, T::Array[Object]])
|
389
|
-
end
|
327
|
+
# @override
|
328
|
+
#: ((Symbol | String) feature) -> Hash[String, Array[Object]]
|
390
329
|
def active_objects(feature)
|
391
330
|
T.unsafe(flags.dig(feature.to_sym, 'active_for_objects')) || {}
|
392
331
|
end
|
393
332
|
|
394
333
|
# Deactivates the given flag for the given objects. Returns `false` if it does not exist.
|
395
|
-
|
396
|
-
|
397
|
-
.params(
|
398
|
-
feature: T.any(Symbol, String),
|
399
|
-
objects: Object,
|
400
|
-
object_id_method: Symbol,
|
401
|
-
).void
|
402
|
-
end
|
334
|
+
# @override
|
335
|
+
#: ((Symbol | String) feature, *Object objects, ?object_id_method: Symbol) -> void
|
403
336
|
def deactivate_for(feature, *objects, object_id_method: CONFIG.default_id_method)
|
404
337
|
return false unless exists?(feature)
|
405
338
|
|
@@ -414,37 +347,27 @@ module SimpleFeatureFlags
|
|
414
347
|
active_ids.reject! { |id| ids_to_remove.include? id }
|
415
348
|
end
|
416
349
|
|
417
|
-
flag =
|
350
|
+
flag = flags[feature.to_sym] #: as !nil
|
418
351
|
flag['active_for_objects'] = active_objects_hash
|
419
352
|
|
420
353
|
true
|
421
354
|
end
|
422
355
|
|
423
356
|
# Returns the data of the flag in a hash.
|
424
|
-
|
425
|
-
|
426
|
-
.params(
|
427
|
-
feature: T.any(Symbol, String),
|
428
|
-
).returns(T.nilable(T::Hash[String, T.anything]))
|
429
|
-
end
|
357
|
+
# @override
|
358
|
+
#: ((Symbol | String) feature) -> Hash[String, top]?
|
430
359
|
def get(feature)
|
431
360
|
return unless exists?(feature)
|
432
361
|
|
433
|
-
flag =
|
362
|
+
flag = flags[feature.to_sym] #: as !nil
|
434
363
|
flag['mandatory'] = mandatory_flags.include?(feature.to_s)
|
435
364
|
|
436
365
|
flag
|
437
366
|
end
|
438
367
|
|
439
368
|
# Adds the given feature flag.
|
440
|
-
|
441
|
-
|
442
|
-
.params(
|
443
|
-
feature: T.any(Symbol, String),
|
444
|
-
description: String,
|
445
|
-
active: T.any(String, Symbol, T::Boolean, NilClass),
|
446
|
-
).returns(T.nilable(T::Hash[String, T.anything]))
|
447
|
-
end
|
369
|
+
# @override
|
370
|
+
#: ((Symbol | String) feature, ?String description, ?(String | Symbol | bool)? active) -> Hash[String, top]?
|
448
371
|
def add(feature, description = '', active = 'false')
|
449
372
|
return if exists?(feature)
|
450
373
|
|
@@ -467,12 +390,8 @@ module SimpleFeatureFlags
|
|
467
390
|
|
468
391
|
# Removes the given feature flag.
|
469
392
|
# Returns its data or nil if it does not exist.
|
470
|
-
|
471
|
-
|
472
|
-
.params(
|
473
|
-
feature: T.any(Symbol, String),
|
474
|
-
).returns(T.nilable(T::Hash[String, T.anything]))
|
475
|
-
end
|
393
|
+
# @override
|
394
|
+
#: ((Symbol | String) feature) -> Hash[String, top]?
|
476
395
|
def remove(feature)
|
477
396
|
return unless exists?(feature)
|
478
397
|
|
@@ -483,9 +402,8 @@ module SimpleFeatureFlags
|
|
483
402
|
end
|
484
403
|
|
485
404
|
# Returns the data of all feature flags.
|
486
|
-
|
487
|
-
|
488
|
-
end
|
405
|
+
# @override
|
406
|
+
#: -> Array[Hash[String, top]]
|
489
407
|
def all
|
490
408
|
hashes = []
|
491
409
|
|