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.
@@ -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
- class RedisStorage
7
- attr_reader :file, :redis, :mandatory_flags
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
- when 'false'
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
- def active_for?(feature, object, object_id_method = CONFIG.default_id_method)
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
- def inactive_for?(feature, object, object_id_method = CONFIG.default_id_method)
69
- !active_for?(feature, object, object_id_method)
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
- def when_active(feature)
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
- yield
141
+ block.call
86
142
  end
87
143
 
88
- def when_inactive(feature)
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
- yield
155
+ block.call
92
156
  end
93
157
 
94
- def when_active_globally(feature)
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
- yield
169
+ block.call
98
170
  end
99
171
 
100
- def when_inactive_globally(feature)
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
- yield
183
+ block.call
104
184
  end
105
185
 
106
- def when_active_partially(feature)
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
- yield
197
+ block.call
110
198
  end
111
199
 
112
- def when_inactive_partially(feature)
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
- yield
211
+ block.call
116
212
  end
117
213
 
118
- def when_active_for(feature, object, object_id_method = CONFIG.default_id_method)
119
- return unless active_for?(feature, object, object_id_method)
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
- yield
227
+ block.call
122
228
  end
123
229
 
124
- def when_inactive_for(feature, object, object_id_method = CONFIG.default_id_method)
125
- return unless inactive_for?(feature, object, object_id_method)
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
- yield
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
 
@@ -135,8 +253,30 @@ module SimpleFeatureFlags
135
253
  true
136
254
  end
137
255
 
256
+ sig do
257
+ override
258
+ .type_parameters(:R)
259
+ .params(
260
+ feature: T.any(Symbol, String),
261
+ block: T.proc.returns(T.type_parameter(:R)),
262
+ )
263
+ .returns(T.type_parameter(:R))
264
+ end
265
+ def do_activate(feature, &block)
266
+ feature = feature.to_s
267
+ prev_value = redis.hget(feature, 'active')
268
+ activate(feature)
269
+ block.call
270
+ ensure
271
+ redis.hset(feature, 'active', prev_value)
272
+ end
273
+
274
+ alias do_activate_globally do_activate
275
+
138
276
  alias activate_globally activate
139
277
 
278
+ # Activates the given flag partially. Returns `false` if it does not exist.
279
+ sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
140
280
  def activate_partially(feature)
141
281
  return false unless exists?(feature)
142
282
 
@@ -145,17 +285,43 @@ module SimpleFeatureFlags
145
285
  true
146
286
  end
147
287
 
148
- def activate_for(feature, objects, object_id_method = CONFIG.default_id_method)
288
+ sig do
289
+ override
290
+ .type_parameters(:R)
291
+ .params(
292
+ feature: T.any(Symbol, String),
293
+ block: T.proc.returns(T.type_parameter(:R)),
294
+ )
295
+ .returns(T.type_parameter(:R))
296
+ end
297
+ def do_activate_partially(feature, &block)
298
+ feature = feature.to_s
299
+ prev_value = redis.hget(feature, 'active')
300
+ activate_partially(feature)
301
+ block.call
302
+ ensure
303
+ redis.hset(feature, 'active', prev_value)
304
+ end
305
+
306
+ # Activates the given flag for the given objects. Returns `false` if it does not exist.
307
+ sig do
308
+ override
309
+ .params(
310
+ feature: T.any(Symbol, String),
311
+ objects: Object,
312
+ object_id_method: Symbol,
313
+ ).void
314
+ end
315
+ def activate_for(feature, *objects, object_id_method: CONFIG.default_id_method)
149
316
  return false unless exists?(feature)
150
317
 
151
- objects = [objects] unless objects.is_a? ::Array
152
- to_activate_hash = objects_to_hash(objects, object_id_method)
318
+ to_activate_hash = objects_to_hash(objects, object_id_method: object_id_method)
153
319
  active_objects_hash = active_objects(feature)
154
320
 
155
321
  to_activate_hash.each do |klass, ids|
156
322
  (active_objects_hash[klass] = ids) && next unless active_objects_hash[klass]
157
323
 
158
- active_objects_hash[klass].concat(ids).uniq!.sort!
324
+ active_objects_hash[klass]&.concat(ids)&.uniq!&.sort! # rubocop:disable Style/SafeNavigationChainLength
159
325
  end
160
326
 
161
327
  redis.hset(feature.to_s, 'active_for_objects', active_objects_hash.to_json)
@@ -163,12 +329,26 @@ module SimpleFeatureFlags
163
329
  true
164
330
  end
165
331
 
166
- def activate_for!(feature, objects, object_id_method = CONFIG.default_id_method)
167
- return false unless activate_for(feature, objects, object_id_method)
332
+ # Activates the given flag for the given objects and sets the flag as partially active.
333
+ # Returns `false` if it does not exist.
334
+ sig do
335
+ override
336
+ .params(
337
+ feature: T.any(Symbol, String),
338
+ objects: Object,
339
+ object_id_method: Symbol,
340
+ ).void
341
+ end
342
+ def activate_for!(feature, *objects, object_id_method: CONFIG.default_id_method)
343
+ return false unless T.unsafe(self).activate_for(feature, *objects, object_id_method: object_id_method)
168
344
 
169
345
  activate_partially(feature)
170
346
  end
171
347
 
348
+ # Deactivates the given flag for all objects.
349
+ # Resets the list of objects that this flag has been turned on for.
350
+ # Returns `false` if it does not exist.
351
+ sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
172
352
  def deactivate!(feature)
173
353
  return false unless exists?(feature)
174
354
 
@@ -178,6 +358,10 @@ module SimpleFeatureFlags
178
358
  true
179
359
  end
180
360
 
361
+ # Deactivates the given flag globally.
362
+ # Does not reset the list of objects that this flag has been turned on for.
363
+ # Returns `false` if it does not exist.
364
+ sig { override.params(feature: T.any(Symbol, String)).returns(T::Boolean) }
181
365
  def deactivate(feature)
182
366
  return false unless exists?(feature)
183
367
 
@@ -186,18 +370,39 @@ module SimpleFeatureFlags
186
370
  true
187
371
  end
188
372
 
373
+ # Returns a hash of Objects that the given flag is turned on for.
374
+ # The keys are class/model names, values are arrays of IDs of instances/records.
375
+ #
376
+ # looks like this:
377
+ #
378
+ # { "Page" => [25, 89], "Book" => [152] }
379
+ #
380
+ sig do
381
+ override
382
+ .params(feature: T.any(Symbol, String))
383
+ .returns(T::Hash[String, T::Array[Object]])
384
+ end
189
385
  def active_objects(feature)
190
386
  ::JSON.parse(redis.hget(feature.to_s, 'active_for_objects').to_s)
191
387
  rescue ::JSON::ParserError
192
388
  {}
193
389
  end
194
390
 
195
- def deactivate_for(feature, objects, object_id_method = CONFIG.default_id_method)
391
+ # Deactivates the given flag for the given objects. Returns `false` if it does not exist.
392
+ sig do
393
+ override
394
+ .params(
395
+ feature: T.any(Symbol, String),
396
+ objects: Object,
397
+ object_id_method: Symbol,
398
+ ).void
399
+ end
400
+ def deactivate_for(feature, *objects, object_id_method: CONFIG.default_id_method)
196
401
  return false unless exists?(feature)
197
402
 
198
403
  active_objects_hash = active_objects(feature)
199
404
 
200
- objects_to_deactivate_hash = objects_to_hash(objects, object_id_method)
405
+ objects_to_deactivate_hash = objects_to_hash(objects, object_id_method: object_id_method)
201
406
 
202
407
  objects_to_deactivate_hash.each do |klass, ids_to_remove|
203
408
  active_ids = active_objects_hash[klass]
@@ -211,18 +416,38 @@ module SimpleFeatureFlags
211
416
  true
212
417
  end
213
418
 
419
+ # Returns the data of the flag in a hash.
420
+ sig do
421
+ override
422
+ .params(
423
+ feature: T.any(Symbol, String),
424
+ ).returns(T.nilable(T::Hash[String, T.anything]))
425
+ end
214
426
  def get(feature)
215
427
  return unless exists?(feature)
216
428
 
217
429
  hash = redis.hgetall(feature.to_s)
218
430
  hash['mandatory'] = mandatory_flags.include?(feature.to_s)
219
- hash['active_for_objects'] = ::JSON.parse(hash['active_for_objects']) rescue {}
431
+ hash['active_for_objects'] = begin
432
+ ::JSON.parse(hash['active_for_objects'])
433
+ rescue StandardError
434
+ {}
435
+ end
220
436
 
221
437
  hash
222
438
  end
223
439
 
224
- def add(feature, description, active = 'false')
225
- return false if exists?(feature)
440
+ # Adds the given feature flag.
441
+ sig do
442
+ override
443
+ .params(
444
+ feature: T.any(Symbol, String),
445
+ description: String,
446
+ active: T.any(String, Symbol, T::Boolean, NilClass),
447
+ ).returns(T.nilable(T::Hash[String, T.anything]))
448
+ end
449
+ def add(feature, description = '', active = 'false')
450
+ return if exists?(feature)
226
451
 
227
452
  active = if ACTIVE_GLOBALLY.include?(active)
228
453
  'globally'
@@ -233,17 +458,25 @@ module SimpleFeatureFlags
233
458
  end
234
459
 
235
460
  hash = {
236
- 'name' => feature.to_s,
237
- 'active' => active,
238
- 'description' => description
461
+ 'name' => feature.to_s,
462
+ 'active' => active,
463
+ 'description' => description,
239
464
  }
240
465
 
241
466
  redis.hset(feature.to_s, hash)
242
467
  hash
243
468
  end
244
469
 
470
+ # Removes the given feature flag.
471
+ # Returns its data or nil if it does not exist.
472
+ sig do
473
+ override
474
+ .params(
475
+ feature: T.any(Symbol, String),
476
+ ).returns(T.nilable(T::Hash[String, T.anything]))
477
+ end
245
478
  def remove(feature)
246
- return false unless exists?(feature)
479
+ return unless exists?(feature)
247
480
 
248
481
  removed = get(feature)
249
482
  redis.del(feature.to_s)
@@ -251,10 +484,14 @@ module SimpleFeatureFlags
251
484
  removed
252
485
  end
253
486
 
487
+ # Returns the data of all feature flags.
488
+ sig do
489
+ override.returns(T::Array[T::Hash[String, T.anything]])
490
+ end
254
491
  def all
255
492
  keys = []
256
493
  hashes = []
257
- redis.scan_each(match: "*") do |key|
494
+ redis.scan_each(match: '*') do |key|
258
495
  next if keys.include?(key)
259
496
 
260
497
  keys << key
@@ -264,30 +501,12 @@ module SimpleFeatureFlags
264
501
  hashes
265
502
  end
266
503
 
504
+ sig { returns(T.nilable(Redis::Namespace)) }
267
505
  def namespaced_redis
268
- redis
269
- end
270
-
271
- private
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
506
+ r = redis
507
+ return unless r.is_a?(Redis::Namespace)
282
508
 
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
509
+ r
291
510
  end
292
511
  end
293
512
  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
- raise(FlagNotDefinedError, "Feature Flag `#{feature}` is not defined as mandatory in #{file}") unless mandatory_flags.include?(feature.to_s)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SimpleFeatureFlags
4
- VERSION = "1.2.0"
4
+ VERSION = '1.4.0'
5
5
  end
@@ -1,17 +1,28 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require 'json'
5
+ require 'sorbet-runtime'
4
6
 
5
- Dir[File.expand_path('simple_feature_flags/*.rb', __dir__)].sort.each { |file| require file }
7
+ Dir[File.expand_path('simple_feature_flags/*.rb', __dir__)].each { |file| require file }
6
8
 
9
+ # Tha main namespace of the `simple_feature_flags` gem.
7
10
  module SimpleFeatureFlags
11
+ extend T::Sig
12
+
8
13
  NOT_PRESENT = ::Object.new.freeze
9
14
  UI_GEM = 'simple_feature_flags-ui'
10
15
  UI_CLASS_NAME = '::SimpleFeatureFlags::Ui'
11
16
  WEB_UI_CLASS_NAME = '::SimpleFeatureFlags::Ui::Web'
12
17
 
13
- ACTIVE_GLOBALLY = ::Set['globally', :globally, 'true', true].freeze
14
- ACTIVE_PARTIALLY = ::Set['partially', :partially].freeze
18
+ ACTIVE_GLOBALLY = T.let(
19
+ ::Set['globally', :globally, 'true', true].freeze,
20
+ T::Set[T.any(String, Symbol, T::Boolean, NilClass)],
21
+ )
22
+ ACTIVE_PARTIALLY = T.let(
23
+ ::Set['partially', :partially].freeze,
24
+ T::Set[T.any(String, Symbol, T::Boolean, NilClass)],
25
+ )
15
26
 
16
27
  class NoSuchCommandError < StandardError; end
17
28
 
@@ -19,9 +30,15 @@ module SimpleFeatureFlags
19
30
 
20
31
  class FlagNotDefinedError < StandardError; end
21
32
 
22
- CONFIG = Configuration.new
33
+ CONFIG = T.let(Configuration.new, Configuration)
34
+
35
+ class << self
36
+ extend T::Sig
23
37
 
24
- def self.configure(&block)
25
- block.call(CONFIG)
38
+ sig { params(block: T.proc.params(arg0: Configuration).void).returns(Configuration) }
39
+ def configure(&block)
40
+ block.call(CONFIG)
41
+ CONFIG
42
+ end
26
43
  end
27
44
  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 = "simple_feature_flags"
6
+ spec.name = 'simple_feature_flags'
7
7
  spec.version = ::SimpleFeatureFlags::VERSION
8
- spec.authors = ["Espago", "Mateusz Drewniak"]
9
- spec.email = ["m.drewniak@espago.com"]
8
+ spec.authors = ['Espago', 'Mateusz Drewniak']
9
+ spec.email = ['m.drewniak@espago.com']
10
10
 
11
- spec.summary = "Simple feature flag functionality for your Ruby/Rails/Sinatra app!"
12
- spec.description = "A simple Ruby gem which lets you dynamically enable/disable parts of your code using Redis or your server's RAM!"
13
- spec.homepage = "https://github.com/espago/simple_feature_flags"
14
- spec.license = "MIT"
15
- spec.required_ruby_version = ::Gem::Requirement.new(">= 2.5.0")
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.2.0'
16
18
 
17
- spec.metadata["homepage_uri"] = spec.homepage
18
- spec.metadata["source_code_uri"] = "https://github.com/espago/simple_feature_flags"
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 = "exe"
27
+ spec.bindir = 'exe'
26
28
  spec.executables = ['simple_feature_flags']
27
- spec.require_paths = ["lib"]
29
+ spec.require_paths = ['lib']
28
30
 
29
- spec.add_development_dependency 'bundler'
30
- spec.add_development_dependency 'bundler-audit'
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