cascading-configuration-hash 1.1.4 → 1.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,64 +1,343 @@
1
1
  # Cascading Configuration #
2
2
 
3
- http://rubygems.org/gems/cascading-configuration
3
+ http://rubygems.org/gems/cascading-configuration-hash
4
4
 
5
5
  # Description #
6
6
 
7
- Adds methods for cascading configurations.
7
+ Adds methods for cascading configuration hashes. Support package for cascading-configuration.
8
8
 
9
9
  # Summary #
10
10
 
11
- Cascading configuration methods for single settings, arrays, hashes.
12
-
13
- ## :attr_configuration ##
11
+ ## :attr_configuration_hash ##
14
12
 
15
- :attr_configuration provides inheritable configuration that cascades downward.
13
+ :attr_configuration_hash provides inheritable configuration that cascades downward.
16
14
 
17
15
  Configuration inheritance can cascade through modules, classes, and instances.
18
16
 
19
- :attr_configuration defines a single attribute accessor that searches upward for the first ancestor defining the configuration.
17
+ :attr_configuration_hash defines a single attribute accessor that composes the set of configuration values appropriate to the ancestor level being queried (merging downward from most distant ancestor to self). An internal cache is kept, and any configuration updates that occur to higher-level ancestors cascade immediately downward.
20
18
 
21
- ## :attr_configuration_array ##
19
+ # Install #
22
20
 
23
- :attr_configuration_array provides inheritable configuration that cascades downward.
21
+ * sudo gem install cascading-configuration-hash
24
22
 
25
- Configuration inheritance can cascade through modules, classes, and instances.
23
+ # Usage #
26
24
 
27
- :attr_configuration_array defines a single attribute accessor that composes the set of configuration values appropriate to the ancestor level being queried (merging downward from most distant ancestor to self). An internal cache is kept, and any configuration updates that occur to higher-level ancestors cascade immediately downward.
25
+ ## First Module ##
28
26
 
29
- The array maintained by :attr_configuration_array is kept ordered and unique.
27
+ 1. Define initial configuration in a module.
30
28
 
31
- ## :attr_configuration_hash ##
29
+ A class works just as well, but we can't use a module in the same chain if we start with a class.
32
30
 
33
- :attr_configuration_hash provides inheritable configuration that cascades downward.
31
+ * Include module to enable attr_configuration_hash.
34
32
 
35
- Configuration inheritance can cascade through modules, classes, and instances.
33
+ ```ruby
36
34
 
37
- :attr_configuration_hash defines a single attribute accessor that composes the set of configuration values appropriate to the ancestor level being queried (merging downward from most distant ancestor to self). An internal cache is kept, and any configuration updates that occur to higher-level ancestors cascade immediately downward.
35
+ module CascadingConfiguration::MockModule
36
+ include CascadingConfiguration::Hash
37
+ end
38
38
 
39
- # Install #
39
+ ```
40
40
 
41
- * sudo gem install cascading-configuration
41
+ * Declare attr_configuration_hash.
42
42
 
43
- # Usage #
43
+ ```ruby
44
+
45
+ module CascadingConfiguration::MockModule
46
+ attr_configuration_hash :some_hash_configuration
47
+ end
48
+
49
+ ```
50
+
51
+ * Set initial value.
52
+
53
+ ```ruby
54
+
55
+ module CascadingConfiguration::MockModule
56
+ self.some_hash_configuration = { :some_value => :some_value }
57
+ end
58
+
59
+ ```
60
+
61
+ * Verify initial configuration value
62
+
63
+ ```ruby
64
+
65
+ module CascadingConfiguration::MockModule
66
+ # => some_hash_configuration.should == { :some_value => :some_value }
67
+ end
68
+
69
+ ```
70
+
71
+ ## Including Module 1 ##
72
+
73
+ 2. Include initial module in another module.
74
+
75
+ Including the module that has included a CascadingConfiguration module is the same as including a CascadingConfiguration module.
76
+
77
+ ```ruby
78
+
79
+ module CascadingConfiguration::MockModule2
80
+ include CascadingConfiguration::MockModule
81
+ end
82
+
83
+ ```
84
+
85
+ * Verify inherited value
86
+
87
+ ```ruby
88
+
89
+ module CascadingConfiguration::MockModule2
90
+ # => some_hash_configuration.should == { :some_value => :some_value }
91
+ end
92
+
93
+ ```
94
+
95
+ * Override inherited value
96
+
97
+ ```ruby
98
+
99
+ module CascadingConfiguration::MockModule2
100
+ self.some_hash_configuration = { :module_value => :some_value }
101
+ end
102
+
103
+ ```
104
+
105
+ * Verify local override value
106
+
107
+ ```ruby
108
+
109
+ module CascadingConfiguration::MockModule2
110
+ # => some_hash_configuration.should == { :module_value => :some_value }
111
+ end
44
112
 
45
- Including CascadingConfiguration includes:
113
+ ```
46
114
 
47
- * CascadingConfiguration::Setting
48
- * CascadingConfiguration::Array
49
- * CascadingConfiguration::Hash
115
+ ## Including Module 2 ##
116
+
117
+ 3. Include second module in another module.
50
118
 
51
119
  ```ruby
52
- module AnyModuleOrClass
53
- include CascadingConfiguration
120
+
121
+ module CascadingConfiguration::MockModule3
122
+ include CascadingConfiguration::MockModule2
54
123
  end
124
+
55
125
  ```
56
126
 
57
- See supporting package README files for examples in each case:
127
+ * Verify inherited value
128
+
129
+ ```ruby
130
+
131
+ module CascadingConfiguration::MockModule3
132
+ # => some_array_configuration.should == { :module_value => :some_value }
133
+ end
134
+
135
+ ```
136
+
137
+ ## Top Class ##
138
+
139
+ 4. Include third module in a class.
140
+
141
+ ```ruby
142
+
143
+ class CascadingConfiguration::MockClass
144
+ include CascadingConfiguration::MockModule3
145
+ end
146
+
147
+ ```
148
+
149
+ * Verify inherited value
150
+
151
+ ```ruby
152
+
153
+ class CascadingConfiguration::MockClass
154
+ # => some_hash_configuration.should == { :module_value => :some_value }
155
+ end
156
+
157
+ ```
158
+
159
+ * Override inherited value
160
+
161
+ ```ruby
162
+
163
+ class CascadingConfiguration::MockClass
164
+ self.some_hash_configuration = { :another_value => :some_value }
165
+ end
166
+
167
+ ```
168
+
169
+ * Verify local override value
170
+
171
+ ```ruby
172
+
173
+ class CascadingConfiguration::MockClass
174
+ # => some_hash_configuration.should == { :another_value => :some_value }
175
+ end
176
+
177
+ ```
178
+
179
+ ## Instance of Top Class ##
180
+
181
+ 5. Instantiate class.
182
+
183
+ ```ruby
58
184
 
59
- * attr_configuration
60
- * attr_configuration_array
61
- * attr_configuration_hash
185
+ object_instance_one = CascadingConfiguration::MockClass.new
186
+
187
+ ```
188
+
189
+ * Verify inherited value
190
+
191
+ ```ruby
192
+
193
+ # => object_instance_one.some_hash_configuration.should == { :another_value => :some_value }
194
+
195
+ ```
196
+
197
+ * Override inherited value
198
+
199
+ ```ruby
200
+
201
+ object_instance_one.some_hash_configuration = { :yet_another_value => :some_value }
202
+
203
+ ```
204
+
205
+ * Verify local override value
206
+
207
+ ```ruby
208
+
209
+ # => object_instance_one.some_hash_configuration.should == { :yet_another_value => :some_value }
210
+ # => CascadingConfiguration::MockClass.some_hash_configuration.should == { :another_value => :some_value }
211
+ # => CascadingConfiguration::MockModule.some_hash_configuration.should == { :some_value => :some_value }
212
+
213
+ ```
214
+
215
+ # First Inheriting Class #
216
+
217
+ 6. Inheriting class.
218
+
219
+ Inheriting class should not get any settings from instance of superclass.
220
+
221
+ * Verify inherited value
222
+
223
+ ```ruby
224
+
225
+ class CascadingConfiguration::MockClassSub1 < CascadingConfiguration::MockClass
226
+ # => some_hash_configuration.should == { :another_value => :some_value }
227
+ end
228
+
229
+ ```
230
+
231
+ * Override inherited value
232
+
233
+ ```ruby
234
+
235
+ class CascadingConfiguration::MockClassSub1 < CascadingConfiguration::MockClass
236
+ self.some_hash_configuration = { :a_value_not_yet_used => :some_value }
237
+ end
238
+
239
+ ```
240
+
241
+ * Verify local override value
242
+
243
+ ```ruby
244
+
245
+ class CascadingConfiguration::MockClassSub1 < CascadingConfiguration::MockClass
246
+ # => some_hash_configuration.should == { :a_value_not_yet_used => :some_value }
247
+ # => CascadingConfiguration::MockClass.some_hash_configuration.should == { :another_value => :some_value }
248
+ # => CascadingConfiguration::MockModule.some_hash_configuration.should == { :some_value => :some_value }
249
+ end
250
+
251
+ ```
252
+
253
+ ## Instance of First Inheriting Class ##
254
+
255
+ 7. Instantiate first inheriting class.
256
+
257
+ ```ruby
258
+
259
+ object_instance_two = CascadingConfiguration::MockClassSub1.new
260
+
261
+ ```
262
+
263
+ * Verify inherited value
264
+
265
+ ```ruby
266
+
267
+ # => object_instance_two.some_hash_configuration.should == { :a_value_not_yet_used => :some_value }
268
+ # => object_instance_one.some_hash_configuration.should == { :yet_another_value => :some_value }
269
+ # => CascadingConfiguration::MockClass.some_hash_configuration.should == { :another_value => :some_value }
270
+ # => CascadingConfiguration::MockModule.some_hash_configuration.should == { :some_value => :some_value }
271
+
272
+ ```
273
+
274
+ ## Second Inheriting Class ##
275
+
276
+ 8. Second inheriting class.
277
+
278
+ * Verify inherited value
279
+
280
+ ```ruby
281
+
282
+ class CascadingConfiguration::MockClassSub2 < CascadingConfiguration::MockClassSub1
283
+ # => some_hash_configuration.should == { :a_value_not_yet_used => :some_value }
284
+ end
285
+
286
+ ```
287
+
288
+ * Override inherited value
289
+
290
+ ```ruby
291
+
292
+ class CascadingConfiguration::MockClassSub2 < CascadingConfiguration::MockClassSub1
293
+ self.some_hash_configuration = { :another_value_not_yet_used => :some_value }
294
+ end
295
+
296
+ ```
297
+
298
+ * Verify local override value
299
+
300
+ ```ruby
301
+
302
+ class CascadingConfiguration::MockClassSub2 < CascadingConfiguration::MockClassSub1
303
+ # => some_hash_configuration.should == { :another_value_not_yet_used => :some_value }
304
+ end
305
+
306
+ ```
307
+
308
+ ## Instance of Second Inheriting Class ##
309
+
310
+ 9. Instantiate Second Inheriting Class.
311
+
312
+ ```ruby
313
+
314
+ object_instance_three = CascadingConfiguration::MockClassSub2.new
315
+
316
+ ```
317
+
318
+ * Verify inherited value
319
+
320
+ ```ruby
321
+
322
+ # => object_instance_three.some_hash_configuration.should == { :another_value_not_yet_used => :some_value }
323
+
324
+ ```
325
+
326
+ * Override inherited value
327
+
328
+ ```ruby
329
+
330
+ object_instance_three.some_hash_configuration = { :one_more_unused_value => :some_value }
331
+
332
+ ```
333
+
334
+ * Verify local override value
335
+
336
+ ```ruby
337
+
338
+ # => object_instance_three.some_hash_configuration.should == { :one_more_unused_value => :some_value }
339
+
340
+ ```
62
341
 
63
342
  # License #
64
343
 
data/README.rdoc CHANGED
@@ -10,24 +10,6 @@ Adds methods for cascading configurations.
10
10
 
11
11
  Cascading configuration methods for single settings, arrays, hashes.
12
12
 
13
- == :attr_configuration
14
-
15
- :attr_configuration provides inheritable configuration that cascades downward.
16
-
17
- Configuration inheritance can cascade through modules, classes, and instances.
18
-
19
- :attr_configuration defines a single attribute accessor that searches upward for the first ancestor defining the configuration.
20
-
21
- == :attr_configuration_array
22
-
23
- :attr_configuration_array provides inheritable configuration that cascades downward.
24
-
25
- Configuration inheritance can cascade through modules, classes, and instances.
26
-
27
- :attr_configuration_array defines a single attribute accessor that composes the set of configuration values appropriate to the ancestor level being queried (merging downward from most distant ancestor to self). An internal cache is kept, and any configuration updates that occur to higher-level ancestors cascade immediately downward.
28
-
29
- The array maintained by :attr_configuration_array is kept ordered and unique.
30
-
31
13
  == :attr_configuration_hash
32
14
 
33
15
  :attr_configuration_hash provides inheritable configuration that cascades downward.
@@ -42,15 +24,7 @@ Configuration inheritance can cascade through modules, classes, and instances.
42
24
 
43
25
  == Usage
44
26
 
45
- module AnyModuleOrClass
46
- include CascadingConfiguration
47
- end
48
-
49
- For further details, see supporting package README markdown files (README.md) for examples in each case:
50
-
51
- * attr_configuration
52
- * attr_configuration_array
53
- * attr_configuration_hash
27
+ See supporting package README markdown files (README.md) for examples.
54
28
 
55
29
  == License
56
30
 
@@ -0,0 +1,39 @@
1
+
2
+ module CascadingConfiguration::CompositingHash::Instance
3
+
4
+ extend CascadingConfiguration::InternalModuleStub
5
+
6
+ ###################
7
+ # self.included #
8
+ ###################
9
+
10
+ def self.included( class_or_module )
11
+ module_self = self
12
+ class_or_module.instance_eval do
13
+ extend module_self
14
+ end
15
+ end
16
+
17
+ ################################################
18
+ # composite_hash_for_cascading_configuration #
19
+ ################################################
20
+
21
+ def composite_hash_for_cascading_configuration( cascading_name )
22
+
23
+ composite_hash = nil
24
+
25
+ klass = ( is_a?( Module ) ? self : self.class )
26
+ accessor_support_module = klass::AccessorSupportModule
27
+ self_instance = self
28
+ accessor_support_module.instance_eval do
29
+ unless composite_hash = ( ( @composite_hashes ||= Hash.new )[ cascading_name ] ||= Hash.new )[ self_instance ]
30
+ composite_hash = ::CascadingConfiguration::CompositingHash.new( cascading_name, self_instance )
31
+ @composite_hashes[ cascading_name ][ self_instance ] = composite_hash
32
+ end
33
+ end
34
+
35
+ return composite_hash
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,136 @@
1
+
2
+ class CascadingConfiguration::CompositingHash < Hash
3
+
4
+ attr_accessor :working_instance, :local_cascading_hash
5
+
6
+ ################
7
+ # initialize #
8
+ ################
9
+
10
+ def initialize( cascading_name, working_instance )
11
+ @cascading_name = cascading_name
12
+ @working_class = ( working_instance.is_a?( Module ) ? working_instance : working_instance.class )
13
+ @cascading_variable = @working_class::AccessorSupportModule.cascading_variable_name( @cascading_name )
14
+ @working_instance = working_instance
15
+ # if first ancestor can have a composite array, register self with it in case it gets updated in the future
16
+ if ( first_ancestor = @working_instance.first_ancestor ).respond_to?( :composite_hash_for_cascading_configuration )
17
+ @parent_composite_hash = first_ancestor.composite_hash_for_cascading_configuration( @cascading_name )
18
+ @parent_composite_hash.register_child_composite_hash( self )
19
+ end
20
+ # get local cascading array (not included in parent composite)
21
+ @local_cascading_hash = ::CascadingConfiguration::LocalConfigurationHash.new
22
+ # we may later have our own child composites
23
+ @child_composite_hashes = ::Array.new
24
+ # initialize self status for parent and local
25
+ update_self_as_cascading_composite
26
+ end
27
+
28
+ ###################################
29
+ # register_child_composite_hash #
30
+ ###################################
31
+
32
+ def register_child_composite_hash( child_composite_hash )
33
+ @child_composite_hashes.push( child_composite_hash )
34
+ return self
35
+ end
36
+
37
+ #####################################
38
+ # unregister_child_composite_hash #
39
+ #####################################
40
+
41
+ def unregister_child_composite_hash( child_composite_hash )
42
+ @child_composite_hashes.delete( child_composite_hash )
43
+ return self
44
+ end
45
+
46
+ #########
47
+ # []= #
48
+ #########
49
+
50
+ def []=( key, value )
51
+ @local_cascading_hash[ key ] = value
52
+ update_adding_composite_elements( key => value )
53
+ end
54
+ alias_method :store, :[]=
55
+
56
+ ############
57
+ # delete #
58
+ ############
59
+
60
+ alias_method :super_delete, :delete
61
+ def delete( key )
62
+ value = self[ key ]
63
+ @local_cascading_hash.delete( key )
64
+ update_removing_composite_elements( key )
65
+ return value
66
+ end
67
+
68
+ ############
69
+ # merge! #
70
+ ############
71
+
72
+ alias_method :super_merge!, :merge!
73
+ def merge!( other_hash )
74
+ @local_cascading_hash.merge!( other_hash )
75
+ update_adding_composite_elements( other_hash )
76
+ return self
77
+ end
78
+
79
+ #############
80
+ # replace #
81
+ #############
82
+
83
+ alias_method :super_replace, :replace
84
+ def replace( other_hash )
85
+ # clear current values
86
+ clear
87
+ # merge replacement settings
88
+ merge!( other_hash )
89
+ update_self_as_cascading_composite
90
+ return self
91
+ end
92
+
93
+ ###########
94
+ # shift #
95
+ ###########
96
+
97
+ def shift
98
+ element = super
99
+ key = element[ 0 ]
100
+ @local_cascading_hash.delete( key )
101
+ update_removing_composite_elements( key )
102
+ return element
103
+ end
104
+
105
+ ###########
106
+ # clear #
107
+ ###########
108
+
109
+ alias_method :super_clear, :clear
110
+ def clear
111
+ # add all existing values to exclude array
112
+ keys.each do |this_key|
113
+ delete( this_key )
114
+ end
115
+ update_removing_composite_elements( *self.keys )
116
+ return self
117
+ end
118
+
119
+ #############
120
+ # freeze! #
121
+ #############
122
+
123
+ # freezes configuration and prevents ancestors from changing this configuration in the future
124
+ def freeze!
125
+
126
+ # move current configuration into local configuration
127
+ @local_cascading_hash.replace( self )
128
+
129
+ # unregister with parent composite so we don't get future updates from it
130
+ @parent_composite_hash.unregister_child_composite_hash( self ) if @parent_composite_hash
131
+
132
+ return self
133
+
134
+ end
135
+
136
+ end
@@ -0,0 +1,33 @@
1
+
2
+ module CascadingConfiguration::Hash::Accessors
3
+
4
+ extend CascadingConfiguration::InternalModuleStub
5
+
6
+ ######################################
7
+ # define_configuration_hash_setter #
8
+ ######################################
9
+
10
+ def define_configuration_hash_setter( configuration_name )
11
+ configuration_setter_name = ( configuration_name.to_s + '=' ).to_sym
12
+ self::AccessorSupportModule.module_eval do
13
+ define_method( configuration_setter_name ) do |hash|
14
+ # we want the hash to supplant existing config
15
+ return composite_hash_for_cascading_configuration( configuration_name ).replace( hash )
16
+ end
17
+ end
18
+ end
19
+
20
+ ######################################
21
+ # define_configuration_hash_getter #
22
+ ######################################
23
+
24
+ def define_configuration_hash_getter( configuration_name )
25
+ configuration_getter_name = configuration_name
26
+ self::AccessorSupportModule.module_eval do
27
+ define_method( configuration_getter_name ) do
28
+ return composite_hash_for_cascading_configuration( configuration_name )
29
+ end
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,24 @@
1
+
2
+ module CascadingConfiguration::Hash::ClassInstance
3
+
4
+ extend CascadingConfiguration::InternalModuleStub
5
+
6
+ #############################
7
+ # attr_configuration_hash #
8
+ #############################
9
+
10
+ def attr_configuration_hash( *property_names, & compositing_block )
11
+
12
+ property_names.each do |this_property_name|
13
+ self::AccessorSupportModule.set_compositing_proc( this_property_name, compositing_block ) if block_given?
14
+ # define configuration setter
15
+ define_configuration_hash_setter( this_property_name )
16
+ # define configuration getter
17
+ define_configuration_hash_getter( this_property_name )
18
+ end
19
+
20
+ return self
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,34 @@
1
+
2
+ module CascadingConfiguration::Hash::ModuleInstance
3
+
4
+ extend CascadingConfiguration::InternalModuleStub
5
+
6
+ ##############
7
+ # included #
8
+ ##############
9
+
10
+ def included( class_or_module )
11
+ super if method_defined?( :super )
12
+ # CascadingConfiguration::Hash
13
+ module_self = self
14
+ class_or_module.instance_eval do
15
+ # cascade CascadingConfiguration::Hash
16
+ include CascadingConfiguration::Hash
17
+ end
18
+ end
19
+
20
+ ##############
21
+ # extended #
22
+ ##############
23
+
24
+ def extended( class_or_module )
25
+ super if method_defined?( :super )
26
+ # CascadingConfiguration::Hash
27
+ module_self = self
28
+ class_or_module.instance_eval do
29
+ # cascade CascadingConfiguration::Hash
30
+ include CascadingConfiguration::Hash
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,24 @@
1
+
2
+ module CascadingConfiguration::Hash
3
+
4
+ extend CascadingConfiguration::InternalModuleStub
5
+
6
+ include CascadingConfiguration::Variable
7
+ include CascadingConfiguration::CompositingHash::Instance
8
+
9
+ ###################
10
+ # self.included #
11
+ ###################
12
+
13
+ def self.included( class_or_module )
14
+ module_self = self
15
+ class_or_module.instance_eval do
16
+ extend module_self
17
+ extend module_self::Accessors
18
+ extend module_self::ClassInstance
19
+ # module support
20
+ extend CascadingConfiguration::Hash::ModuleInstance unless is_a?( Class )
21
+ end
22
+ end
23
+
24
+ end