hash-hooked 1.0.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.
@@ -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: