compositing-hash 1.0.15

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.
@@ -0,0 +1,65 @@
1
+ # CompositingHash #
2
+
3
+ http://rubygems.org/gems/compositing-hash
4
+
5
+ # Description #
6
+
7
+ Provides CompositingHash.
8
+
9
+ # Summary #
10
+
11
+ An implementation of Hash that permits chaining, where children inherit changes to parent and where parent settings can be overridden in children.
12
+
13
+ # Install #
14
+
15
+ * sudo gem install compositing-hash
16
+
17
+ # Usage #
18
+
19
+ ```ruby
20
+ compositing_hash = CompositingHash.new
21
+ sub_compositing_hash = CompositingHash.new( compositing_hash )
22
+
23
+ compositing_hash[ :some_key ] = :some_value
24
+ # compositing_hash
25
+ # => { :some_key => :some_value }
26
+ # sub_compositing_hash
27
+ # => { :some_key => :some_value }
28
+
29
+ compositing_hash.delete( :some_key )
30
+ # compositing_hash
31
+ # => { }
32
+ # sub_compositing_hash
33
+ # => { }
34
+
35
+ sub_compositing_hash[ :some_key ] = :some_value
36
+ # compositing_hash
37
+ # => { }
38
+ # sub_compositing_hash
39
+ # => { :some_key => :some_value }
40
+ ```
41
+
42
+ # License #
43
+
44
+ (The MIT License)
45
+
46
+ Copyright (c) Asher
47
+
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of this software and associated documentation files (the
50
+ 'Software'), to deal in the Software without restriction, including
51
+ without limitation the rights to use, copy, modify, merge, publish,
52
+ distribute, sublicense, and/or sell copies of the Software, and to
53
+ permit persons to whom the Software is furnished to do so, subject to
54
+ the following conditions:
55
+
56
+ The above copyright notice and this permission notice shall be
57
+ included in all copies or substantial portions of the Software.
58
+
59
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
60
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
61
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
62
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
63
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
64
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
65
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
File without changes
@@ -0,0 +1,5 @@
1
+
2
+ require 'hooked-hash'
3
+
4
+ require_relative 'compositing-hash/CompositingHash.rb'
5
+
@@ -0,0 +1,374 @@
1
+
2
+ class ::CompositingHash < ::HookedHash
3
+
4
+ ################
5
+ # initialize #
6
+ ################
7
+
8
+ def initialize( parent_composite_hash = nil, configuration_instance = nil )
9
+
10
+ super( configuration_instance )
11
+
12
+ @replaced_parents = { }
13
+ @parent_key_lookup = { }
14
+
15
+ # we may later have our own child composites that register with us
16
+ @sub_composite_hashes = [ ]
17
+
18
+ initialize_for_parent( parent_composite_hash )
19
+
20
+ end
21
+
22
+ #############################
23
+ # parent_composite_object #
24
+ # parent_composite_hash #
25
+ #############################
26
+
27
+ attr_accessor :parent_composite_object
28
+
29
+ alias_method :parent_composite_hash, :parent_composite_object
30
+
31
+ ################################### Sub-Hash Management #######################################
32
+
33
+ ###########################
34
+ # initialize_for_parent #
35
+ ###########################
36
+
37
+ def initialize_for_parent( parent_composite_hash )
38
+
39
+ if @parent_composite_object = parent_composite_hash
40
+
41
+ @parent_composite_object.register_sub_composite_hash( self )
42
+
43
+ # @parent_key_lookup tracks keys that we have not yet received from parent
44
+ @parent_composite_object.each do |this_key, this_object|
45
+ @parent_key_lookup[ this_key ] = true
46
+ non_cascading_store( this_key, nil )
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ #################################
54
+ # register_sub_composite_hash #
55
+ #################################
56
+
57
+ def register_sub_composite_hash( sub_composite_hash )
58
+
59
+ @sub_composite_hashes.push( sub_composite_hash )
60
+
61
+ return self
62
+
63
+ end
64
+
65
+ ###################################
66
+ # unregister_sub_composite_hash #
67
+ ###################################
68
+
69
+ def unregister_sub_composite_hash( sub_composite_hash )
70
+
71
+ @sub_composite_hashes.delete( sub_composite_hash )
72
+
73
+ return self
74
+
75
+ end
76
+
77
+ ###################################### Subclass Hooks ##########################################
78
+
79
+ ########################
80
+ # child_pre_set_hook #
81
+ ########################
82
+
83
+ def child_pre_set_hook( key, object )
84
+
85
+ return object
86
+
87
+ end
88
+
89
+ #########################
90
+ # child_post_set_hook #
91
+ #########################
92
+
93
+ def child_post_set_hook( key, object )
94
+
95
+ return object
96
+
97
+ end
98
+
99
+ ###########################
100
+ # child_pre_delete_hook #
101
+ ###########################
102
+
103
+ def child_pre_delete_hook( key )
104
+
105
+ # false means delete does not take place
106
+ return true
107
+
108
+ end
109
+
110
+ ############################
111
+ # child_post_delete_hook #
112
+ ############################
113
+
114
+ def child_post_delete_hook( key, object )
115
+
116
+ return object
117
+
118
+ end
119
+
120
+ ##################################### Self Management ##########################################
121
+
122
+ ########
123
+ # == #
124
+ ########
125
+
126
+ def ==( object )
127
+
128
+ @parent_key_lookup.each do |this_key, true_value|
129
+ self[ this_key ]
130
+ end
131
+
132
+ super
133
+
134
+ end
135
+
136
+ ##########
137
+ # each #
138
+ ##########
139
+
140
+ def each( *args, & block )
141
+
142
+ @parent_key_lookup.each do |this_key, true_value|
143
+ self[ this_key ]
144
+ end
145
+
146
+ super
147
+
148
+ end
149
+
150
+ ##########
151
+ # to_s #
152
+ ##########
153
+
154
+ def to_s
155
+
156
+ @parent_key_lookup.each do |this_key, true_value|
157
+ self[ this_key ]
158
+ end
159
+
160
+ super
161
+
162
+ end
163
+
164
+ #############
165
+ # inspect #
166
+ #############
167
+
168
+ def inspect
169
+
170
+ @parent_key_lookup.each do |this_key, true_value|
171
+ self[ this_key ]
172
+ end
173
+
174
+ super
175
+
176
+ end
177
+
178
+ ########
179
+ # [] #
180
+ ########
181
+
182
+ def []( key )
183
+
184
+ return_value = nil
185
+
186
+ if @parent_key_lookup.has_key?( key )
187
+ return_value = set_parent_element_in_self( key, @parent_composite_object[ key ] )
188
+ @parent_key_lookup.delete( key )
189
+ else
190
+ return_value = super
191
+ end
192
+
193
+ return return_value
194
+
195
+ end
196
+
197
+ #########
198
+ # []= #
199
+ #########
200
+
201
+ private
202
+ alias_method :non_cascading_store, :store
203
+ public
204
+
205
+ def []=( key, object )
206
+
207
+ @replaced_parents[ key ] = true
208
+
209
+ @parent_key_lookup.delete( key )
210
+
211
+ super
212
+
213
+ @sub_composite_hashes.each do |this_sub_hash|
214
+ this_sub_hash.instance_eval do
215
+ update_as_sub_hash_for_parent_store( key )
216
+ end
217
+ end
218
+
219
+ return object
220
+
221
+ end
222
+ alias_method :store, :[]=
223
+
224
+ ############
225
+ # delete #
226
+ ############
227
+
228
+ private
229
+ alias_method :non_cascading_delete, :delete
230
+ public
231
+
232
+ def delete( key )
233
+
234
+ @replaced_parents.delete( key )
235
+
236
+ @parent_key_lookup.delete( key )
237
+
238
+ object = super
239
+
240
+ @sub_composite_hashes.each do |this_sub_hash|
241
+ this_sub_hash.instance_eval do
242
+ update_as_sub_hash_for_parent_delete( key, object )
243
+ end
244
+ end
245
+
246
+ return object
247
+
248
+ end
249
+
250
+ #############
251
+ # freeze! #
252
+ #############
253
+
254
+ # freezes configuration and prevents ancestors from changing this configuration in the future
255
+ def freeze!
256
+
257
+ # unregister with parent composite so we don't get future updates from it
258
+ if @parent_composite_object
259
+ @parent_composite_object.unregister_sub_composite_hash( self )
260
+ end
261
+
262
+ return self
263
+
264
+ end
265
+
266
+ ##################################################################################################
267
+ private ######################################################################################
268
+ ##################################################################################################
269
+
270
+ ######################### Self-as-Sub Management for Parent Updates ############################
271
+
272
+ ################################
273
+ # set_parent_element_in_self #
274
+ ################################
275
+
276
+ def set_parent_element_in_self( key, object )
277
+
278
+ unless @without_child_hooks
279
+ object = child_pre_set_hook( key, object )
280
+ end
281
+
282
+ unless @without_hooks
283
+ object = pre_set_hook( key, object )
284
+ end
285
+
286
+ non_cascading_store( key, object )
287
+
288
+ unless @without_hooks
289
+ object = post_set_hook( key, object )
290
+ end
291
+
292
+ unless @without_child_hooks
293
+ object = child_post_set_hook( key, object )
294
+ end
295
+
296
+ return object
297
+
298
+ end
299
+
300
+ #########################################
301
+ # update_as_sub_hash_for_parent_store #
302
+ #########################################
303
+
304
+ def update_as_sub_hash_for_parent_store( key )
305
+
306
+ unless @replaced_parents[ key ]
307
+
308
+ @parent_key_lookup[ key ] = true
309
+
310
+ @sub_composite_hashes.each do |this_hash|
311
+ this_hash.instance_eval do
312
+ update_as_sub_hash_for_parent_store( key )
313
+ end
314
+ end
315
+
316
+ end
317
+
318
+ end
319
+
320
+ ##########################################
321
+ # update_as_sub_hash_for_parent_delete #
322
+ ##########################################
323
+
324
+ def update_as_sub_hash_for_parent_delete( key, object )
325
+
326
+ unless @replaced_parents[ key ]
327
+
328
+ if @without_child_hooks
329
+ child_pre_delete_hook_result = true
330
+ else
331
+ child_pre_delete_hook_result = child_pre_delete_hook( key )
332
+ end
333
+
334
+ if @without_hooks
335
+ pre_delete_hook_result = true
336
+ else
337
+ pre_delete_hook_result = pre_delete_hook( key )
338
+ end
339
+
340
+ if child_pre_delete_hook_result and pre_delete_hook_result
341
+
342
+ @parent_key_lookup.delete( key )
343
+ object = non_cascading_delete( key )
344
+
345
+ unless @without_hooks
346
+ post_delete_hook( key, object )
347
+ end
348
+
349
+ unless @without_child_hooks
350
+ child_post_delete_hook( key, object )
351
+ end
352
+
353
+ else
354
+
355
+ # if we were told not to delete in child when parent delete
356
+ # and the child does not yet have its parent value
357
+ # then we need to get it now
358
+ if @parent_key_lookup.delete( key )
359
+ self[ key ] = object
360
+ end
361
+
362
+ end
363
+
364
+ @sub_composite_hashes.each do |this_hash|
365
+ this_hash.instance_eval do
366
+ update_as_sub_hash_for_parent_delete( key, object )
367
+ end
368
+ end
369
+
370
+ end
371
+
372
+ end
373
+
374
+ end
@@ -0,0 +1,648 @@
1
+
2
+ require_relative '../lib/compositing-hash.rb'
3
+
4
+ describe ::CompositingHash do
5
+
6
+ before :all do
7
+
8
+ module ::CompositingHash::MockA
9
+ # needed for ccv ancestor determination
10
+ def self.some_configuration
11
+ end
12
+ end
13
+ module ::CompositingHash::MockB
14
+ end
15
+
16
+ @configuration_instance = ::CompositingHash::MockA
17
+ @sub_configuration_instance = ::CompositingHash::MockB
18
+
19
+ end
20
+
21
+ ################
22
+ # initialize #
23
+ ################
24
+
25
+ it 'can add initialize with an ancestor, inheriting its values and linking to it as a child' do
26
+
27
+ cascading_composite_hash = ::CompositingHash.new
28
+
29
+ cascading_composite_hash.instance_variable_get( :@parent_composite_object ).should == nil
30
+ cascading_composite_hash.should == {}
31
+ cascading_composite_hash[ :A ] = 1
32
+ cascading_composite_hash[ :B ] = 2
33
+ cascading_composite_hash[ :C ] = 3
34
+ cascading_composite_hash[ :D ] = 4
35
+ cascading_composite_hash.should == { :A => 1,
36
+ :B => 2,
37
+ :C => 3,
38
+ :D => 4 }
39
+
40
+ sub_cascading_composite_hash = ::CompositingHash.new( cascading_composite_hash )
41
+ sub_cascading_composite_hash.instance_variable_get( :@parent_composite_object ).should == cascading_composite_hash
42
+ sub_cascading_composite_hash.should == { :A => 1,
43
+ :B => 2,
44
+ :C => 3,
45
+ :D => 4 }
46
+
47
+ end
48
+
49
+ ##################################################################################################
50
+ # private #####################################################################################
51
+ ##################################################################################################
52
+
53
+ #########################################
54
+ # update_as_sub_hash_for_parent_store #
55
+ #########################################
56
+
57
+ it 'can update for a parent store' do
58
+
59
+ cascading_composite_hash = ::CompositingHash.new
60
+ cascading_composite_hash[ :A ] = 1
61
+ sub_cascading_composite_hash = ::CompositingHash.new( cascading_composite_hash )
62
+
63
+ sub_cascading_composite_hash.instance_eval do
64
+ update_as_sub_hash_for_parent_store( :A )
65
+ self.should == { :A => 1 }
66
+ end
67
+
68
+ end
69
+
70
+ ##########################################
71
+ # update_as_sub_hash_for_parent_delete #
72
+ ##########################################
73
+
74
+ it 'can update for a parent delete' do
75
+
76
+ cascading_composite_hash = ::CompositingHash.new
77
+ sub_cascading_composite_hash = ::CompositingHash.new( cascading_composite_hash )
78
+
79
+ cascading_composite_hash[ :A ] = 1
80
+ cascading_composite_hash.should == { :A => 1 }
81
+ sub_cascading_composite_hash.should == { :A => 1 }
82
+
83
+ sub_cascading_composite_hash.instance_eval do
84
+ update_as_sub_hash_for_parent_delete( :A, 1 )
85
+ self.should == { }
86
+ end
87
+
88
+ end
89
+
90
+ ##################################################################################################
91
+ # public ######################################################################################
92
+ ##################################################################################################
93
+
94
+ #########
95
+ # []= #
96
+ #########
97
+
98
+ it 'can add elements' do
99
+
100
+ cascading_composite_hash = ::CompositingHash.new
101
+ sub_cascading_composite_hash = ::CompositingHash.new( cascading_composite_hash )
102
+
103
+ cascading_composite_hash[ :some_setting ] = :some_value
104
+ cascading_composite_hash.should == { :some_setting => :some_value }
105
+ sub_cascading_composite_hash.should == { :some_setting => :some_value }
106
+
107
+ cascading_composite_hash[ :other_setting ] = :some_value
108
+ cascading_composite_hash.should == { :some_setting => :some_value,
109
+ :other_setting => :some_value }
110
+ sub_cascading_composite_hash.should == { :some_setting => :some_value,
111
+ :other_setting => :some_value }
112
+
113
+ sub_cascading_composite_hash[ :yet_another_setting ] = :some_value
114
+ cascading_composite_hash.should == { :some_setting => :some_value,
115
+ :other_setting => :some_value }
116
+ sub_cascading_composite_hash.should == { :some_setting => :some_value,
117
+ :other_setting => :some_value,
118
+ :yet_another_setting => :some_value }
119
+
120
+ cascading_composite_hash.method( :[]= ).should == cascading_composite_hash.method( :store )
121
+
122
+ end
123
+
124
+ ############
125
+ # delete #
126
+ ############
127
+
128
+ it 'can delete elements' do
129
+
130
+ cascading_composite_hash = ::CompositingHash.new
131
+ sub_cascading_composite_hash = ::CompositingHash.new( cascading_composite_hash )
132
+
133
+ cascading_composite_hash.store( :some_setting, :some_value )
134
+ cascading_composite_hash.should == { :some_setting => :some_value }
135
+ sub_cascading_composite_hash.should == { :some_setting => :some_value }
136
+
137
+ cascading_composite_hash.store( :other_setting, :some_value )
138
+ cascading_composite_hash.should == { :some_setting => :some_value,
139
+ :other_setting => :some_value }
140
+ sub_cascading_composite_hash.should == { :some_setting => :some_value,
141
+ :other_setting => :some_value }
142
+
143
+ cascading_composite_hash.delete( :some_setting )
144
+ cascading_composite_hash.should == { :other_setting => :some_value }
145
+ sub_cascading_composite_hash.should == { :other_setting => :some_value }
146
+
147
+ sub_cascading_composite_hash.store( :yet_another_setting, :some_value )
148
+ cascading_composite_hash.should == { :other_setting => :some_value }
149
+ sub_cascading_composite_hash.should == { :other_setting => :some_value,
150
+ :yet_another_setting => :some_value }
151
+
152
+ sub_cascading_composite_hash.delete( :other_setting )
153
+ sub_cascading_composite_hash.should == { :yet_another_setting => :some_value }
154
+ cascading_composite_hash.should == { :other_setting => :some_value }
155
+
156
+ end
157
+
158
+ ###############
159
+ # delete_if #
160
+ ###############
161
+
162
+ it 'can delete elements with a block' do
163
+
164
+ cascading_composite_hash = ::CompositingHash.new
165
+ sub_cascading_composite_hash = ::CompositingHash.new( cascading_composite_hash )
166
+
167
+ cascading_composite_hash.store( :some_setting, :some_value )
168
+ cascading_composite_hash.should == { :some_setting => :some_value }
169
+ sub_cascading_composite_hash.should == { :some_setting => :some_value }
170
+
171
+ cascading_composite_hash.store( :other_setting, :some_value )
172
+ cascading_composite_hash.should == { :some_setting => :some_value,
173
+ :other_setting => :some_value }
174
+ sub_cascading_composite_hash.should == { :some_setting => :some_value,
175
+ :other_setting => :some_value }
176
+ cascading_composite_hash.delete_if do |key, value|
177
+ key == :some_setting
178
+ end
179
+ cascading_composite_hash.should == { :other_setting => :some_value }
180
+ sub_cascading_composite_hash.should == { :other_setting => :some_value }
181
+
182
+ sub_cascading_composite_hash.store( :yet_another_setting, :some_value )
183
+ cascading_composite_hash.should == { :other_setting => :some_value }
184
+ sub_cascading_composite_hash.should == { :other_setting => :some_value,
185
+ :yet_another_setting => :some_value }
186
+ sub_cascading_composite_hash.delete_if do |key, value|
187
+ key == :other_setting
188
+ end
189
+ cascading_composite_hash.should == { :other_setting => :some_value }
190
+ sub_cascading_composite_hash.should == { :yet_another_setting => :some_value }
191
+
192
+ end
193
+
194
+ #############
195
+ # reject! #
196
+ #############
197
+
198
+ it 'can delete elements with a block' do
199
+
200
+ cascading_composite_hash = ::CompositingHash.new
201
+ sub_cascading_composite_hash = ::CompositingHash.new( cascading_composite_hash )
202
+
203
+ cascading_composite_hash.store( :some_setting, :some_value )
204
+ cascading_composite_hash.should == { :some_setting => :some_value }
205
+ sub_cascading_composite_hash.should == { :some_setting => :some_value }
206
+
207
+ cascading_composite_hash.store( :other_setting, :some_value )
208
+ cascading_composite_hash.should == { :some_setting => :some_value,
209
+ :other_setting => :some_value }
210
+ sub_cascading_composite_hash.should == { :some_setting => :some_value,
211
+ :other_setting => :some_value }
212
+ cascading_composite_hash.reject! do |key, value|
213
+ key == :some_setting
214
+ end
215
+ cascading_composite_hash.should == { :other_setting => :some_value }
216
+ sub_cascading_composite_hash.should == { :other_setting => :some_value }
217
+
218
+ sub_cascading_composite_hash.store( :yet_another_setting, :some_value )
219
+ cascading_composite_hash.should == { :other_setting => :some_value }
220
+ sub_cascading_composite_hash.should == { :other_setting => :some_value,
221
+ :yet_another_setting => :some_value }
222
+ sub_cascading_composite_hash.reject! do |key, value|
223
+ key == :other_setting
224
+ end
225
+ cascading_composite_hash.should == { :other_setting => :some_value }
226
+ sub_cascading_composite_hash.should == { :yet_another_setting => :some_value }
227
+
228
+ end
229
+
230
+ #############
231
+ # keep_if #
232
+ #############
233
+
234
+ it 'can keep elements with a block' do
235
+
236
+ cascading_composite_hash = ::CompositingHash.new
237
+ sub_cascading_composite_hash = ::CompositingHash.new( cascading_composite_hash )
238
+
239
+ cascading_composite_hash.store( :some_setting, :some_value )
240
+ cascading_composite_hash.should == { :some_setting => :some_value }
241
+ sub_cascading_composite_hash.should == { :some_setting => :some_value }
242
+
243
+ cascading_composite_hash.store( :other_setting, :some_value )
244
+ cascading_composite_hash.should == { :some_setting => :some_value,
245
+ :other_setting => :some_value }
246
+ sub_cascading_composite_hash.should == { :some_setting => :some_value,
247
+ :other_setting => :some_value }
248
+ cascading_composite_hash.keep_if do |key, value|
249
+ key != :some_setting
250
+ end
251
+ cascading_composite_hash.should == { :other_setting => :some_value }
252
+ sub_cascading_composite_hash.should == { :other_setting => :some_value }
253
+
254
+ sub_cascading_composite_hash.store( :yet_another_setting, :some_value )
255
+ cascading_composite_hash.should == { :other_setting => :some_value }
256
+ sub_cascading_composite_hash.should == { :other_setting => :some_value,
257
+ :yet_another_setting => :some_value }
258
+ sub_cascading_composite_hash.keep_if do |key, value|
259
+ key != :other_setting
260
+ end
261
+ cascading_composite_hash.should == { :other_setting => :some_value }
262
+ sub_cascading_composite_hash.should == { :yet_another_setting => :some_value }
263
+
264
+ end
265
+
266
+ #############
267
+ # select! #
268
+ #############
269
+
270
+ it 'can keep elements with a block' do
271
+
272
+ cascading_composite_hash = ::CompositingHash.new
273
+ sub_cascading_composite_hash = ::CompositingHash.new( cascading_composite_hash )
274
+
275
+ cascading_composite_hash.store( :some_setting, :some_value )
276
+ cascading_composite_hash.should == { :some_setting => :some_value }
277
+ sub_cascading_composite_hash.should == { :some_setting => :some_value }
278
+
279
+ cascading_composite_hash.store( :other_setting, :some_value )
280
+ cascading_composite_hash.should == { :some_setting => :some_value,
281
+ :other_setting => :some_value }
282
+ sub_cascading_composite_hash.should == { :some_setting => :some_value,
283
+ :other_setting => :some_value }
284
+ cascading_composite_hash.select! do |key, value|
285
+ key != :some_setting
286
+ end
287
+ cascading_composite_hash.should == { :other_setting => :some_value }
288
+ sub_cascading_composite_hash.should == { :other_setting => :some_value }
289
+
290
+ sub_cascading_composite_hash.store( :yet_another_setting, :some_value )
291
+ cascading_composite_hash.should == { :other_setting => :some_value }
292
+ sub_cascading_composite_hash.should == { :other_setting => :some_value,
293
+ :yet_another_setting => :some_value }
294
+ sub_cascading_composite_hash.select! do |key, value|
295
+ key != :other_setting
296
+ end
297
+ cascading_composite_hash.should == { :other_setting => :some_value }
298
+ sub_cascading_composite_hash.should == { :yet_another_setting => :some_value }
299
+
300
+ end
301
+
302
+ ############
303
+ # merge! #
304
+ # update #
305
+ ############
306
+
307
+ it 'can merge from another hash' do
308
+
309
+ cascading_composite_hash = ::CompositingHash.new
310
+ sub_cascading_composite_hash = ::CompositingHash.new( cascading_composite_hash )
311
+
312
+ cascading_composite_hash.merge!( :some_setting => :some_value )
313
+ cascading_composite_hash.should == { :some_setting => :some_value }
314
+ cascading_composite_hash.merge!( :other_setting => :some_value )
315
+ cascading_composite_hash.should == { :some_setting => :some_value,
316
+ :other_setting => :some_value }
317
+
318
+ sub_cascading_composite_hash.should == { :some_setting => :some_value,
319
+ :other_setting => :some_value }
320
+ sub_cascading_composite_hash.merge!( :yet_another_setting => :some_value )
321
+ sub_cascading_composite_hash.should == { :some_setting => :some_value,
322
+ :other_setting => :some_value,
323
+ :yet_another_setting => :some_value }
324
+
325
+ end
326
+
327
+ #############
328
+ # replace #
329
+ #############
330
+
331
+ it 'can replace existing elements with others' do
332
+
333
+ cascading_composite_hash = ::CompositingHash.new
334
+ sub_cascading_composite_hash = ::CompositingHash.new( cascading_composite_hash )
335
+
336
+ cascading_composite_hash.replace( :some_setting => :some_value )
337
+ cascading_composite_hash.should == { :some_setting => :some_value }
338
+ cascading_composite_hash.replace( :other_setting => :some_value )
339
+ cascading_composite_hash.should == { :other_setting => :some_value }
340
+
341
+ sub_cascading_composite_hash.should == { :other_setting => :some_value }
342
+ sub_cascading_composite_hash.replace( :yet_another_setting => :some_value )
343
+ sub_cascading_composite_hash.should == { :yet_another_setting => :some_value }
344
+
345
+ end
346
+
347
+ ###########
348
+ # shift #
349
+ ###########
350
+
351
+ it 'can shift the first element' do
352
+
353
+ cascading_composite_hash = ::CompositingHash.new
354
+ sub_cascading_composite_hash = ::CompositingHash.new( cascading_composite_hash )
355
+
356
+ cascading_composite_hash.store( :some_setting, :some_value )
357
+ cascading_composite_hash.should == { :some_setting => :some_value }
358
+ cascading_composite_hash.store( :other_setting, :some_value )
359
+ cascading_composite_hash.should == { :some_setting => :some_value,
360
+ :other_setting => :some_value }
361
+ cascading_composite_hash.shift
362
+ cascading_composite_hash.should == { :other_setting => :some_value }
363
+
364
+ sub_cascading_composite_hash.should == { :other_setting => :some_value }
365
+ sub_cascading_composite_hash.store( :yet_another_setting, :some_value )
366
+ sub_cascading_composite_hash.should == { :other_setting => :some_value,
367
+ :yet_another_setting => :some_value }
368
+ sub_cascading_composite_hash.shift
369
+ sub_cascading_composite_hash.should == { :yet_another_setting => :some_value }
370
+ cascading_composite_hash.should == { :other_setting => :some_value }
371
+
372
+ end
373
+
374
+ ###########
375
+ # clear #
376
+ ###########
377
+
378
+ it 'can clear, causing present elements to be excluded' do
379
+
380
+ cascading_composite_hash = ::CompositingHash.new
381
+ sub_cascading_composite_hash = ::CompositingHash.new( cascading_composite_hash )
382
+
383
+ cascading_composite_hash.store( :some_setting, :some_value )
384
+ cascading_composite_hash.should == { :some_setting => :some_value }
385
+ cascading_composite_hash.store( :other_setting, :some_value )
386
+ cascading_composite_hash.should == { :some_setting => :some_value,
387
+ :other_setting => :some_value }
388
+ cascading_composite_hash.clear
389
+ cascading_composite_hash.should == { }
390
+ cascading_composite_hash.store( :other_setting, :some_value )
391
+ cascading_composite_hash.should == { :other_setting => :some_value }
392
+
393
+ sub_cascading_composite_hash.should == { :other_setting => :some_value }
394
+ sub_cascading_composite_hash.store( :yet_another_setting, :some_value )
395
+ sub_cascading_composite_hash.should == { :other_setting => :some_value,
396
+ :yet_another_setting => :some_value }
397
+ sub_cascading_composite_hash.clear
398
+ sub_cascading_composite_hash.should == { }
399
+ cascading_composite_hash.should == { :other_setting => :some_value }
400
+
401
+ end
402
+
403
+ ##################
404
+ # pre_set_hook #
405
+ ##################
406
+
407
+ it 'has a hook that is called before setting a value; return value is used in place of object' do
408
+
409
+ class ::CompositingHash::SubMockPreSet < ::CompositingHash
410
+
411
+ def pre_set_hook( key, object, is_insert = false )
412
+ return :some_other_value
413
+ end
414
+
415
+ end
416
+
417
+ cascading_composite_hash = ::CompositingHash::SubMockPreSet.new
418
+
419
+ cascading_composite_hash[ :some_key ] = :some_value
420
+
421
+ cascading_composite_hash.should == { :some_key => :some_other_value }
422
+
423
+ end
424
+
425
+ ###################
426
+ # post_set_hook #
427
+ ###################
428
+
429
+ it 'has a hook that is called after setting a value' do
430
+
431
+ class ::CompositingHash::SubMockPostSet < ::CompositingHash
432
+
433
+ def post_set_hook( key, object, is_insert = false )
434
+ unless key == :some_other_key
435
+ self[ :some_other_key ] = :some_other_value
436
+ end
437
+ return object
438
+ end
439
+
440
+ end
441
+
442
+ cascading_composite_hash = ::CompositingHash::SubMockPostSet.new
443
+
444
+ cascading_composite_hash[ :some_key ] = :some_value
445
+
446
+ cascading_composite_hash.should == { :some_key => :some_value,
447
+ :some_other_key => :some_other_value }
448
+
449
+ end
450
+
451
+ ##################
452
+ # pre_get_hook #
453
+ ##################
454
+
455
+ it 'has a hook that is called before getting a value; if return value is false, get does not occur' do
456
+
457
+ class ::CompositingHash::SubMockPreGet < ::CompositingHash
458
+
459
+ def pre_get_hook( key )
460
+ return false
461
+ end
462
+
463
+ end
464
+
465
+ cascading_composite_hash = ::CompositingHash::SubMockPreGet.new
466
+
467
+ cascading_composite_hash[ :some_key ] = :some_value
468
+ cascading_composite_hash[ :some_key ].should == nil
469
+
470
+ cascading_composite_hash.should == { :some_key => :some_value }
471
+
472
+ end
473
+
474
+ ###################
475
+ # post_get_hook #
476
+ ###################
477
+
478
+ it 'has a hook that is called after getting a value' do
479
+
480
+ class ::CompositingHash::SubMockPostGet < ::CompositingHash
481
+
482
+ def post_get_hook( key, object )
483
+ self[ :some_other_key ] = :some_other_value
484
+ return object
485
+ end
486
+
487
+ end
488
+
489
+ cascading_composite_hash = ::CompositingHash::SubMockPostGet.new
490
+
491
+ cascading_composite_hash[ :some_key ] = :some_value
492
+
493
+ cascading_composite_hash.should == { :some_key => :some_value }
494
+
495
+ cascading_composite_hash[ :some_key ].should == :some_value
496
+
497
+ cascading_composite_hash.should == { :some_key => :some_value,
498
+ :some_other_key => :some_other_value }
499
+
500
+ end
501
+
502
+ #####################
503
+ # pre_delete_hook #
504
+ #####################
505
+
506
+ it 'has a hook that is called before deleting an key; if return value is false, delete does not occur' do
507
+
508
+ class ::CompositingHash::SubMockPreDelete < ::CompositingHash
509
+
510
+ def pre_delete_hook( key )
511
+ return false
512
+ end
513
+
514
+ end
515
+
516
+ cascading_composite_hash = ::CompositingHash::SubMockPreDelete.new
517
+
518
+ cascading_composite_hash[ :some_key ] = :some_value
519
+ cascading_composite_hash.delete( :some_key )
520
+
521
+ cascading_composite_hash.should == { :some_key => :some_value }
522
+
523
+ end
524
+
525
+ ######################
526
+ # post_delete_hook #
527
+ ######################
528
+
529
+ it 'has a hook that is called after deleting an key' do
530
+
531
+ class ::CompositingHash::SubMockPostDelete < ::CompositingHash
532
+
533
+ def post_delete_hook( key, object )
534
+ unless key == :some_other_key
535
+ delete( :some_other_key )
536
+ end
537
+ end
538
+
539
+ end
540
+
541
+ cascading_composite_hash = ::CompositingHash::SubMockPostDelete.new
542
+
543
+ cascading_composite_hash[ :some_key ] = :some_value
544
+ cascading_composite_hash[ :some_other_key ] = :some_other_value
545
+ cascading_composite_hash.delete( :some_key )
546
+
547
+ cascading_composite_hash.should == { }
548
+
549
+ end
550
+
551
+ ########################
552
+ # child_pre_set_hook #
553
+ ########################
554
+
555
+ it 'has a hook that is called before setting a value that has been passed by a parent; return value is used in place of object' do
556
+
557
+ class ::CompositingHash::SubMockChildPreSet < ::CompositingHash
558
+
559
+ def child_pre_set_hook( key, object, is_insert = false )
560
+ return :some_other_value
561
+ end
562
+
563
+ end
564
+
565
+ cascading_composite_hash = ::CompositingHash::SubMockChildPreSet.new
566
+ sub_cascading_composite_hash = ::CompositingHash::SubMockChildPreSet.new( cascading_composite_hash )
567
+
568
+ cascading_composite_hash[ :some_key ] = :some_value
569
+
570
+ cascading_composite_hash.should == { :some_key => :some_value }
571
+ sub_cascading_composite_hash.should == { :some_key => :some_other_value }
572
+
573
+ end
574
+
575
+ #########################
576
+ # child_post_set_hook #
577
+ #########################
578
+
579
+ it 'has a hook that is called after setting a value passed by a parent' do
580
+
581
+ class ::CompositingHash::SubMockChildPostSet < ::CompositingHash
582
+
583
+ def child_post_set_hook( key, object, is_insert = false )
584
+ self[ :some_other_key ] = :some_other_value
585
+ end
586
+
587
+ end
588
+
589
+ cascading_composite_hash = ::CompositingHash::SubMockChildPostSet.new
590
+ sub_cascading_composite_hash = ::CompositingHash::SubMockChildPostSet.new( cascading_composite_hash )
591
+ cascading_composite_hash[ :some_key ] = :some_value
592
+
593
+ cascading_composite_hash.should == { :some_key => :some_value }
594
+ sub_cascading_composite_hash.should == { :some_key => :some_value,
595
+ :some_other_key => :some_other_value }
596
+
597
+ end
598
+
599
+ ###########################
600
+ # child_pre_delete_hook #
601
+ ###########################
602
+
603
+ it 'has a hook that is called before deleting an key that has been passed by a parent; if return value is false, delete does not occur' do
604
+
605
+ class ::CompositingHash::SubMockChildPreDelete < ::CompositingHash
606
+
607
+ def child_pre_delete_hook( key )
608
+ false
609
+ end
610
+
611
+ end
612
+
613
+ cascading_composite_hash = ::CompositingHash::SubMockChildPreDelete.new
614
+ sub_cascading_composite_hash = ::CompositingHash::SubMockChildPreDelete.new( cascading_composite_hash )
615
+ cascading_composite_hash[ :some_key ] = :some_value
616
+ cascading_composite_hash.delete( :some_key )
617
+
618
+ cascading_composite_hash.should == { }
619
+ sub_cascading_composite_hash.should == { :some_key => :some_value }
620
+
621
+ end
622
+
623
+ ############################
624
+ # child_post_delete_hook #
625
+ ############################
626
+
627
+ it 'has a hook that is called after deleting an key passed by a parent' do
628
+
629
+ class ::CompositingHash::SubMockChildPostDelete < ::CompositingHash
630
+
631
+ def child_post_delete_hook( key, object )
632
+ delete( :some_other_key )
633
+ end
634
+
635
+ end
636
+
637
+ cascading_composite_hash = ::CompositingHash::SubMockChildPostDelete.new
638
+ sub_cascading_composite_hash = ::CompositingHash::SubMockChildPostDelete.new( cascading_composite_hash )
639
+ cascading_composite_hash[ :some_key ] = :some_value
640
+ sub_cascading_composite_hash[ :some_other_key ] = :some_other_value
641
+ cascading_composite_hash.delete( :some_key )
642
+
643
+ cascading_composite_hash.should == { }
644
+ sub_cascading_composite_hash.should == { }
645
+
646
+ end
647
+
648
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: compositing-hash
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.15
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Asher
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-29 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: hooked-hash
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: An implementation of Hash that permits chaining, where children inherit
31
+ changes to parent and where parent settings can be overridden in children.
32
+ email: asher@ridiculouspower.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - lib/compositing-hash/CompositingHash.rb
38
+ - lib/compositing-hash.rb
39
+ - spec/CompositingHash_spec.rb
40
+ - README.md
41
+ - README.rdoc
42
+ homepage: http://rubygems.org/gems/compositing-hash
43
+ licenses: []
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubyforge_project: compositing-hash
62
+ rubygems_version: 1.8.23
63
+ signing_key:
64
+ specification_version: 3
65
+ summary: Provides CompositingHash.
66
+ test_files: []
67
+ has_rdoc: