simple_feature_flags 0.1.0 → 1.0.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/.vscode/settings.json +5 -0
- data/Gemfile.lock +1 -1
- data/README.md +161 -14
- data/lib/simple_feature_flags.rb +4 -0
- data/lib/simple_feature_flags/ram_storage.rb +97 -3
- data/lib/simple_feature_flags/redis_storage.rb +107 -3
- data/lib/simple_feature_flags/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9d732d5d2141046aac302cce21de1487ca8c2d3526a64f7ad1845fc964ab8bec
|
4
|
+
data.tar.gz: 98677ad0f773881b575c7e3e3bb1c28b857544bdb6dbe370f8ad1d9f739848f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 003561d885bf3e8ea25c6210c1f727453561c761a22bd08607d5b6e4cbfc36182b168b7ffa901d9c4ebc4e71b3499d1a7d4469ec1fd746c8b62ab4dab47a1abc
|
7
|
+
data.tar.gz: a7bc11c251004a5acfb190f435c993d2c8fd02136581ca74035abbdac174ed3345a6ef7f893048698196c437f22fbd925c14a28917f5bffcd18dc243618b9415
|
data/.vscode/settings.json
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -127,30 +127,144 @@ FEATURE_FLAGS = ::SimpleFeatureFlags::RamStorage.new(config_file)
|
|
127
127
|
|
128
128
|
### Functionality
|
129
129
|
|
130
|
-
####
|
130
|
+
#### Activate a feature
|
131
131
|
|
132
|
-
|
132
|
+
Activates a feature in the global scope
|
133
133
|
|
134
|
-
In case you'd like to add flags programmatically
|
135
134
|
```ruby
|
136
|
-
FEATURE_FLAGS.add(:feature_name, 'Description')
|
137
135
|
FEATURE_FLAGS.active?(:feature_name) #=> false
|
138
136
|
|
139
|
-
|
140
|
-
|
141
|
-
FEATURE_FLAGS.active?(:
|
137
|
+
FEATURE_FLAGS.activate(:feature_name)
|
138
|
+
|
139
|
+
FEATURE_FLAGS.active?(:feature_name) #=> true
|
142
140
|
```
|
143
141
|
|
144
|
-
####
|
142
|
+
#### Deactivate a feature
|
145
143
|
|
146
|
-
|
144
|
+
Deactivates a feature in the global scope
|
147
145
|
|
148
|
-
In case you'd like to remove flags programmatically
|
149
146
|
```ruby
|
150
|
-
FEATURE_FLAGS.
|
147
|
+
FEATURE_FLAGS.active?(:feature_name) #=> true
|
148
|
+
|
149
|
+
FEATURE_FLAGS.deactivate(:feature_name)
|
150
|
+
|
151
151
|
FEATURE_FLAGS.active?(:feature_name) #=> false
|
152
152
|
```
|
153
153
|
|
154
|
+
#### Activate a feature for a particular record/object
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
FEATURE_FLAGS.activate_for(:feature_name, User.first) #=> true
|
158
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.first) #=> true
|
159
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.last) #=> false
|
160
|
+
```
|
161
|
+
|
162
|
+
Note that the flag itself has to be `active` in the global scope for any record/object specific settings to work.
|
163
|
+
When the flag is `deactivated` it is completely turned off globally and for every specific record/object.
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
# The flag is deactivated in the global scope to begin with
|
167
|
+
FEATURE_FLAGS.active?(:feature_name) #=> false
|
168
|
+
|
169
|
+
# We activate it for the first User
|
170
|
+
FEATURE_FLAGS.activate_for(:feature_name, User.first)
|
171
|
+
|
172
|
+
FEATURE_FLAGS.active?(:feature_name) #=> false
|
173
|
+
# It is globally `deactivated` though, so the feature stays inactive for all users
|
174
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.first) #=> false
|
175
|
+
|
176
|
+
# Once we activate the flag in the global scope, record specific settings will be applied
|
177
|
+
FEATURE_FLAGS.activate(:feature_name)
|
178
|
+
|
179
|
+
FEATURE_FLAGS.active?(:feature_name) #=> true
|
180
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.first) #=> true
|
181
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.last) #=> false
|
182
|
+
|
183
|
+
FEATURE_FLAGS.deactivate(:feature_name)
|
184
|
+
|
185
|
+
FEATURE_FLAGS.active?(:feature_name) #=> false
|
186
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.first) #=> false
|
187
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.last) #=> false
|
188
|
+
```
|
189
|
+
|
190
|
+
There is a convenience method `activate_for!`, which activates the feature in the global scope and for specific records/objects at the same time
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
# The flag is deactivated in the global scope to begin with
|
194
|
+
FEATURE_FLAGS.active?(:feature_name) #=> false
|
195
|
+
|
196
|
+
# We activate it in the global scope and for the first User
|
197
|
+
FEATURE_FLAGS.activate_for!(:feature_name, User.first)
|
198
|
+
|
199
|
+
FEATURE_FLAGS.active?(:feature_name) #=> true
|
200
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.first) #=> true
|
201
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.last) #=> false
|
202
|
+
```
|
203
|
+
|
204
|
+
A feature that is `active` in the global scope is inactive for all specific records, unless it has been activated for them.
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
# The flag is active in the global scope to begin with
|
208
|
+
FEATURE_FLAGS.active?(:feature_name) #=> true
|
209
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.first) #=> false
|
210
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.last) #=> false
|
211
|
+
|
212
|
+
FEATURE_FLAGS.activate_for(:feature_name, User.first)
|
213
|
+
|
214
|
+
FEATURE_FLAGS.active?(:feature_name) #=> true
|
215
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.first) #=> true
|
216
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.last) #=> false
|
217
|
+
```
|
218
|
+
|
219
|
+
You can also pass an array of objects to activate all of them simultaneously
|
220
|
+
|
221
|
+
```ruby
|
222
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.first) #=> false
|
223
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.find(2)) #=> false
|
224
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.last) #=> false
|
225
|
+
|
226
|
+
FEATURE_FLAGS.activate_for(:feature_name, User.first(2))
|
227
|
+
|
228
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.first) #=> true
|
229
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.find(2)) #=> true
|
230
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.last) #=> false
|
231
|
+
```
|
232
|
+
|
233
|
+
#### Activate the feature for every record
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
# The flag is active in the global scope to begin with
|
237
|
+
FEATURE_FLAGS.active?(:feature_name) #=> true
|
238
|
+
# It is also enabled for the first user
|
239
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.first) #=> true
|
240
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.last) #=> false
|
241
|
+
|
242
|
+
# We force it onto every user
|
243
|
+
FEATURE_FLAGS.activate!(:feature_name)
|
244
|
+
|
245
|
+
FEATURE_FLAGS.active?(:feature_name) #=> true
|
246
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.first) #=> true
|
247
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.last) #=> true
|
248
|
+
|
249
|
+
# We can easily return to the previous settings
|
250
|
+
FEATURE_FLAGS.activate(:feature_name)
|
251
|
+
|
252
|
+
FEATURE_FLAGS.active?(:feature_name) #=> true
|
253
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.first) #=> true
|
254
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.last) #=> false
|
255
|
+
```
|
256
|
+
|
257
|
+
#### Deactivate a feature for a particular record/object
|
258
|
+
|
259
|
+
```ruby
|
260
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.first) #=> true
|
261
|
+
|
262
|
+
FEATURE_FLAGS.deactivate_for(:feature_name, User.first)
|
263
|
+
|
264
|
+
FEATURE_FLAGS.active_for?(:feature_name, User.first) #=> false
|
265
|
+
```
|
266
|
+
|
267
|
+
|
154
268
|
#### Run a block of code only when the flag is active
|
155
269
|
|
156
270
|
There are two ways of running code only when the feature flag is active
|
@@ -158,18 +272,51 @@ There are two ways of running code only when the feature flag is active
|
|
158
272
|
```ruby
|
159
273
|
number = 1
|
160
274
|
if FEATURE_FLAGS.active?(:feature_name)
|
161
|
-
|
275
|
+
number += 1
|
162
276
|
end
|
163
277
|
|
164
278
|
# or using a block
|
165
279
|
|
166
280
|
# this code will run only when the :feature_name flag is active
|
167
|
-
FEATURE_FLAGS.
|
168
|
-
|
281
|
+
FEATURE_FLAGS.when_active(:feature_name) do
|
282
|
+
number += 1
|
169
283
|
end
|
170
284
|
|
171
285
|
# feature flags that don't exist will return false
|
172
286
|
FEATURE_FLAGS.active?(:non_existant) #=> false
|
287
|
+
|
288
|
+
if FEATURE_FLAGS.active_for?(:feature_name, User.first)
|
289
|
+
number += 1
|
290
|
+
end
|
291
|
+
|
292
|
+
# this code will run only if the :feature_name flag is active for the first User
|
293
|
+
FEATURE_FLAGS.when_active_for(:feature_name, User.first) do
|
294
|
+
number += 1
|
295
|
+
end
|
296
|
+
```
|
297
|
+
|
298
|
+
#### Adding feature flags
|
299
|
+
|
300
|
+
You can add new feature flags programmatically, though we highly encourage you to use the generated `config/simple_feature_flags.yml` file instead. It will make it easier to add and/or remove feature flags automatically on app startup without having to add them manually after merging a branch with new feature flags.
|
301
|
+
|
302
|
+
In case you'd like to add flags programmatically
|
303
|
+
```ruby
|
304
|
+
FEATURE_FLAGS.add(:feature_name, 'Description')
|
305
|
+
FEATURE_FLAGS.active?(:feature_name) #=> false
|
306
|
+
|
307
|
+
# add a new active flag
|
308
|
+
FEATURE_FLAGS.add(:active_feature_name, 'Description', true)
|
309
|
+
FEATURE_FLAGS.active?(:active_feature_name) #=> true
|
310
|
+
```
|
311
|
+
|
312
|
+
#### Removing feature flags
|
313
|
+
|
314
|
+
You can remove feature flags programmatically, though we highly encourage you to use the generated `config/simple_feature_flags.yml` file instead. It will make it easier to add and/or remove feature flags automatically on app startup without having to add them manually after merging a branch with new feature flags.
|
315
|
+
|
316
|
+
In case you'd like to remove flags programmatically
|
317
|
+
```ruby
|
318
|
+
FEATURE_FLAGS.remove(:feature_name)
|
319
|
+
FEATURE_FLAGS.active?(:feature_name) #=> false
|
173
320
|
```
|
174
321
|
|
175
322
|
|
data/lib/simple_feature_flags.rb
CHANGED
@@ -17,6 +17,22 @@ module SimpleFeatureFlags
|
|
17
17
|
__active__(feature)
|
18
18
|
end
|
19
19
|
|
20
|
+
def active_globally?(feature)
|
21
|
+
flags.dig(feature.to_sym, 'active') == 'globally'
|
22
|
+
end
|
23
|
+
|
24
|
+
def active_for?(feature, object, object_id_method = :id)
|
25
|
+
return false unless active?(feature)
|
26
|
+
return true if active_globally?(feature)
|
27
|
+
|
28
|
+
active_objects_hash = active_objects(feature)
|
29
|
+
active_ids = active_objects_hash[object.class.to_s]
|
30
|
+
|
31
|
+
return false unless active_ids
|
32
|
+
|
33
|
+
active_ids.include? object.public_send(object_id_method)
|
34
|
+
end
|
35
|
+
|
20
36
|
def exists?(feature)
|
21
37
|
return false if [nil, ''].include? flags[feature.to_sym]
|
22
38
|
|
@@ -27,12 +43,26 @@ module SimpleFeatureFlags
|
|
27
43
|
flags.dig(feature.to_sym, 'description')
|
28
44
|
end
|
29
45
|
|
30
|
-
def
|
46
|
+
def when_active(feature, ignore_file = false, &block)
|
31
47
|
return unless active?(feature, ignore_file)
|
32
48
|
|
33
49
|
block.call
|
34
50
|
end
|
35
51
|
|
52
|
+
def when_active_for(feature, object, object_id_method = :id, &block)
|
53
|
+
return unless active_for?(feature, object, object_id_method)
|
54
|
+
|
55
|
+
block.call
|
56
|
+
end
|
57
|
+
|
58
|
+
def activate!(feature)
|
59
|
+
return false unless exists?(feature)
|
60
|
+
|
61
|
+
flags[feature.to_sym]['active'] = 'globally'
|
62
|
+
|
63
|
+
true
|
64
|
+
end
|
65
|
+
|
36
66
|
def activate(feature)
|
37
67
|
return false unless exists?(feature)
|
38
68
|
|
@@ -41,6 +71,39 @@ module SimpleFeatureFlags
|
|
41
71
|
true
|
42
72
|
end
|
43
73
|
|
74
|
+
def activate_for(feature, objects, object_id_method = :id)
|
75
|
+
return false unless exists?(feature)
|
76
|
+
|
77
|
+
objects = [objects] unless objects.is_a? ::Array
|
78
|
+
to_activate_hash = objects_to_hash(objects, object_id_method)
|
79
|
+
active_objects_hash = active_objects(feature)
|
80
|
+
|
81
|
+
to_activate_hash.each do |klass, ids|
|
82
|
+
(active_objects_hash[klass] = ids) && next unless active_objects_hash[klass]
|
83
|
+
|
84
|
+
active_objects_hash[klass].concat(ids).sort!
|
85
|
+
end
|
86
|
+
|
87
|
+
flags[feature.to_sym]['active_for_objects'] = active_objects_hash
|
88
|
+
|
89
|
+
true
|
90
|
+
end
|
91
|
+
|
92
|
+
def activate_for!(feature, objects, object_id_method = :id)
|
93
|
+
return false unless activate_for(feature, objects, object_id_method)
|
94
|
+
|
95
|
+
activate(feature)
|
96
|
+
end
|
97
|
+
|
98
|
+
def deactivate!(feature)
|
99
|
+
return false unless exists?(feature)
|
100
|
+
|
101
|
+
flags[feature.to_sym]['active'] = 'false'
|
102
|
+
flags[feature.to_sym]['active_for_objects'] = nil
|
103
|
+
|
104
|
+
true
|
105
|
+
end
|
106
|
+
|
44
107
|
def deactivate(feature)
|
45
108
|
return false unless exists?(feature)
|
46
109
|
|
@@ -49,6 +112,29 @@ module SimpleFeatureFlags
|
|
49
112
|
true
|
50
113
|
end
|
51
114
|
|
115
|
+
def active_objects(feature)
|
116
|
+
flags.dig(feature.to_sym, 'active_for_objects') || {}
|
117
|
+
end
|
118
|
+
|
119
|
+
def deactivate_for(feature, objects, object_id_method = :id)
|
120
|
+
return false unless exists?(feature)
|
121
|
+
|
122
|
+
active_objects_hash = active_objects(feature)
|
123
|
+
|
124
|
+
objects_to_deactivate_hash = objects_to_hash(objects, object_id_method)
|
125
|
+
|
126
|
+
objects_to_deactivate_hash.each do |klass, ids_to_remove|
|
127
|
+
active_ids = active_objects_hash[klass]
|
128
|
+
next unless active_ids
|
129
|
+
|
130
|
+
active_ids.reject! { |id| ids_to_remove.include? id }
|
131
|
+
end
|
132
|
+
|
133
|
+
flags[feature.to_sym]['active_for_objects'] = active_objects_hash
|
134
|
+
|
135
|
+
true
|
136
|
+
end
|
137
|
+
|
52
138
|
def get(feature)
|
53
139
|
return unless exists?(feature)
|
54
140
|
|
@@ -64,6 +150,8 @@ module SimpleFeatureFlags
|
|
64
150
|
active = case active
|
65
151
|
when true, 'true'
|
66
152
|
'true'
|
153
|
+
when 'globally', :globally
|
154
|
+
'globally'
|
67
155
|
else
|
68
156
|
'false'
|
69
157
|
end
|
@@ -102,13 +190,19 @@ module SimpleFeatureFlags
|
|
102
190
|
|
103
191
|
private
|
104
192
|
|
193
|
+
def objects_to_hash(objects, object_id_method = :id)
|
194
|
+
objects = [objects] unless objects.is_a? ::Array
|
195
|
+
|
196
|
+
objects.group_by { |ob| ob.class.to_s }.transform_values { |arr| arr.map(&object_id_method) }
|
197
|
+
end
|
198
|
+
|
105
199
|
def __active__(feature)
|
106
|
-
flags.dig(feature.to_sym, 'active')
|
200
|
+
%w[true globally].include? flags.dig(feature.to_sym, 'active')
|
107
201
|
end
|
108
202
|
|
109
203
|
def import_flags_from_file
|
110
204
|
changes = YAML.load_file(file)
|
111
|
-
changes = { mandatory: [], remove: [] } unless changes.is_a? Hash
|
205
|
+
changes = { mandatory: [], remove: [] } unless changes.is_a? ::Hash
|
112
206
|
|
113
207
|
changes[:mandatory].each do |el|
|
114
208
|
mandatory_flags << el['name']
|
@@ -16,6 +16,27 @@ module SimpleFeatureFlags
|
|
16
16
|
__active__(feature)
|
17
17
|
end
|
18
18
|
|
19
|
+
def active_globally?(feature)
|
20
|
+
case redis.hget(feature.to_s, 'active')
|
21
|
+
when 'globally'
|
22
|
+
true
|
23
|
+
else
|
24
|
+
false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def active_for?(feature, object, object_id_method = :id)
|
29
|
+
return false unless active?(feature)
|
30
|
+
return true if active_globally?(feature)
|
31
|
+
|
32
|
+
active_objects_hash = active_objects(feature)
|
33
|
+
active_ids = active_objects_hash[object.class.to_s]
|
34
|
+
|
35
|
+
return false unless active_ids
|
36
|
+
|
37
|
+
active_ids.include? object.public_send(object_id_method)
|
38
|
+
end
|
39
|
+
|
19
40
|
def exists?(feature)
|
20
41
|
return false if [nil, ''].include? redis.hget(feature.to_s, 'name')
|
21
42
|
|
@@ -26,12 +47,28 @@ module SimpleFeatureFlags
|
|
26
47
|
redis.hget(feature.to_s, 'description')
|
27
48
|
end
|
28
49
|
|
29
|
-
def
|
50
|
+
def when_active(feature, _ignore_file = false, &block)
|
30
51
|
return unless active?(feature)
|
31
52
|
|
32
53
|
block.call
|
33
54
|
end
|
34
55
|
|
56
|
+
def when_active_for(feature, object, object_id_method = :id, &block)
|
57
|
+
return unless active_for?(feature, object, object_id_method)
|
58
|
+
|
59
|
+
block.call
|
60
|
+
end
|
61
|
+
|
62
|
+
def activate!(feature)
|
63
|
+
return false unless exists?(feature)
|
64
|
+
|
65
|
+
redis.hset(feature.to_s, 'active', 'globally')
|
66
|
+
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
alias activate_globally activate!
|
71
|
+
|
35
72
|
def activate(feature)
|
36
73
|
return false unless exists?(feature)
|
37
74
|
|
@@ -40,6 +77,39 @@ module SimpleFeatureFlags
|
|
40
77
|
true
|
41
78
|
end
|
42
79
|
|
80
|
+
def activate_for(feature, objects, object_id_method = :id)
|
81
|
+
return false unless exists?(feature)
|
82
|
+
|
83
|
+
objects = [objects] unless objects.is_a? ::Array
|
84
|
+
to_activate_hash = objects_to_hash(objects, object_id_method)
|
85
|
+
active_objects_hash = active_objects(feature)
|
86
|
+
|
87
|
+
to_activate_hash.each do |klass, ids|
|
88
|
+
(active_objects_hash[klass] = ids) && next unless active_objects_hash[klass]
|
89
|
+
|
90
|
+
active_objects_hash[klass].concat(ids).sort!
|
91
|
+
end
|
92
|
+
|
93
|
+
redis.hset(feature.to_s, 'active_for_objects', active_objects_hash.to_json)
|
94
|
+
|
95
|
+
true
|
96
|
+
end
|
97
|
+
|
98
|
+
def activate_for!(feature, objects, object_id_method = :id)
|
99
|
+
return false unless activate_for(feature, objects, object_id_method)
|
100
|
+
|
101
|
+
activate(feature)
|
102
|
+
end
|
103
|
+
|
104
|
+
def deactivate!(feature)
|
105
|
+
return false unless exists?(feature)
|
106
|
+
|
107
|
+
redis.hset(feature.to_s, 'active', 'false')
|
108
|
+
redis.hset(feature.to_s, 'active_for_objects', '')
|
109
|
+
|
110
|
+
true
|
111
|
+
end
|
112
|
+
|
43
113
|
def deactivate(feature)
|
44
114
|
return false unless exists?(feature)
|
45
115
|
|
@@ -48,11 +118,37 @@ module SimpleFeatureFlags
|
|
48
118
|
true
|
49
119
|
end
|
50
120
|
|
121
|
+
def active_objects(feature)
|
122
|
+
::JSON.parse(redis.hget(feature.to_s, 'active_for_objects').to_s)
|
123
|
+
rescue ::JSON::ParserError
|
124
|
+
{}
|
125
|
+
end
|
126
|
+
|
127
|
+
def deactivate_for(feature, objects, object_id_method = :id)
|
128
|
+
return false unless exists?(feature)
|
129
|
+
|
130
|
+
active_objects_hash = active_objects(feature)
|
131
|
+
|
132
|
+
objects_to_deactivate_hash = objects_to_hash(objects, object_id_method)
|
133
|
+
|
134
|
+
objects_to_deactivate_hash.each do |klass, ids_to_remove|
|
135
|
+
active_ids = active_objects_hash[klass]
|
136
|
+
next unless active_ids
|
137
|
+
|
138
|
+
active_ids.reject! { |id| ids_to_remove.include? id }
|
139
|
+
end
|
140
|
+
|
141
|
+
redis.hset(feature.to_s, 'active_for_objects', active_objects_hash.to_json)
|
142
|
+
|
143
|
+
true
|
144
|
+
end
|
145
|
+
|
51
146
|
def get(feature)
|
52
147
|
return unless exists?(feature)
|
53
148
|
|
54
149
|
hash = redis.hgetall(feature.to_s)
|
55
150
|
hash['mandatory'] = mandatory_flags.include?(feature.to_s)
|
151
|
+
hash['active_for_objects'] = ::JSON.parse(hash['active_for_objects']) rescue {}
|
56
152
|
|
57
153
|
hash
|
58
154
|
end
|
@@ -63,6 +159,8 @@ module SimpleFeatureFlags
|
|
63
159
|
active = case active
|
64
160
|
when true, 'true'
|
65
161
|
'true'
|
162
|
+
when 'globally', :globally
|
163
|
+
'globally'
|
66
164
|
else
|
67
165
|
'false'
|
68
166
|
end
|
@@ -105,9 +203,15 @@ module SimpleFeatureFlags
|
|
105
203
|
|
106
204
|
private
|
107
205
|
|
206
|
+
def objects_to_hash(objects, object_id_method = :id)
|
207
|
+
objects = [objects] unless objects.is_a? ::Array
|
208
|
+
|
209
|
+
objects.group_by { |ob| ob.class.to_s }.transform_values { |arr| arr.map(&object_id_method) }
|
210
|
+
end
|
211
|
+
|
108
212
|
def __active__(feature)
|
109
213
|
case redis.hget(feature.to_s, 'active')
|
110
|
-
when 'true'
|
214
|
+
when 'true', 'globally'
|
111
215
|
true
|
112
216
|
when 'false'
|
113
217
|
false
|
@@ -116,7 +220,7 @@ module SimpleFeatureFlags
|
|
116
220
|
|
117
221
|
def import_flags_from_file
|
118
222
|
changes = YAML.load_file(file)
|
119
|
-
changes = { mandatory: [], remove: [] } unless changes.is_a? Hash
|
223
|
+
changes = { mandatory: [], remove: [] } unless changes.is_a? ::Hash
|
120
224
|
|
121
225
|
changes[:mandatory].each do |el|
|
122
226
|
mandatory_flags << el['name']
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_feature_flags
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Espago
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2021-08-
|
12
|
+
date: 2021-08-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|