configurable 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,226 +0,0 @@
1
- require 'configurable/delegate'
2
-
3
- module Configurable
4
-
5
- # DelegateHash delegates get and set operations to instance methods on a receiver.
6
- #
7
- # class Sample
8
- # attr_accessor :key
9
- # end
10
- # sample = Sample.new
11
- #
12
- # dhash = DelegateHash.new
13
- # dhash.delegates[:key] = Delegate.new(:key)
14
- # dhash.bind(sample)
15
- #
16
- # sample.key = 'value'
17
- # dhash[:key] # => 'value'
18
- #
19
- # dhash[:key] = 'another'
20
- # sample.key # => 'another'
21
- #
22
- # Non-delegate keys are sent to an underlying data store:
23
- #
24
- # dhash[:not_delegated] = 'value'
25
- # dhash[:not_delegated] # => 'value'
26
- #
27
- # dhash.store # => {:not_delegated => 'value'}
28
- # dhash.to_hash # => {:key => 'another', :not_delegated => 'value'}
29
- #
30
- # ==== IndifferentAccess
31
- #
32
- # The delegates hash maps keys to Delegate objects. In cases where multiple
33
- # keys need to map to the same delegate (for example when you want indifferent
34
- # access for strings and symbols), simply extend the delegate hash so that the
35
- # AGET ([]) method returns the correct delegate in all cases.
36
- #
37
- class DelegateHash
38
-
39
- # The bound receiver
40
- attr_reader :receiver
41
-
42
- # The underlying data store
43
- attr_reader :store
44
-
45
- # A hash of (key, Delegate) pairs identifying which
46
- # keys to delegate to the receiver
47
- attr_reader :delegates
48
-
49
- # Initializes a new DelegateHash. Note that initialize simply sets the
50
- # receiver, it does NOT map stored values the same way bind does. This
51
- # allows quick, implicit binding when the store is set up beforehand.
52
- #
53
- # For more standard binding use: DelegateHash.new.bind(receiver)
54
- def initialize(delegates={}, store={}, receiver=nil)
55
- @store = store
56
- @delegates = delegates
57
- @receiver = receiver
58
- end
59
-
60
- # Binds self to the specified receiver. Delegate values are removed from
61
- # store and sent to their writer on receiver. If the store has no value
62
- # for a delegate key, the delegate default value will be used.
63
- def bind(receiver, rebind=false)
64
- raise ArgumentError, "receiver cannot be nil" if receiver == nil
65
-
66
- if bound? && !rebind
67
- if @receiver == receiver
68
- return(self)
69
- else
70
- raise ArgumentError, "already bound to: #{@receiver}"
71
- end
72
- end
73
-
74
- @receiver = receiver
75
- map(store)
76
- self
77
- end
78
-
79
- # Returns true if self is bound to a receiver
80
- def bound?
81
- receiver != nil
82
- end
83
-
84
- # Unbinds self from the specified receiver. Delegate values
85
- # are stored in store. Returns the unbound receiver.
86
- def unbind
87
- unmap(store)
88
- @receiver = nil
89
- self
90
- end
91
-
92
- # Retrieves the value corresponding to the key. When bound, delegates pull
93
- # values from the receiver using the delegate.reader method; otherwise the
94
- # value in store will be returned. When unbound, if the store has no value
95
- # for a delegate, the delgate default value will be returned.
96
- def [](key)
97
- return store[key] unless delegate = delegates[key]
98
-
99
- case
100
- when bound?
101
- receiver.send(delegate.reader)
102
- when store.has_key?(key)
103
- store[key]
104
- else
105
- store[key] = delegate.default
106
- end
107
- end
108
-
109
- # Stores a value for the key. When bound, delegates set the value in the
110
- # receiver using the delegate.writer method; otherwise values are stored in
111
- # store.
112
- def []=(key, value)
113
- if bound? && delegate = delegates[key]
114
- receiver.send(delegate.writer, value)
115
- else
116
- store[key] = value
117
- end
118
- end
119
-
120
- # Returns the union of delegate and store keys.
121
- def keys
122
- delegates.keys | store.keys
123
- end
124
-
125
- # True if the key is an assigned delegate or store key.
126
- def has_key?(key)
127
- delegates.has_key?(key) || store.has_key?(key)
128
- end
129
-
130
- # Merges another with self.
131
- def merge!(another)
132
- if bound?
133
- (delegates.keys | another.keys).each do |key|
134
- self[key] = another[key] if another.has_key?(key)
135
- end
136
- else
137
- # optimization for the common case of an
138
- # unbound merge of another hash
139
- store.merge!(another.to_hash)
140
- end
141
- end
142
-
143
- # Calls block once for each key-value pair stored in self.
144
- def each_pair # :yields: key, value
145
- keys.each {|key| yield(key, self[key]) }
146
- end
147
-
148
- # Equal if the to_hash values of self and another are equal.
149
- def ==(another)
150
- another.respond_to?(:to_hash) && to_hash == another.to_hash
151
- end
152
-
153
- # Returns self as a hash. Any DelegateHash values are recursively
154
- # hashified, to account for nesting.
155
- def to_hash(&block)
156
- hash = {}
157
- each_pair do |key, value|
158
- if value.kind_of?(DelegateHash)
159
- value = value.to_hash(&block)
160
- end
161
-
162
- if block_given?
163
- yield(hash, key, value)
164
- else
165
- hash[key] = value
166
- end
167
- end
168
- hash
169
- end
170
-
171
- # Overrides default inspect to show the to_hash values.
172
- def inspect
173
- "#<#{self.class}:#{object_id} to_hash=#{to_hash.inspect}>"
174
- end
175
-
176
- # Ensures duplicates are unbound and store the same values as the original.
177
- def initialize_copy(orig)
178
- super
179
-
180
- @receiver = nil
181
- @store = @store.dup
182
- orig.unmap(@store) if orig.bound?
183
- end
184
-
185
- protected
186
-
187
- # helper to map delegate values from source to the receiver
188
- def map(source) # :nodoc:
189
- source_values = {}
190
- source.each_key do |key|
191
- if delegate = delegates[key]
192
- if source_values.has_key?(delegate)
193
- key = delegates.keys.find {|k| delegates[k] == delegate }
194
- raise "multiple values mapped to #{key.inspect}"
195
- end
196
-
197
- source_values[delegate] = source.delete(key)
198
- end
199
- end
200
-
201
- delegates.each_pair do |key, delegate|
202
- # map the value; if no value is set in the source then use the
203
- # delegate default. if map_default is false, then simply skip...
204
- # this ensures each config is initialized to a value when bound
205
- # UNLESS map_default is set (indicating manual initialization)
206
- value = case
207
- when source_values.has_key?(delegate)
208
- source_values[delegate]
209
- when delegate[:set_default, true]
210
- delegate.default
211
- else
212
- next
213
- end
214
-
215
- receiver.send(delegate.writer, value)
216
- end
217
- end
218
-
219
- # helper to unmap delegates from the receiver to a target hash
220
- def unmap(target) # :nodoc:
221
- delegates.each_pair do |key, delegate|
222
- target[key] = receiver.send(delegate.reader)
223
- end
224
- end
225
- end
226
- end