hash-hooked 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+
2
+ == 6/15/2012
3
+
4
+ Initial release - split from compositing-hash.
5
+
6
+ == 6/30/2012
7
+
8
+ Renamed from hooked-hash to hash-hooked. File schema updated to reflect gem name.
@@ -0,0 +1,58 @@
1
+ # Hooked Hash #
2
+
3
+ http://rubygems.org/gems/hash-hooked
4
+
5
+ # Description #
6
+
7
+ Provides ::Hash::Hooked and ::HookedHash.
8
+
9
+ # Summary #
10
+
11
+ A subclass of Hash that offers event hooks for pre-set/pre-delete, set/delete. ::HookedHash offers implicit reference to a configuration instance.
12
+
13
+ # Install #
14
+
15
+ * sudo gem install hash-hooked
16
+
17
+ # Usage #
18
+
19
+ Provides methods that can be overridden that will be called during every corresponding event:
20
+
21
+ * pre_set_hook
22
+ * post_set_hook
23
+ * pre_get_hook
24
+ * post_get_hook
25
+ * pre_delete_hook
26
+ * post_delete_hook
27
+
28
+ As a result, several internal perform methods have been created:
29
+
30
+ * perform_set_between_hooks
31
+ * perform_delete_between_hooks
32
+
33
+ Also provides methods corresponding to each already-existing method + '_without_hooks', which causes methods to bypass hooks.
34
+
35
+ # License #
36
+
37
+ (The MIT License)
38
+
39
+ Copyright (c) Asher
40
+
41
+ Permission is hereby granted, free of charge, to any person obtaining
42
+ a copy of this software and associated documentation files (the
43
+ 'Software'), to deal in the Software without restriction, including
44
+ without limitation the rights to use, copy, modify, merge, publish,
45
+ distribute, sublicense, and/or sell copies of the Software, and to
46
+ permit persons to whom the Software is furnished to do so, subject to
47
+ the following conditions:
48
+
49
+ The above copyright notice and this permission notice shall be
50
+ included in all copies or substantial portions of the Software.
51
+
52
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
53
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
54
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
55
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
56
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
57
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
58
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,2 @@
1
+
2
+ require_relative 'hash/hooked.rb'
@@ -0,0 +1,29 @@
1
+
2
+ require 'identifies_as'
3
+
4
+ # namespaces that have to be declared ahead of time for proper load order
5
+ require_relative './namespaces'
6
+
7
+ # source file requires
8
+ require_relative './requires.rb'
9
+
10
+ class ::Hash::Hooked < ::Hash
11
+
12
+ # Alias to original :[]= method. Used to perform actual set between hooks.
13
+ # @param [Object] key Key where object is to be stored.
14
+ # @param [Object] object Element being stored.
15
+ # @return [Object] Element returned.
16
+ alias_method :perform_set_between_hooks, :store
17
+
18
+ # Alias to original :delete method. Used to perform actual delete between hooks.
19
+ # @param [Object] key Key where object is to be stored.
20
+ # @return [Object] Element returned.
21
+ alias_method :perform_delete_between_hooks, :delete
22
+
23
+ # Alias to original :merge method. Used to perform actual merge between hooks.
24
+ # @return [Object] Self.
25
+ alias_method :perform_merge_between_hooks!, :merge!
26
+
27
+ include ::Hash::Hooked::HashInterface
28
+
29
+ end
@@ -0,0 +1,527 @@
1
+
2
+ module ::Hash::Hooked::HashInterface
3
+
4
+ instances_identify_as!( ::Hash::Hooked )
5
+
6
+ ###################################### Subclass Hooks ##########################################
7
+
8
+ ##################
9
+ # pre_set_hook #
10
+ ##################
11
+
12
+ # A hook that is called before setting a value; return value is used in place of object.
13
+ # @param [Object] key Key where object is to be stored.
14
+ # @param [Object] object Element being stored.
15
+ # @return [true,false] Return value is used in place of object.
16
+ def pre_set_hook( key, object )
17
+
18
+ return object
19
+
20
+ end
21
+
22
+ ###################
23
+ # post_set_hook #
24
+ ###################
25
+
26
+ # A hook that is called after setting a value.
27
+ # @param [Object] key Key where object is to be stored.
28
+ # @param [Object] object Element being stored.
29
+ # @return [Object] Ignored.
30
+ def post_set_hook( key, object )
31
+
32
+ return object
33
+
34
+ end
35
+
36
+ ##################
37
+ # pre_get_hook #
38
+ ##################
39
+
40
+ # A hook that is called before getting a value; if return value is false, get does not occur.
41
+ # @param [Object] key Key where object is to be stored.
42
+ # @return [true,false] If return value is false, get does not occur.
43
+ def pre_get_hook( key )
44
+
45
+ return true
46
+
47
+ end
48
+
49
+ ###################
50
+ # post_get_hook #
51
+ ###################
52
+
53
+ # A hook that is called after getting a value.
54
+ # @param [Object] key Key where object is to be stored.
55
+ # @param [Object] object Element being stored.
56
+ # @return [Object] Object returned in place of get result.
57
+ def post_get_hook( key, object )
58
+
59
+ return object
60
+
61
+ end
62
+
63
+ #####################
64
+ # pre_delete_hook #
65
+ #####################
66
+
67
+ # A hook that is called before deleting a value; if return value is false, delete does not occur.
68
+ # @param [Object] key Key where object is to be stored.
69
+ # @return [true,false] If return value is false, delete does not occur.
70
+ def pre_delete_hook( key )
71
+
72
+ return true
73
+
74
+ end
75
+
76
+ ######################
77
+ # post_delete_hook #
78
+ ######################
79
+
80
+ # A hook that is called after deleting a value.
81
+ # @param [Object] key Key where object is to be stored.
82
+ # @param [Object] object Element deleted.
83
+ # @return [Object] Object returned in place of delete result.
84
+ def post_delete_hook( key, object )
85
+
86
+ return object
87
+
88
+ end
89
+
90
+ ##################################### Self Management ##########################################
91
+
92
+ ########
93
+ # [] #
94
+ ########
95
+
96
+ def []( key )
97
+
98
+ object = nil
99
+
100
+ if @without_hooks
101
+ pre_get_hook_result = true
102
+ else
103
+ pre_get_hook_result = pre_get_hook( key )
104
+ end
105
+
106
+ if pre_get_hook_result
107
+
108
+ object = super( key )
109
+
110
+ unless @without_hooks
111
+ object = post_get_hook( key, object )
112
+ end
113
+
114
+ end
115
+
116
+ return object
117
+
118
+ end
119
+
120
+ #######################
121
+ # get_without_hooks #
122
+ #######################
123
+
124
+ # Alias to :[] that bypasses hooks.
125
+ # @param [Object] key Key where object is to be stored.
126
+ # @return [Object] Element returned.
127
+ def get_without_hooks( key )
128
+
129
+ @without_hooks = true
130
+
131
+ object = self[ key ]
132
+
133
+ @without_hooks = false
134
+
135
+ return object
136
+
137
+ end
138
+
139
+ #########
140
+ # []= #
141
+ #########
142
+
143
+ def []=( key, object )
144
+
145
+ unless @without_hooks
146
+ object = pre_set_hook( key, object )
147
+ end
148
+
149
+ perform_set_between_hooks( key, object )
150
+
151
+ unless @without_hooks
152
+ object = post_set_hook( key, object )
153
+ end
154
+
155
+ return object
156
+
157
+ end
158
+
159
+ alias_method :store, :[]=
160
+
161
+ #########################
162
+ # store_without_hooks #
163
+ #########################
164
+
165
+ # Alias to :[]= that bypasses hooks.
166
+ # @param [Object] key Key where object is to be stored.
167
+ # @param [Object] object Element being set.
168
+ # @return [Object] Element returned.
169
+ def store_without_hooks( key, object )
170
+
171
+ @without_hooks = true
172
+
173
+ self[ key ] = object
174
+
175
+ @without_hooks = false
176
+
177
+ return object
178
+
179
+ end
180
+
181
+ ############
182
+ # delete #
183
+ ############
184
+
185
+ def delete( key )
186
+
187
+ object = nil
188
+
189
+ if @without_hooks
190
+ pre_delete_result = true
191
+ else
192
+ pre_delete_result = pre_delete_hook( key )
193
+ end
194
+
195
+ if pre_delete_result
196
+
197
+ object = perform_delete_between_hooks( key )
198
+
199
+ unless @without_hooks
200
+ object = post_delete_hook( key, object )
201
+ end
202
+
203
+ end
204
+
205
+ return object
206
+
207
+ end
208
+
209
+ ##########################
210
+ # delete_without_hooks #
211
+ ##########################
212
+
213
+ # Alias to :delete that bypasses hooks.
214
+ # @param [Object] object Element being deleted.
215
+ # @return [Object] Element returned.
216
+ def delete_without_hooks( key )
217
+
218
+ @without_hooks = true
219
+
220
+ object = delete( key )
221
+
222
+ @without_hooks = false
223
+
224
+ return object
225
+
226
+ end
227
+
228
+ ###############
229
+ # delete_if #
230
+ ###############
231
+
232
+ def delete_if
233
+
234
+ return to_enum unless block_given?
235
+
236
+ indexes = [ ]
237
+
238
+ self.each do |this_key, this_object|
239
+ if yield( this_key, this_object )
240
+ delete( this_key )
241
+ end
242
+ end
243
+
244
+ return self
245
+
246
+ end
247
+
248
+ #############################
249
+ # delete_if_without_hooks #
250
+ #############################
251
+
252
+ # Alias to :delete_if that bypasses hooks.
253
+ # @yield Block passed to :delete_if.
254
+ # @return [Object] Deleted element.
255
+ def delete_if_without_hooks( & block )
256
+
257
+ @without_hooks = true
258
+
259
+ delete_if( & block )
260
+
261
+ @without_hooks = false
262
+
263
+ end
264
+
265
+ #############
266
+ # reject! #
267
+ #############
268
+
269
+ def reject!
270
+
271
+ return to_enum unless block_given?
272
+
273
+ return_value = nil
274
+
275
+ self.each do |this_key, this_object|
276
+ if yield( this_key, this_object )
277
+ delete( this_key )
278
+ return_value = self
279
+ end
280
+ end
281
+
282
+ return return_value
283
+
284
+ end
285
+
286
+ ###########################
287
+ # reject_without_hooks! #
288
+ ###########################
289
+
290
+ # Alias to :reject that bypasses hooks.
291
+ # @yield Block passed to :keep_if.
292
+ # @return [Object] Self.
293
+ def reject_without_hooks!
294
+
295
+ @without_hooks = true
296
+
297
+ return_value = reject!( & block )
298
+
299
+ @without_hooks = false
300
+
301
+ return return_value
302
+
303
+ end
304
+
305
+ #############
306
+ # keep_if #
307
+ #############
308
+
309
+ def keep_if
310
+
311
+ return to_enum unless block_given?
312
+
313
+ indexes = [ ]
314
+
315
+ self.each do |this_key, this_object|
316
+ unless yield( this_key, this_object )
317
+ delete( this_key )
318
+ end
319
+ end
320
+
321
+ return self
322
+
323
+
324
+ end
325
+
326
+ ###########################
327
+ # keep_if_without_hooks #
328
+ ###########################
329
+
330
+ # Alias to :keep_if that bypasses hooks.
331
+ # @yield Block passed to :keep_if.
332
+ # @return [Object] Deleted element.
333
+ def keep_if_without_hooks( & block )
334
+
335
+ @without_hooks = true
336
+
337
+ keep_if( & block )
338
+
339
+ @without_hooks = false
340
+
341
+ return self
342
+
343
+ end
344
+
345
+ #############
346
+ # select! #
347
+ #############
348
+
349
+ def select!
350
+
351
+ return to_enum unless block_given?
352
+
353
+ return_value = nil
354
+
355
+ self.each do |this_key, this_object|
356
+ unless yield( this_key, this_object )
357
+ delete( this_key )
358
+ return_value = self
359
+ end
360
+ end
361
+
362
+ return return_value
363
+
364
+ end
365
+
366
+ ###########################
367
+ # select_without_hooks! #
368
+ ###########################
369
+
370
+ # Alias to :select that bypasses hooks.
371
+ # @yield Block passed to :select!.
372
+ # @return [Object] Self.
373
+ def select_without_hooks!( & block )
374
+
375
+ @without_hooks = true
376
+
377
+ return_value = select!( & block )
378
+
379
+ @without_hooks = false
380
+
381
+ return return_value
382
+
383
+ end
384
+
385
+ ############
386
+ # merge! #
387
+ # update #
388
+ ############
389
+
390
+ def merge!( other_hash )
391
+
392
+ other_hash.each do |this_key, this_object|
393
+ if @compositing_proc
394
+ self[ this_key ] = @compositing_proc.call( self, this_key, this_object )
395
+ else
396
+ self[ this_key ] = this_object
397
+ end
398
+ end
399
+
400
+ return self
401
+
402
+ end
403
+
404
+ alias_method :update, :merge!
405
+
406
+ ##########################
407
+ # merge_without_hooks! #
408
+ # update_without_hooks #
409
+ ##########################
410
+
411
+ # Alias to :merge! that bypasses hooks.
412
+ # @return [Object] Self.
413
+ def merge_without_hooks!
414
+
415
+ @without_hooks = true
416
+
417
+ merge!( other_hash )
418
+
419
+ @without_hooks = false
420
+
421
+ return self
422
+
423
+ end
424
+
425
+ alias_method :update_without_hooks, :merge_without_hooks!
426
+
427
+ #############
428
+ # replace #
429
+ #############
430
+
431
+ def replace( other_hash )
432
+
433
+ # clear current values
434
+ clear
435
+
436
+ # merge replacement settings
437
+ merge!( other_hash )
438
+
439
+ return self
440
+
441
+ end
442
+
443
+ ###########################
444
+ # replace_without_hooks #
445
+ ###########################
446
+
447
+ # Alias to :replace that bypasses hooks.
448
+ # @param [Array] other_array Other array to replace self with.
449
+ # @return [Object] Self.
450
+ def replace_without_hooks( other_hash )
451
+
452
+ @without_hooks = true
453
+
454
+ replace( other_hash )
455
+
456
+ @without_hooks = false
457
+
458
+ end
459
+
460
+ ###########
461
+ # shift #
462
+ ###########
463
+
464
+ def shift
465
+
466
+ object = nil
467
+
468
+ unless empty?
469
+ last_key = first[ 0 ]
470
+ object = delete( last_key )
471
+ end
472
+
473
+ return [ last_key, object ]
474
+
475
+ end
476
+
477
+ #########################
478
+ # shift_without_hooks #
479
+ #########################
480
+
481
+ # Alias to :shift that bypasses hooks.
482
+ # @return [Object] Self.
483
+ def shift_without_hooks
484
+
485
+ @without_hooks = true
486
+
487
+ object = shift
488
+
489
+ @without_hooks = false
490
+
491
+ return object
492
+
493
+ end
494
+
495
+ ###########
496
+ # clear #
497
+ ###########
498
+
499
+ def clear
500
+
501
+ keys.each do |this_key|
502
+ delete( this_key )
503
+ end
504
+
505
+ return self
506
+
507
+ end
508
+
509
+ #########################
510
+ # clear_without_hooks #
511
+ #########################
512
+
513
+ # Alias to :clear that bypasses hooks.
514
+ # @return [Object] Self.
515
+ def clear_without_hooks
516
+
517
+ @without_hooks = true
518
+
519
+ clear
520
+
521
+ @without_hooks = false
522
+
523
+ return self
524
+
525
+ end
526
+
527
+ end
@@ -0,0 +1,6 @@
1
+
2
+ class ::Hash::Hooked < ::Hash
3
+ end
4
+
5
+ class ::HookedHash < ::Hash::Hooked
6
+ end
@@ -0,0 +1,26 @@
1
+
2
+ basepath = 'hooked'
3
+
4
+ files = [
5
+
6
+ 'hash_interface'
7
+
8
+ ]
9
+
10
+ second_basepath = '../hooked_hash'
11
+
12
+ second_files = [
13
+
14
+ 'hash_interface'
15
+
16
+ ]
17
+
18
+ files.each do |this_file|
19
+ require_relative( File.join( basepath, this_file ) + '.rb' )
20
+ end
21
+ second_files.each do |this_file|
22
+ require_relative( File.join( second_basepath, this_file ) + '.rb' )
23
+ end
24
+
25
+ require_relative( basepath + '.rb' )
26
+ require_relative( second_basepath + '.rb' )
@@ -0,0 +1,2 @@
1
+
2
+ require_relative '../hash/hooked.rb'
@@ -0,0 +1,6 @@
1
+
2
+ class ::HookedHash < ::Hash::Hooked
3
+
4
+ include ::HookedHash::Interface
5
+
6
+ end
@@ -0,0 +1,29 @@
1
+
2
+ module ::HookedHash::Interface
3
+
4
+ instances_identify_as!( ::HookedHash )
5
+
6
+ ################
7
+ # initialize #
8
+ ################
9
+
10
+ # Initialize with reference a configuration instance.
11
+ # @param [Object] object Object that HookedHash instance is attached to, primarily useful for
12
+ # reference from hooks.
13
+ # @param [Hash<Object>] args Parameters passed through super to Hash#initialize.
14
+ # @return [true,false] Whether receiver identifies as object.
15
+ def initialize( configuration_instance = nil, *args )
16
+
17
+ @configuration_instance = configuration_instance
18
+
19
+ super( *args )
20
+
21
+ end
22
+
23
+ ############################
24
+ # configuration_instance #
25
+ ############################
26
+
27
+ attr_accessor :configuration_instance
28
+
29
+ end
@@ -0,0 +1,368 @@
1
+
2
+ require_relative '../../lib/hash-hooked.rb'
3
+
4
+ describe ::Hash::Hooked do
5
+
6
+ ################
7
+ # initialize #
8
+ ################
9
+
10
+ it 'can add initialize with an ancestor, inheriting its values and linking to it as a child' do
11
+
12
+ cascading_composite_hash = ::Hash::Hooked.new
13
+
14
+ cascading_composite_hash.instance_variable_get( :@parent_composite_object ).should == nil
15
+ cascading_composite_hash.should == {}
16
+ cascading_composite_hash[ :A ] = 1
17
+ cascading_composite_hash[ :B ] = 2
18
+ cascading_composite_hash[ :C ] = 3
19
+ cascading_composite_hash[ :D ] = 4
20
+ cascading_composite_hash.should == { :A => 1,
21
+ :B => 2,
22
+ :C => 3,
23
+ :D => 4 }
24
+
25
+ end
26
+
27
+ #########
28
+ # []= #
29
+ #########
30
+
31
+ it 'can add elements' do
32
+
33
+ cascading_composite_hash = ::Hash::Hooked.new
34
+
35
+ cascading_composite_hash[ :some_setting ] = :some_value
36
+ cascading_composite_hash.should == { :some_setting => :some_value }
37
+
38
+ cascading_composite_hash[ :other_setting ] = :some_value
39
+ cascading_composite_hash.should == { :some_setting => :some_value,
40
+ :other_setting => :some_value }
41
+
42
+ cascading_composite_hash.method( :[]= ).should == cascading_composite_hash.method( :store )
43
+
44
+ end
45
+
46
+ ############
47
+ # delete #
48
+ ############
49
+
50
+ it 'can delete elements' do
51
+
52
+ cascading_composite_hash = ::Hash::Hooked.new
53
+
54
+ cascading_composite_hash.store( :some_setting, :some_value )
55
+ cascading_composite_hash.should == { :some_setting => :some_value }
56
+
57
+ cascading_composite_hash.store( :other_setting, :some_value )
58
+ cascading_composite_hash.should == { :some_setting => :some_value,
59
+ :other_setting => :some_value }
60
+
61
+ cascading_composite_hash.delete( :some_setting )
62
+ cascading_composite_hash.should == { :other_setting => :some_value }
63
+
64
+ end
65
+
66
+ ###############
67
+ # delete_if #
68
+ ###############
69
+
70
+ it 'can delete elements with a block' do
71
+
72
+ cascading_composite_hash = ::Hash::Hooked.new
73
+
74
+ cascading_composite_hash.store( :some_setting, :some_value )
75
+ cascading_composite_hash.should == { :some_setting => :some_value }
76
+
77
+ cascading_composite_hash.store( :other_setting, :some_value )
78
+ cascading_composite_hash.should == { :some_setting => :some_value,
79
+ :other_setting => :some_value }
80
+ cascading_composite_hash.delete_if do |key, value|
81
+ key == :some_setting
82
+ end
83
+ cascading_composite_hash.should == { :other_setting => :some_value }
84
+
85
+ end
86
+
87
+ #############
88
+ # reject! #
89
+ #############
90
+
91
+ it 'can delete elements with a block' do
92
+
93
+ cascading_composite_hash = ::Hash::Hooked.new
94
+
95
+ cascading_composite_hash.store( :some_setting, :some_value )
96
+ cascading_composite_hash.should == { :some_setting => :some_value }
97
+
98
+ cascading_composite_hash.store( :other_setting, :some_value )
99
+ cascading_composite_hash.should == { :some_setting => :some_value,
100
+ :other_setting => :some_value }
101
+ cascading_composite_hash.reject! do |key, value|
102
+ key == :some_setting
103
+ end
104
+ cascading_composite_hash.should == { :other_setting => :some_value }
105
+
106
+ end
107
+
108
+ #############
109
+ # keep_if #
110
+ #############
111
+
112
+ it 'can keep elements with a block' do
113
+
114
+ cascading_composite_hash = ::Hash::Hooked.new
115
+
116
+ cascading_composite_hash.store( :some_setting, :some_value )
117
+ cascading_composite_hash.should == { :some_setting => :some_value }
118
+
119
+ cascading_composite_hash.store( :other_setting, :some_value )
120
+ cascading_composite_hash.should == { :some_setting => :some_value,
121
+ :other_setting => :some_value }
122
+ cascading_composite_hash.keep_if do |key, value|
123
+ key != :some_setting
124
+ end
125
+ cascading_composite_hash.should == { :other_setting => :some_value }
126
+
127
+ end
128
+
129
+ #############
130
+ # select! #
131
+ #############
132
+
133
+ it 'can keep elements with a block' do
134
+
135
+ cascading_composite_hash = ::Hash::Hooked.new
136
+
137
+ cascading_composite_hash.store( :some_setting, :some_value )
138
+ cascading_composite_hash.should == { :some_setting => :some_value }
139
+
140
+ cascading_composite_hash.store( :other_setting, :some_value )
141
+ cascading_composite_hash.should == { :some_setting => :some_value,
142
+ :other_setting => :some_value }
143
+ cascading_composite_hash.select! do |key, value|
144
+ key != :some_setting
145
+ end
146
+ cascading_composite_hash.should == { :other_setting => :some_value }
147
+
148
+ end
149
+
150
+ ############
151
+ # merge! #
152
+ # update #
153
+ ############
154
+
155
+ it 'can merge from another hash' do
156
+
157
+ cascading_composite_hash = ::Hash::Hooked.new
158
+
159
+ cascading_composite_hash.merge!( :some_setting => :some_value )
160
+ cascading_composite_hash.should == { :some_setting => :some_value }
161
+ cascading_composite_hash.merge!( :other_setting => :some_value )
162
+ cascading_composite_hash.should == { :some_setting => :some_value,
163
+ :other_setting => :some_value }
164
+
165
+ end
166
+
167
+ #############
168
+ # replace #
169
+ #############
170
+
171
+ it 'can replace existing elements with others' do
172
+
173
+ cascading_composite_hash = ::Hash::Hooked.new
174
+
175
+ cascading_composite_hash.replace( :some_setting => :some_value )
176
+ cascading_composite_hash.should == { :some_setting => :some_value }
177
+ cascading_composite_hash.replace( :other_setting => :some_value )
178
+ cascading_composite_hash.should == { :other_setting => :some_value }
179
+
180
+ end
181
+
182
+ ###########
183
+ # shift #
184
+ ###########
185
+
186
+ it 'can shift the first element' do
187
+
188
+ cascading_composite_hash = ::Hash::Hooked.new
189
+
190
+ cascading_composite_hash.store( :some_setting, :some_value )
191
+ cascading_composite_hash.should == { :some_setting => :some_value }
192
+ cascading_composite_hash.store( :other_setting, :some_value )
193
+ cascading_composite_hash.should == { :some_setting => :some_value,
194
+ :other_setting => :some_value }
195
+ cascading_composite_hash.shift
196
+ cascading_composite_hash.should == { :other_setting => :some_value }
197
+
198
+ end
199
+
200
+ ###########
201
+ # clear #
202
+ ###########
203
+
204
+ it 'can clear, causing present elements to be excluded' do
205
+
206
+ cascading_composite_hash = ::Hash::Hooked.new
207
+
208
+ cascading_composite_hash.store( :some_setting, :some_value )
209
+ cascading_composite_hash.should == { :some_setting => :some_value }
210
+ cascading_composite_hash.store( :other_setting, :some_value )
211
+ cascading_composite_hash.should == { :some_setting => :some_value,
212
+ :other_setting => :some_value }
213
+ cascading_composite_hash.clear
214
+ cascading_composite_hash.should == { }
215
+ cascading_composite_hash.store( :other_setting, :some_value )
216
+ cascading_composite_hash.should == { :other_setting => :some_value }
217
+
218
+ end
219
+
220
+ ##################
221
+ # pre_set_hook #
222
+ ##################
223
+
224
+ it 'has a hook that is called before setting a value; return value is used in place of object' do
225
+
226
+ class ::Hash::Hooked::SubMockPreSet < ::Hash::Hooked
227
+
228
+ def pre_set_hook( key, object, is_insert = false )
229
+ return :some_other_value
230
+ end
231
+
232
+ end
233
+
234
+ cascading_composite_hash = ::Hash::Hooked::SubMockPreSet.new
235
+
236
+ cascading_composite_hash[ :some_key ] = :some_value
237
+
238
+ cascading_composite_hash.should == { :some_key => :some_other_value }
239
+
240
+ end
241
+
242
+ ###################
243
+ # post_set_hook #
244
+ ###################
245
+
246
+ it 'has a hook that is called after setting a value' do
247
+
248
+ class ::Hash::Hooked::SubMockPostSet < ::Hash::Hooked
249
+
250
+ def post_set_hook( key, object, is_insert = false )
251
+ unless key == :some_other_key
252
+ self[ :some_other_key ] = :some_other_value
253
+ end
254
+ return object
255
+ end
256
+
257
+ end
258
+
259
+ cascading_composite_hash = ::Hash::Hooked::SubMockPostSet.new
260
+
261
+ cascading_composite_hash[ :some_key ] = :some_value
262
+
263
+ cascading_composite_hash.should == { :some_key => :some_value,
264
+ :some_other_key => :some_other_value }
265
+
266
+ end
267
+
268
+ ##################
269
+ # pre_get_hook #
270
+ ##################
271
+
272
+ it 'has a hook that is called before getting a value; if return value is false, get does not occur' do
273
+
274
+ class ::Hash::Hooked::SubMockPreGet < ::Hash::Hooked
275
+
276
+ def pre_get_hook( key )
277
+ return false
278
+ end
279
+
280
+ end
281
+
282
+ cascading_composite_hash = ::Hash::Hooked::SubMockPreGet.new
283
+
284
+ cascading_composite_hash[ :some_key ] = :some_value
285
+ cascading_composite_hash[ :some_key ].should == nil
286
+
287
+ cascading_composite_hash.should == { :some_key => :some_value }
288
+
289
+ end
290
+
291
+ ###################
292
+ # post_get_hook #
293
+ ###################
294
+
295
+ it 'has a hook that is called after getting a value' do
296
+
297
+ class ::Hash::Hooked::SubMockPostGet < ::Hash::Hooked
298
+
299
+ def post_get_hook( key, object )
300
+ self[ :some_other_key ] = :some_other_value
301
+ return object
302
+ end
303
+
304
+ end
305
+
306
+ cascading_composite_hash = ::Hash::Hooked::SubMockPostGet.new
307
+
308
+ cascading_composite_hash[ :some_key ] = :some_value
309
+
310
+ cascading_composite_hash.should == { :some_key => :some_value }
311
+
312
+ cascading_composite_hash[ :some_key ].should == :some_value
313
+
314
+ cascading_composite_hash.should == { :some_key => :some_value,
315
+ :some_other_key => :some_other_value }
316
+
317
+ end
318
+
319
+ #####################
320
+ # pre_delete_hook #
321
+ #####################
322
+
323
+ it 'has a hook that is called before deleting an key; if return value is false, delete does not occur' do
324
+
325
+ class ::Hash::Hooked::SubMockPreDelete < ::Hash::Hooked
326
+
327
+ def pre_delete_hook( key )
328
+ return false
329
+ end
330
+
331
+ end
332
+
333
+ cascading_composite_hash = ::Hash::Hooked::SubMockPreDelete.new
334
+
335
+ cascading_composite_hash[ :some_key ] = :some_value
336
+ cascading_composite_hash.delete( :some_key )
337
+
338
+ cascading_composite_hash.should == { :some_key => :some_value }
339
+
340
+ end
341
+
342
+ ######################
343
+ # post_delete_hook #
344
+ ######################
345
+
346
+ it 'has a hook that is called after deleting an key' do
347
+
348
+ class ::Hash::Hooked::SubMockPostDelete < ::Hash::Hooked
349
+
350
+ def post_delete_hook( key, object )
351
+ unless key == :some_other_key
352
+ delete( :some_other_key )
353
+ end
354
+ end
355
+
356
+ end
357
+
358
+ cascading_composite_hash = ::Hash::Hooked::SubMockPostDelete.new
359
+
360
+ cascading_composite_hash[ :some_key ] = :some_value
361
+ cascading_composite_hash[ :some_other_key ] = :some_other_value
362
+ cascading_composite_hash.delete( :some_key )
363
+
364
+ cascading_composite_hash.should == { }
365
+
366
+ end
367
+
368
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hash-hooked
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Asher
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: identifies_as
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: A subclass of Hash that offers event hooks for pre-set/pre-delete, set/delete.
31
+ ::HookedHash offers implicit reference to a configuration instance.
32
+ email: asher@ridiculouspower.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - lib/hash/hooked/hash_interface.rb
38
+ - lib/hash/hooked.rb
39
+ - lib/hash/namespaces.rb
40
+ - lib/hash/requires.rb
41
+ - lib/hash-hooked.rb
42
+ - lib/hooked/hash.rb
43
+ - lib/hooked_hash/hash_interface.rb
44
+ - lib/hooked_hash.rb
45
+ - spec/hash/hooked_spec.rb
46
+ - README.md
47
+ - CHANGELOG.rdoc
48
+ homepage: http://rubygems.org/gems/hash-hooked
49
+ licenses: []
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project: hash-hooked
68
+ rubygems_version: 1.8.23
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Provides ::Hash::Hooked and ::HookedHash.
72
+ test_files: []
73
+ has_rdoc: