configurable 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History +19 -0
- data/MIT-LICENSE +17 -15
- data/README +112 -40
- data/lib/config_parser.rb +159 -96
- data/lib/config_parser/option.rb +10 -3
- data/lib/config_parser/switch.rb +1 -1
- data/lib/config_parser/utils.rb +52 -18
- data/lib/configurable.rb +128 -36
- data/lib/configurable/class_methods.rb +171 -192
- data/lib/configurable/config.rb +97 -0
- data/lib/configurable/config_hash.rb +198 -0
- data/lib/configurable/indifferent_access.rb +1 -1
- data/lib/configurable/module_methods.rb +7 -17
- data/lib/configurable/nest_config.rb +78 -0
- data/lib/configurable/ordered_hash_patch.rb +85 -0
- data/lib/configurable/utils.rb +25 -32
- data/lib/configurable/validation.rb +69 -31
- data/lib/configurable/version.rb +7 -0
- metadata +13 -8
- data/lib/configurable/delegate.rb +0 -103
- data/lib/configurable/delegate_hash.rb +0 -226
@@ -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
|