Class: SimpleFeatureFlags::RamStorage

Inherits:
BaseStorage show all
Defined in:
lib/simple_feature_flags/ram_storage.rb

Overview

Stores feature flags in memory.

Direct Known Subclasses

TestRamStorage

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file) ⇒ RamStorage

: (String file) -> void



21
22
23
24
25
26
27
# File 'lib/simple_feature_flags/ram_storage.rb', line 21

def initialize(file)
  @file = file
  @mandatory_flags = []
  @flags = {}

  import_flags_from_file
end

Instance Attribute Details

#fileObject (readonly)

: String



11
12
13
# File 'lib/simple_feature_flags/ram_storage.rb', line 11

def file
  @file
end

#flagsObject (readonly)

: Hash[Symbol, Hash[String, Object]]



18
19
20
# File 'lib/simple_feature_flags/ram_storage.rb', line 18

def flags
  @flags
end

#mandatory_flagsObject (readonly)

: Array



15
16
17
# File 'lib/simple_feature_flags/ram_storage.rb', line 15

def mandatory_flags
  @mandatory_flags
end

Instance Method Details

#activate(feature) ⇒ Object Also known as: activate_globally

Activates the given flag. Returns ‘false` if it does not exist. : ((Symbol | String) feature) -> bool



202
203
204
205
206
207
208
209
# File 'lib/simple_feature_flags/ram_storage.rb', line 202

def activate(feature)
  return false unless exists?(feature)

  flag = flags[feature.to_sym] #: as !nil
  flag['active'] = 'globally'

  true
end

#activate_for(feature, *objects, object_id_method: CONFIG.default_id_method) ⇒ Object

Activates the given flag for the given objects. Returns ‘false` if it does not exist. : ((Symbol | String) feature, *Object objects, ?object_id_method: Symbol) -> void



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/simple_feature_flags/ram_storage.rb', line 252

def activate_for(feature, *objects, object_id_method: CONFIG.default_id_method)
  return false unless exists?(feature)

  to_activate_hash = objects_to_hash(objects, object_id_method: object_id_method)
  active_objects_hash = active_objects(feature)

  to_activate_hash.each do |klass, ids|
    (active_objects_hash[klass] = ids) && next unless active_objects_hash[klass]

    active_objects_hash[klass]&.concat(ids)&.uniq!&.sort! # rubocop:disable Style/SafeNavigationChainLength
  end

  flag = flags[feature.to_sym] #: as !nil
  flag['active_for_objects'] = active_objects_hash

  true
end

#activate_for!(feature, *objects, object_id_method: CONFIG.default_id_method) ⇒ Object

Activates the given flag for the given objects and sets the flag as partially active. Returns ‘false` if it does not exist. : ((Symbol | String) feature, *Object objects, ?object_id_method: Symbol) -> void



274
275
276
277
278
# File 'lib/simple_feature_flags/ram_storage.rb', line 274

def activate_for!(feature, *objects, object_id_method: CONFIG.default_id_method)
  return false unless T.unsafe(self).activate_for(feature, *objects, object_id_method: object_id_method)

  activate_partially(feature)
end

#activate_partially(feature) ⇒ Object

Activates the given flag partially. Returns ‘false` if it does not exist. : ((Symbol | String) feature) -> bool



229
230
231
232
233
234
235
236
# File 'lib/simple_feature_flags/ram_storage.rb', line 229

def activate_partially(feature)
  return false unless exists?(feature)

  flag = flags[feature.to_sym] #: as !nil
  flag['active'] = 'partially'

  true
end

#active(feature) ⇒ Object

Checks whether the flag is active. Returns ‘true`, `false`, `:globally` or `:partially` : ((Symbol | String) feature) -> (Symbol | bool)



32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/simple_feature_flags/ram_storage.rb', line 32

def active(feature)
  case flags.dig(feature.to_sym, 'active')
  when 'globally', :globally
    :globally
  when 'partially', :partially
    :partially
  when 'true', true
    true
  else
    false
  end
end

#active?(feature) ⇒ Boolean

Checks whether the flag is active. : ((Symbol | String) feature) -> bool

Returns:

  • (Boolean)


48
49
50
51
52
# File 'lib/simple_feature_flags/ram_storage.rb', line 48

def active?(feature)
  return true if active(feature)

  false
end

#active_for?(feature, object, object_id_method: CONFIG.default_id_method) ⇒ Boolean

Checks whether the flag is active for the given object. : ((Symbol | String) feature, Object object, ?object_id_method: Symbol) -> bool

Returns:

  • (Boolean)


92
93
94
95
96
97
98
99
100
101
102
# File 'lib/simple_feature_flags/ram_storage.rb', line 92

def active_for?(feature, object, object_id_method: CONFIG.default_id_method)
  return false unless active?(feature)
  return true if active_globally?(feature)

  active_objects_hash = active_objects(feature)
  active_ids = active_objects_hash[object.class.to_s]

  return false unless active_ids

  active_ids.include? object.public_send(object_id_method)
end

#active_globally?(feature) ⇒ Boolean

Checks whether the flag is active globally, for every object. : ((Symbol | String) feature) -> bool

Returns:

  • (Boolean)


64
65
66
# File 'lib/simple_feature_flags/ram_storage.rb', line 64

def active_globally?(feature)
  ACTIVE_GLOBALLY.include? T.unsafe(flags.dig(feature.to_sym, 'active'))
end

#active_objects(feature) ⇒ Object

Returns a hash of Objects that the given flag is turned on for. The keys are class/model names, values are arrays of IDs of instances/records.

looks like this:

{ "Page" => [25, 89], "Book" => [152] }

: ((Symbol | String) feature) -> Hash[String, Array]



329
330
331
# File 'lib/simple_feature_flags/ram_storage.rb', line 329

def active_objects(feature)
  T.unsafe(flags.dig(feature.to_sym, 'active_for_objects')) || {}
end

#active_partially?(feature) ⇒ Boolean

Checks whether the flag is active partially, only for certain objects. : ((Symbol | String) feature) -> bool

Returns:

  • (Boolean)


78
79
80
# File 'lib/simple_feature_flags/ram_storage.rb', line 78

def active_partially?(feature)
  ACTIVE_PARTIALLY.include? T.unsafe(flags.dig(feature.to_sym, 'active'))
end

#add(feature, description = '', active = 'false') ⇒ Object

Adds the given feature flag. : ((Symbol | String) feature, ?String description, ?(String | Symbol | bool)? active) -> Hash[String, top]?



371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/simple_feature_flags/ram_storage.rb', line 371

def add(feature, description = '', active = 'false')
  return if exists?(feature)

  active = if ACTIVE_GLOBALLY.include?(active)
             'globally'
           elsif ACTIVE_PARTIALLY.include?(active)
             'partially'
           else
             'false'
           end

  hash = {
    'name'        => feature.to_s,
    'active'      => active,
    'description' => description,
  }

  flags[feature.to_sym] = hash
end

#allObject

Returns the data of all feature flags. : -> Array[Hash[String, top]]



407
408
409
410
411
412
413
414
415
# File 'lib/simple_feature_flags/ram_storage.rb', line 407

def all
  hashes = []

  flags.each_key do |key|
    hashes << get(key)
  end

  hashes
end

#deactivate(feature) ⇒ Object

Deactivates the given flag globally. Does not reset the list of objects that this flag has been turned on for. Returns ‘false` if it does not exist. : ((Symbol | String) feature) -> bool



300
301
302
303
304
305
306
307
# File 'lib/simple_feature_flags/ram_storage.rb', line 300

def deactivate(feature)
  return false unless exists?(feature)

  flag = flags[feature.to_sym] #: as !nil
  flag['active'] = 'false'

  true
end

#deactivate!(feature) ⇒ Object

Deactivates the given flag for all objects. Resets the list of objects that this flag has been turned on for. Returns ‘false` if it does not exist. : ((Symbol | String) feature) -> bool



285
286
287
288
289
290
291
292
293
# File 'lib/simple_feature_flags/ram_storage.rb', line 285

def deactivate!(feature)
  return false unless exists?(feature)

  flag = flags[feature.to_sym] #: as !nil
  flag['active'] = 'false'
  flag['active_for_objects'] = nil

  true
end

#deactivate_for(feature, *objects, object_id_method: CONFIG.default_id_method) ⇒ Object

Deactivates the given flag for the given objects. Returns ‘false` if it does not exist. : ((Symbol | String) feature, *Object objects, ?object_id_method: Symbol) -> void



336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/simple_feature_flags/ram_storage.rb', line 336

def deactivate_for(feature, *objects, object_id_method: CONFIG.default_id_method)
  return false unless exists?(feature)

  active_objects_hash = active_objects(feature)

  objects_to_deactivate_hash = objects_to_hash(objects, object_id_method: object_id_method)

  objects_to_deactivate_hash.each do |klass, ids_to_remove|
    active_ids = active_objects_hash[klass]
    next unless active_ids

    active_ids.reject! { |id| ids_to_remove.include? id }
  end

  flag = flags[feature.to_sym] #: as !nil
  flag['active_for_objects'] = active_objects_hash

  true
end

#description(feature) ⇒ Object

Returns the description of the flag if it exists. : ((Symbol | String) feature) -> String?



123
124
125
# File 'lib/simple_feature_flags/ram_storage.rb', line 123

def description(feature)
  flags.dig(feature.to_sym, 'description') #: as untyped
end

#do_activate(feature, &block) ⇒ Object Also known as: do_activate_globally

: [R] ((Symbol | String) feature) { -> R } -> R



215
216
217
218
219
220
221
222
# File 'lib/simple_feature_flags/ram_storage.rb', line 215

def do_activate(feature, &block)
  feature = feature.to_sym
  prev_value = flags.dig(feature, 'active')
  activate(feature)
  block.call
ensure
  T.unsafe(flags)[feature]['active'] = prev_value
end

#do_activate_partially(feature, &block) ⇒ Object

: [R] ((Symbol | String) feature) { -> R } -> R



240
241
242
243
244
245
246
247
# File 'lib/simple_feature_flags/ram_storage.rb', line 240

def do_activate_partially(feature, &block)
  feature = feature.to_sym
  prev_value = flags.dig(feature, 'active')
  activate_partially(feature)
  block.call
ensure
  T.unsafe(flags)[feature]['active'] = prev_value
end

#do_deactivate(feature, &block) ⇒ Object

: [R] ((Symbol | String) feature) { -> R } -> R



311
312
313
314
315
316
317
318
# File 'lib/simple_feature_flags/ram_storage.rb', line 311

def do_deactivate(feature, &block)
  feature = feature.to_sym
  prev_value = flags.dig(feature, 'active')
  deactivate(feature)
  block.call
ensure
  T.unsafe(flags)[feature]['active'] = prev_value
end

#exists?(feature) ⇒ Boolean

Checks whether the flag exists. : ((Symbol | String) feature) -> bool

Returns:

  • (Boolean)


114
115
116
117
118
# File 'lib/simple_feature_flags/ram_storage.rb', line 114

def exists?(feature)
  return false if [nil, ''].include? flags[feature.to_sym]

  true
end

#get(feature) ⇒ Object

Returns the data of the flag in a hash. : ((Symbol | String) feature) -> Hash[String, top]?



359
360
361
362
363
364
365
366
# File 'lib/simple_feature_flags/ram_storage.rb', line 359

def get(feature)
  return unless exists?(feature)

  flag = flags[feature.to_sym] #: as !nil
  flag['mandatory'] = mandatory_flags.include?(feature.to_s)

  flag
end

#inactive?(feature) ⇒ Boolean

Checks whether the flag is inactive. : ((Symbol | String) feature) -> bool

Returns:

  • (Boolean)


57
58
59
# File 'lib/simple_feature_flags/ram_storage.rb', line 57

def inactive?(feature)
  !active?(feature)
end

#inactive_for?(feature, object, object_id_method: CONFIG.default_id_method) ⇒ Boolean

Checks whether the flag is inactive for the given object. : ((Symbol | String) feature, Object object, ?object_id_method: Symbol) -> bool

Returns:

  • (Boolean)


107
108
109
# File 'lib/simple_feature_flags/ram_storage.rb', line 107

def inactive_for?(feature, object, object_id_method: CONFIG.default_id_method)
  !active_for?(feature, object, object_id_method: object_id_method)
end

#inactive_globally?(feature) ⇒ Boolean

Checks whether the flag is inactive globally, for every object. : ((Symbol | String) feature) -> bool

Returns:

  • (Boolean)


71
72
73
# File 'lib/simple_feature_flags/ram_storage.rb', line 71

def inactive_globally?(feature)
  !active_globally?(feature)
end

#inactive_partially?(feature) ⇒ Boolean

Checks whether the flag is inactive partially, only for certain objects. : ((Symbol | String) feature) -> bool

Returns:

  • (Boolean)


85
86
87
# File 'lib/simple_feature_flags/ram_storage.rb', line 85

def inactive_partially?(feature)
  !active_partially?(feature)
end

#remove(feature) ⇒ Object

Removes the given feature flag. Returns its data or nil if it does not exist. : ((Symbol | String) feature) -> Hash[String, top]?



395
396
397
398
399
400
401
402
# File 'lib/simple_feature_flags/ram_storage.rb', line 395

def remove(feature)
  return unless exists?(feature)

  removed = get(feature)
  flags.delete(feature.to_sym)

  removed
end

#when_active(feature, &block) ⇒ Object

Calls the given block if the flag is active. : ((Symbol | String) feature) { -> void } -> void



130
131
132
133
134
# File 'lib/simple_feature_flags/ram_storage.rb', line 130

def when_active(feature, &block)
  return unless active?(feature)

  block.call
end

#when_active_for(feature, object, object_id_method: CONFIG.default_id_method, &block) ⇒ Object

Calls the given block if the flag is active for the given object. : ((Symbol | String) feature, Object object, ?object_id_method: Symbol) { -> void } -> void



184
185
186
187
188
# File 'lib/simple_feature_flags/ram_storage.rb', line 184

def when_active_for(feature, object, object_id_method: CONFIG.default_id_method, &block)
  return unless active_for?(feature, object, object_id_method: object_id_method)

  block.call
end

#when_active_globally(feature, &block) ⇒ Object

Calls the given block if the flag is active globally. : ((Symbol | String) feature) { -> void } -> void



148
149
150
151
152
# File 'lib/simple_feature_flags/ram_storage.rb', line 148

def when_active_globally(feature, &block)
  return unless active_globally?(feature)

  block.call
end

#when_active_partially(feature, &block) ⇒ Object

Calls the given block if the flag is active partially. : ((Symbol | String) feature) { -> void } -> void



166
167
168
169
170
# File 'lib/simple_feature_flags/ram_storage.rb', line 166

def when_active_partially(feature, &block)
  return unless active_partially?(feature)

  block.call
end

#when_inactive(feature, &block) ⇒ Object

Calls the given block if the flag is inactive. : ((Symbol | String) feature) { -> void } -> void



139
140
141
142
143
# File 'lib/simple_feature_flags/ram_storage.rb', line 139

def when_inactive(feature, &block)
  return unless inactive?(feature)

  block.call
end

#when_inactive_for(feature, object, object_id_method: CONFIG.default_id_method, &block) ⇒ Object

Calls the given block if the flag is inactive for the given object. : ((Symbol | String) feature, Object object, ?object_id_method: Symbol) { -> void } -> void



193
194
195
196
197
# File 'lib/simple_feature_flags/ram_storage.rb', line 193

def when_inactive_for(feature, object, object_id_method: CONFIG.default_id_method, &block)
  return unless inactive_for?(feature, object, object_id_method: object_id_method)

  block.call
end

#when_inactive_globally(feature, &block) ⇒ Object

Calls the given block if the flag is inactive globally. : ((Symbol | String) feature) { -> void } -> void



157
158
159
160
161
# File 'lib/simple_feature_flags/ram_storage.rb', line 157

def when_inactive_globally(feature, &block)
  return unless inactive_globally?(feature)

  block.call
end

#when_inactive_partially(feature, &block) ⇒ Object

Calls the given block if the flag is inactive partially. : ((Symbol | String) feature) { -> void } -> void



175
176
177
178
179
# File 'lib/simple_feature_flags/ram_storage.rb', line 175

def when_inactive_partially(feature, &block)
  return unless inactive_partially?(feature)

  block.call
end