Class: Configurable::DelegateHash
- Defined in:
- lib/configurable/delegate_hash.rb
Overview
DelegateHash delegates get and set operations to instance methods on a receiver.
class Sample
attr_accessor :key
end
sample = Sample.new
dhash = DelegateHash.new
dhash.delegates[:key] = Delegate.new(:key)
dhash.bind(sample)
sample.key = 'value'
dhash[:key] # => 'value'
dhash[:key] = 'another'
sample.key # => 'another'
Non-delegate keys are sent to an underlying data store:
dhash[:not_delegated] = 'value'
dhash[:not_delegated] # => 'value'
dhash.store # => {:not_delegated => 'value'}
dhash.to_hash # => {:key => 'another', :not_delegated => 'value'}
IndifferentAccess
The delegates hash maps keys to Delegate objects. In cases where multiple keys need to map to the same delegate (for example when you want indifferent access for strings and symbols), simply extend the delegate hash so that the AGET ([]) method returns the correct delegate in all cases.
Instance Attribute Summary collapse
-
#delegates ⇒ Object
readonly
A hash of (key, Delegate) pairs identifying which keys to delegate to the receiver.
-
#receiver ⇒ Object
readonly
The bound receiver.
-
#store ⇒ Object
readonly
The underlying data store.
Instance Method Summary collapse
-
#==(another) ⇒ Object
Equal if the to_hash values of self and another are equal.
-
#[](key) ⇒ Object
Retrieves the value corresponding to the key.
-
#[]=(key, value) ⇒ Object
Stores a value for the key.
-
#bind(receiver, rebind = false) ⇒ Object
Binds self to the specified receiver.
-
#bound? ⇒ Boolean
Returns true if self is bound to a receiver.
-
#each_pair ⇒ Object
Calls block once for each key-value pair stored in self.
-
#has_key?(key) ⇒ Boolean
True if the key is an assigned delegate or store key.
-
#initialize(delegates = {}, store = {}, receiver = nil) ⇒ DelegateHash
constructor
Initializes a new DelegateHash.
-
#initialize_copy(orig) ⇒ Object
Ensures duplicates are unbound and store the same values as the original.
-
#inspect ⇒ Object
Overrides default inspect to show the to_hash values.
-
#keys ⇒ Object
Returns the union of delegate and store keys.
-
#merge!(another) ⇒ Object
Merges another with self.
-
#to_hash(&block) ⇒ Object
Returns self as a hash.
-
#unbind ⇒ Object
Unbinds self from the specified receiver.
Constructor Details
#initialize(delegates = {}, store = {}, receiver = nil) ⇒ DelegateHash
Initializes a new DelegateHash. Note that initialize simply sets the receiver, it does NOT map stored values the same way bind does. This allows quick, implicit binding when the store is set up beforehand.
For more standard binding use: DelegateHash.new.bind(receiver)
54 55 56 57 58 |
# File 'lib/configurable/delegate_hash.rb', line 54 def initialize(delegates={}, store={}, receiver=nil) @store = store @delegates = delegates @receiver = receiver end |
Instance Attribute Details
#delegates ⇒ Object (readonly)
A hash of (key, Delegate) pairs identifying which keys to delegate to the receiver
47 48 49 |
# File 'lib/configurable/delegate_hash.rb', line 47 def delegates @delegates end |
#receiver ⇒ Object (readonly)
The bound receiver
40 41 42 |
# File 'lib/configurable/delegate_hash.rb', line 40 def receiver @receiver end |
#store ⇒ Object (readonly)
The underlying data store
43 44 45 |
# File 'lib/configurable/delegate_hash.rb', line 43 def store @store end |
Instance Method Details
#==(another) ⇒ Object
Equal if the to_hash values of self and another are equal.
149 150 151 |
# File 'lib/configurable/delegate_hash.rb', line 149 def ==(another) another.respond_to?(:to_hash) && to_hash == another.to_hash end |
#[](key) ⇒ Object
Retrieves the value corresponding to the key. When bound, delegates pull values from the receiver using the delegate.reader method; otherwise the value in store will be returned. When unbound, if the store has no value for a delegate, the delgate default value will be returned.
96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/configurable/delegate_hash.rb', line 96 def [](key) return store[key] unless delegate = delegates[key] case when bound? receiver.send(delegate.reader) when store.has_key?(key) store[key] else store[key] = delegate.default end end |
#[]=(key, value) ⇒ Object
Stores a value for the key. When bound, delegates set the value in the receiver using the delegate.writer method; otherwise values are stored in store.
112 113 114 115 116 117 118 |
# File 'lib/configurable/delegate_hash.rb', line 112 def []=(key, value) if bound? && delegate = delegates[key] receiver.send(delegate.writer, value) else store[key] = value end end |
#bind(receiver, rebind = false) ⇒ Object
Binds self to the specified receiver. Delegate values are removed from store and sent to their writer on receiver. If the store has no value for a delegate key, the delegate default value will be used.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/configurable/delegate_hash.rb', line 63 def bind(receiver, rebind=false) raise ArgumentError, "receiver cannot be nil" if receiver == nil if bound? && !rebind if @receiver == receiver return(self) else raise ArgumentError, "already bound to: #{@receiver}" end end @receiver = receiver map(store) self end |
#bound? ⇒ Boolean
Returns true if self is bound to a receiver
80 81 82 |
# File 'lib/configurable/delegate_hash.rb', line 80 def bound? receiver != nil end |
#each_pair ⇒ Object
Calls block once for each key-value pair stored in self.
144 145 146 |
# File 'lib/configurable/delegate_hash.rb', line 144 def each_pair # :yields: key, value keys.each {|key| yield(key, self[key]) } end |
#has_key?(key) ⇒ Boolean
True if the key is an assigned delegate or store key.
126 127 128 |
# File 'lib/configurable/delegate_hash.rb', line 126 def has_key?(key) delegates.has_key?(key) || store.has_key?(key) end |
#initialize_copy(orig) ⇒ Object
Ensures duplicates are unbound and store the same values as the original.
177 178 179 180 181 182 183 |
# File 'lib/configurable/delegate_hash.rb', line 177 def initialize_copy(orig) super @receiver = nil @store = @store.dup orig.unmap(@store) if orig.bound? end |
#inspect ⇒ Object
Overrides default inspect to show the to_hash values.
172 173 174 |
# File 'lib/configurable/delegate_hash.rb', line 172 def inspect "#<#{self.class}:#{object_id} to_hash=#{to_hash.inspect}>" end |
#keys ⇒ Object
Returns the union of delegate and store keys.
121 122 123 |
# File 'lib/configurable/delegate_hash.rb', line 121 def keys delegates.keys | store.keys end |
#merge!(another) ⇒ Object
Merges another with self.
131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/configurable/delegate_hash.rb', line 131 def merge!(another) if bound? (delegates.keys | another.keys).each do |key| self[key] = another[key] if another.has_key?(key) end else # optimization for the common case of an # unbound merge of another hash store.merge!(another.to_hash) end end |
#to_hash(&block) ⇒ Object
Returns self as a hash. Any DelegateHash values are recursively hashified, to account for nesting.
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/configurable/delegate_hash.rb', line 155 def to_hash(&block) hash = {} each_pair do |key, value| if value.kind_of?(DelegateHash) value = value.to_hash(&block) end if block_given? yield(hash, key, value) else hash[key] = value end end hash end |
#unbind ⇒ Object
Unbinds self from the specified receiver. Delegate values are stored in store. Returns the unbound receiver.
86 87 88 89 90 |
# File 'lib/configurable/delegate_hash.rb', line 86 def unbind unmap(store) @receiver = nil self end |