Class: Configurable::ConfigHash
- Defined in:
- lib/configurable/config_hash.rb
Overview
ConfigHash acts like a hash that maps get and set operations as specified in a Configurable’s class configurations.
class Sample
include Configurable
config :key
end
sample = Sample.new
sample.config.class # => ConfigHash
sample.key = 'value'
sample.config[:key] # => 'value'
sample.config[:key] = 'another'
sample.key # => 'another'
Non-configuration keys are sent to an underlying data store:
sample.config[:not_delegated] = 'value'
sample.config[:not_delegated] # => 'value'
sample.config.store # => {:not_delegated => 'value'}
sample.config.to_hash # => {:key => 'another', :not_delegated => 'value'}
IndifferentAccess
A ConfigHash uses the receiver class configurations to determine when and how to map get/set operations. In cases where multiple keys need to map in the same way (for example when you want indifferent access for strings and symbols), simply extend the class configurations so that the AGET ([]) method returns the correct Config in all cases.
Inconsistency
ConfigHashes can fall into an inconsistent state if you manually add values to store that would normally be mapped to the receiver. This is both easy to avoid and easy to repair.
To avoid inconsistency, don’t manually add values to the store and set import_store to true during initialization. To repair inconsistency, import the current store to self.
config_hash = Sample.new.config
config_hash[:key] = 'a'
config_hash.store[:key] = 'b'
config_hash[:key] # => 'a'
config_hash.to_hash # => {:key => 'b'}
config_hash.inconsistent? # => true
config_hash.import(config_hash.store)
config_hash[:key] # => 'b'
config_hash.to_hash # => {:key => 'b'}
config_hash.inconsistent? # => false
Instance Attribute Summary collapse
-
#receiver ⇒ Object
readonly
The bound receiver.
-
#store ⇒ Object
readonly
The underlying data store; setting values in store directly can result in an inconsistent state.
Instance Method Summary collapse
-
#==(another) ⇒ Object
Equal if the to_hash values of self and another are equal.
-
#[](key) ⇒ Object
Retrieves the value for the key, either from the receiver or the store.
-
#[]=(key, value) ⇒ Object
Stores a value for the key, either on the receiver or in the store.
-
#configs ⇒ Object
Returns receiver.class.configurations.
-
#each_pair ⇒ Object
Calls block once for each key-value pair stored in self.
-
#has_key?(key) ⇒ Boolean
True if the key is a key in configs or store.
-
#import(store) ⇒ Object
Imports stored values that can be mapped to the receiver.
-
#inconsistent? ⇒ Boolean
Returns true if the store has entries that can be stored on the receiver.
-
#initialize(receiver, store = {}, import_store = true) ⇒ ConfigHash
constructor
Initializes a new ConfigHash.
-
#inspect ⇒ Object
Returns an inspection string.
-
#keys ⇒ Object
Returns the union of configs and store keys.
-
#merge!(another) ⇒ Object
Merges another with self.
-
#to_hash(scrub = false, &block) ⇒ Object
Returns self as a hash.
Constructor Details
#initialize(receiver, store = {}, import_store = true) ⇒ ConfigHash
Initializes a new ConfigHash. Initialize normally imports values from store to ensure it doesn’t contain entries that could be stored on the receiver.
Setting import_store to false allows quick initialization but can result in an inconsistent state.
77 78 79 80 81 82 |
# File 'lib/configurable/config_hash.rb', line 77 def initialize(receiver, store={}, import_store=true) @receiver = receiver @store = store import(store) if import_store end |
Instance Attribute Details
#receiver ⇒ Object (readonly)
The bound receiver
65 66 67 |
# File 'lib/configurable/config_hash.rb', line 65 def receiver @receiver end |
#store ⇒ Object (readonly)
The underlying data store; setting values in store directly can result in an inconsistent state. Use []= instead.
69 70 71 |
# File 'lib/configurable/config_hash.rb', line 69 def store @store end |
Instance Method Details
#==(another) ⇒ Object
Equal if the to_hash values of self and another are equal.
166 167 168 |
# File 'lib/configurable/config_hash.rb', line 166 def ==(another) another.respond_to?(:to_hash) && to_hash == another.to_hash end |
#[](key) ⇒ Object
Retrieves the value for the key, either from the receiver or the store.
111 112 113 114 115 116 117 |
# File 'lib/configurable/config_hash.rb', line 111 def [](key) if config = configs[key] config.get(receiver) else store[key] end end |
#[]=(key, value) ⇒ Object
Stores a value for the key, either on the receiver or in the store.
120 121 122 123 124 125 126 |
# File 'lib/configurable/config_hash.rb', line 120 def []=(key, value) if config = configs[key] config.set(receiver, value) else store[key] = value end end |
#configs ⇒ Object
Returns receiver.class.configurations.
85 86 87 |
# File 'lib/configurable/config_hash.rb', line 85 def configs receiver.class.configurations end |
#each_pair ⇒ Object
Calls block once for each key-value pair stored in self.
155 156 157 158 159 160 161 162 163 |
# File 'lib/configurable/config_hash.rb', line 155 def each_pair # :yields: key, value configs.each_pair do |key, config| yield(key, config.get(receiver)) end store.each_pair do |key, value| yield(key, value) end end |
#has_key?(key) ⇒ Boolean
True if the key is a key in configs or store.
134 135 136 |
# File 'lib/configurable/config_hash.rb', line 134 def has_key?(key) configs[key] != nil || store.has_key?(key) end |
#import(store) ⇒ Object
Imports stored values that can be mapped to the receiver. The values are removed from store in the process. Returns self.
Primarily used to create a consistent state for self (see above).
93 94 95 96 97 98 99 100 101 |
# File 'lib/configurable/config_hash.rb', line 93 def import(store) configs = self.configs # cache as an optimization store.keys.each do |key| next unless config = configs[key] config.set(receiver, store.delete(key)) end self end |
#inconsistent? ⇒ Boolean
Returns true if the store has entries that can be stored on the receiver.
105 106 107 108 |
# File 'lib/configurable/config_hash.rb', line 105 def inconsistent? configs = self.configs # cache as an optimization store.keys.any? {|key| configs[key] } end |
#inspect ⇒ Object
Returns an inspection string.
194 195 196 |
# File 'lib/configurable/config_hash.rb', line 194 def inspect "#<#{self.class}:#{object_id} to_hash=#{to_hash.inspect}>" end |
#keys ⇒ Object
Returns the union of configs and store keys.
129 130 131 |
# File 'lib/configurable/config_hash.rb', line 129 def keys configs.keys | store.keys end |
#merge!(another) ⇒ Object
Merges another with self.
139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/configurable/config_hash.rb', line 139 def merge!(another) # cache configs and inline set as a significant optimization configs = self.configs (configs.keys | another.keys).each do |key| next unless another.has_key?(key) value = another[key] if config = configs[key] config.set(receiver, value) else store[key] = value end end end |
#to_hash(scrub = false, &block) ⇒ Object
Returns self as a hash. Any ConfigHash values are recursively hashified, to account for nesting.
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/configurable/config_hash.rb', line 172 def to_hash(scrub=false, &block) hash = {} each_pair do |key, value| if value.kind_of?(ConfigHash) value = value.to_hash(scrub, &block) end if scrub config = configs[key] next if config && config.default == value end if block_given? yield(hash, key, value) else hash[key] = value end end hash end |