1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
require 'concurrent/atomic/read_write_lock'
module Flipper
module Adapters
# Public: Adapter for storing everything in memory.
# Useful for tests/specs.
class Memory
include ::Flipper::Adapter
FeaturesKey = :features
# Public: The name of the adapter.
attr_reader :name
# Public
def initialize(source = nil)
@source = Hash.new.update(source || {})
@name = :memory
@lock = Concurrent::ReadWriteLock.new
end
# Public: The set of known features.
def features
@lock.with_read_lock { @source.keys }.to_set
end
# Public: Adds a feature to the set of known features.
def add(feature)
@lock.with_write_lock { @source[feature.key] ||= default_config }
true
end
# Public: Removes a feature from the set of known features and clears
# all the values for the feature.
def remove(feature)
@lock.with_write_lock { @source.delete(feature.key) }
true
end
# Public: Clears all the gate values for a feature.
def clear(feature)
@lock.with_write_lock { @source[feature.key] = default_config }
true
end
# Public
def get(feature)
@lock.with_read_lock { @source[feature.key] } || default_config
end
def get_multi(features)
@lock.with_read_lock do
result = {}
features.each do |feature|
result[feature.key] = @source[feature.key] || default_config
end
result
end
end
def get_all
@lock.with_read_lock { @source.to_h }
end
# Public
def enable(feature, gate, thing)
@lock.with_write_lock do
@source[feature.key] ||= default_config
case gate.data_type
when :boolean
@source[feature.key] = default_config
@source[feature.key][gate.key] = thing.value.to_s
when :integer
@source[feature.key][gate.key] = thing.value.to_s
when :set
@source[feature.key][gate.key] << thing.value.to_s
else
raise "#{gate} is not supported by this adapter yet"
end
true
end
end
# Public
def disable(feature, gate, thing)
@lock.with_write_lock do
@source[feature.key] ||= default_config
case gate.data_type
when :boolean
@source[feature.key] = default_config
when :integer
@source[feature.key][gate.key] = thing.value.to_s
when :set
@source[feature.key][gate.key].delete thing.value.to_s
else
raise "#{gate} is not supported by this adapter yet"
end
true
end
end
# Public
def inspect
attributes = [
'name=:memory',
"source=#{@source.inspect}",
]
"#<#{self.class.name}:#{object_id} #{attributes.join(', ')}>"
end
# Public: a more efficient implementation of import for this adapter
def import(source_adapter)
get_all = source_adapter.get_all
@lock.with_write_lock { @source.replace(get_all) }
end
end
end
end
|