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