extlib 0.9.2 → 0.9.3
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.
Potentially problematic release.
This version of extlib might be problematic. Click here for more details.
- data/.autotest +21 -0
- data/History.txt +1 -0
- data/Manifest.txt +29 -0
- data/README.txt +3 -0
- data/Rakefile +145 -0
- data/lib/extlib/hook.rb +80 -27
- data/lib/extlib/lazy_array.rb +4 -2
- data/lib/extlib/module.rb +31 -13
- data/lib/extlib/object.rb +1 -1
- data/lib/extlib/pooling.rb +47 -41
- data/lib/extlib/version.rb +3 -0
- data/spec/hook_spec.rb +332 -31
- data/spec/lazy_array_spec.rb +22 -8
- data/spec/module_spec.rb +33 -11
- data/spec/object_spec.rb +1 -1
- data/spec/pooling_spec.rb +3 -7
- data/tasks/hoe.rb +39 -0
- metadata +28 -16
- data/README +0 -0
data/lib/extlib/object.rb
CHANGED
data/lib/extlib/pooling.rb
CHANGED
@@ -10,7 +10,7 @@ module Extlib
|
|
10
10
|
# because instances are keeped in memory reused.
|
11
11
|
#
|
12
12
|
# Classes that include Pooling module have re-defined new
|
13
|
-
# method that returns instances
|
13
|
+
# method that returns instances acquired from pool.
|
14
14
|
#
|
15
15
|
# Term resource is used for any type of poolable objects
|
16
16
|
# and should NOT be thought as DataMapper Resource or
|
@@ -31,13 +31,14 @@ module Extlib
|
|
31
31
|
loop do
|
32
32
|
lock.synchronize do
|
33
33
|
pools.each do |pool|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
# This is a useful check, but non-essential, and right now it breaks lots of stuff.
|
35
|
+
# if pool.expired?
|
36
|
+
pool.lock.synchronize do
|
37
|
+
if pool.reserved_count == 0
|
38
|
+
pool.dispose
|
39
39
|
end
|
40
40
|
end
|
41
|
+
# end
|
41
42
|
end
|
42
43
|
end
|
43
44
|
sleep(scavenger_interval)
|
@@ -95,17 +96,13 @@ module Extlib
|
|
95
96
|
end
|
96
97
|
|
97
98
|
def self.pool_size
|
98
|
-
|
99
|
-
end
|
100
|
-
|
101
|
-
def self.scavenge_interval
|
102
|
-
10
|
99
|
+
8
|
103
100
|
end
|
104
101
|
end
|
105
102
|
end
|
106
103
|
|
107
104
|
def release
|
108
|
-
@__pool.release(self)
|
105
|
+
@__pool.release(self) unless @__pool.nil?
|
109
106
|
end
|
110
107
|
|
111
108
|
class Pool
|
@@ -118,9 +115,7 @@ module Extlib
|
|
118
115
|
@args = args
|
119
116
|
|
120
117
|
@available = []
|
121
|
-
@
|
122
|
-
|
123
|
-
Extlib::Pooling::append_pool(self)
|
118
|
+
@reserved_count = 0
|
124
119
|
end
|
125
120
|
|
126
121
|
def lock
|
@@ -135,15 +130,17 @@ module Extlib
|
|
135
130
|
instance = nil
|
136
131
|
|
137
132
|
lock.synchronize do
|
138
|
-
instance =
|
133
|
+
instance = acquire
|
139
134
|
end
|
140
135
|
|
136
|
+
Extlib::Pooling::append_pool(self)
|
137
|
+
|
141
138
|
if instance.nil?
|
142
139
|
# Account for the current thread, and the pool scavenger.
|
143
|
-
if ThreadGroup::Default.list.size == 2 && @
|
140
|
+
if ThreadGroup::Default.list.size == 2 && @reserved_count >= @max_size
|
144
141
|
raise ThreadStopError.new(size)
|
145
142
|
else
|
146
|
-
sleep(0.
|
143
|
+
sleep(0.05)
|
147
144
|
new
|
148
145
|
end
|
149
146
|
else
|
@@ -153,52 +150,62 @@ module Extlib
|
|
153
150
|
|
154
151
|
def release(instance)
|
155
152
|
lock.synchronize do
|
156
|
-
raise OrphanedObjectError.new(instance) unless @reserved.delete?(instance)
|
157
153
|
instance.instance_variable_set(:@__pool, nil)
|
154
|
+
@reserved_count -= 1
|
158
155
|
@available.push(instance)
|
159
156
|
end
|
160
157
|
nil
|
161
158
|
end
|
162
159
|
|
160
|
+
def delete(instance)
|
161
|
+
lock.synchronize do
|
162
|
+
instance.instance_variable_set(:@__pool, nil)
|
163
|
+
@reserved_count -= 1
|
164
|
+
end
|
165
|
+
nil
|
166
|
+
end
|
167
|
+
|
163
168
|
def size
|
164
|
-
@available.size + @
|
169
|
+
@available.size + @reserved_count
|
165
170
|
end
|
166
171
|
alias length size
|
167
172
|
|
168
173
|
def inspect
|
169
|
-
"#<Extlib::Pooling::Pool<#{@resource.name}> available=#{@available.size}
|
174
|
+
"#<Extlib::Pooling::Pool<#{@resource.name}> available=#{@available.size} reserved_count=#{@reserved_count}>"
|
170
175
|
end
|
171
176
|
|
172
177
|
def flush!
|
173
|
-
|
174
|
-
@available.each do |instance|
|
175
|
-
instance.dispose
|
176
|
-
end
|
177
|
-
@available.clear
|
178
|
-
end
|
178
|
+
@available.pop.dispose until @available.empty?
|
179
179
|
end
|
180
180
|
|
181
181
|
def dispose
|
182
|
+
flush!
|
182
183
|
@resource.__pools.delete(@args)
|
183
184
|
!Extlib::Pooling::pools.delete?(self).nil?
|
184
185
|
end
|
185
186
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
187
|
+
# Disabled temporarily.
|
188
|
+
#
|
189
|
+
# def expired?
|
190
|
+
# lock.synchronize do
|
191
|
+
# @available.each do |instance|
|
192
|
+
# if instance.instance_variable_get(:@__allocated_in_pool) + scavenge_interval < Time.now
|
193
|
+
# instance.dispose
|
194
|
+
# @available.delete(instance)
|
195
|
+
# end
|
196
|
+
# end
|
197
|
+
#
|
198
|
+
# size == 0
|
199
|
+
# end
|
200
|
+
# end
|
201
|
+
|
202
|
+
def reserved_count
|
203
|
+
@reserved_count
|
197
204
|
end
|
198
205
|
|
199
206
|
private
|
200
207
|
|
201
|
-
def
|
208
|
+
def acquire
|
202
209
|
instance = if !@available.empty?
|
203
210
|
@available.pop
|
204
211
|
elsif size < @max_size
|
@@ -211,7 +218,7 @@ module Extlib
|
|
211
218
|
instance
|
212
219
|
else
|
213
220
|
raise CrossPoolError.new(instance) if instance.instance_variable_get(:@__pool)
|
214
|
-
@
|
221
|
+
@reserved_count += 1
|
215
222
|
instance.instance_variable_set(:@__pool, self)
|
216
223
|
instance.instance_variable_set(:@__allocated_in_pool, Time.now)
|
217
224
|
instance
|
@@ -219,7 +226,6 @@ module Extlib
|
|
219
226
|
end
|
220
227
|
end
|
221
228
|
|
222
|
-
private
|
223
229
|
def self.scavenger_interval
|
224
230
|
60
|
225
231
|
end
|
data/spec/hook_spec.rb
CHANGED
@@ -124,6 +124,21 @@ describe Extlib::Hook do
|
|
124
124
|
@class.hookable!
|
125
125
|
@class.hookable?
|
126
126
|
end
|
127
|
+
|
128
|
+
it "should allow hooking methods that have single character names" do
|
129
|
+
@class.class_eval do
|
130
|
+
def self.a; end;
|
131
|
+
def self.b; end;
|
132
|
+
end
|
133
|
+
|
134
|
+
@class.before_class_method(:a) { omg! }
|
135
|
+
@class.before_class_method(:b) { hi2u! }
|
136
|
+
|
137
|
+
@class.should_receive(:omg!).once.ordered
|
138
|
+
@class.should_receive(:hi2u!).once.ordered
|
139
|
+
@class.a
|
140
|
+
@class.b
|
141
|
+
end
|
127
142
|
end
|
128
143
|
|
129
144
|
describe "for instance methods" do
|
@@ -217,6 +232,22 @@ describe Extlib::Hook do
|
|
217
232
|
inst.hookable = 'hello'
|
218
233
|
inst.hookable?
|
219
234
|
end
|
235
|
+
|
236
|
+
it "should allow hooking methods that have single character names" do
|
237
|
+
@class.class_eval do
|
238
|
+
def a; end;
|
239
|
+
def b; end;
|
240
|
+
end
|
241
|
+
|
242
|
+
@class.before(:a) { omg! }
|
243
|
+
@class.before(:b) { hi2u! }
|
244
|
+
|
245
|
+
inst = @class.new
|
246
|
+
inst.should_receive(:omg!).once.ordered
|
247
|
+
inst.should_receive(:hi2u!).once.ordered
|
248
|
+
inst.a
|
249
|
+
inst.b
|
250
|
+
end
|
220
251
|
end
|
221
252
|
|
222
253
|
end
|
@@ -337,21 +368,94 @@ describe Extlib::Hook do
|
|
337
368
|
@class.clakable
|
338
369
|
end
|
339
370
|
|
340
|
-
it
|
341
|
-
@class.class_eval
|
342
|
-
|
343
|
-
|
371
|
+
it "should not pass any of the hookable method's arguments if the hook block does not accept arguments" do
|
372
|
+
@class.class_eval do
|
373
|
+
def self.method_with_args(one, two, three); end;
|
374
|
+
before_class_method(:method_with_args) { hi_mom! }
|
375
|
+
end
|
376
|
+
|
377
|
+
@class.should_receive(:hi_mom!)
|
378
|
+
@class.method_with_args(1, 2, 3)
|
379
|
+
end
|
380
|
+
|
381
|
+
it "should not pass any of the hookable method's arguments if the hook method does not accept arguments" do
|
382
|
+
@class.class_eval do
|
383
|
+
def self.method_with_args(one, two, three); end;
|
384
|
+
def self.before_method_with_args; hi_mom!; end;
|
385
|
+
before_class_method(:method_with_args, :before_method_with_args)
|
386
|
+
end
|
387
|
+
|
388
|
+
@class.should_receive(:hi_mom!)
|
389
|
+
@class.method_with_args(1, 2, 3)
|
390
|
+
end
|
391
|
+
|
392
|
+
it "should not pass any of the hookable method's arguments if the hook is declared after it is registered and does not accept arguments" do
|
393
|
+
@class.class_eval do
|
394
|
+
def self.method_with_args(one, two, three); end;
|
395
|
+
before_class_method(:method_with_args, :before_method_with_args)
|
396
|
+
def self.before_method_with_args; hi_mom!; end;
|
397
|
+
end
|
398
|
+
|
399
|
+
@class.should_receive(:hi_mom!)
|
400
|
+
@class.method_with_args(1, 2, 3)
|
401
|
+
end
|
402
|
+
|
403
|
+
it "should not pass any of the hookable method's arguments if the hook has been re-defined not to accept arguments" do
|
404
|
+
@class.class_eval do
|
405
|
+
def self.method_with_args(one, two, three); end;
|
406
|
+
def self.before_method_with_args(one, two, three); hi_mom!; end;
|
407
|
+
before_class_method(:method_with_args, :before_method_with_args)
|
408
|
+
def self.before_method_with_args; hi_dad!; end;
|
409
|
+
end
|
410
|
+
|
411
|
+
@class.should_not_receive(:hi_mom1)
|
412
|
+
@class.should_receive(:hi_dad!)
|
413
|
+
@class.method_with_args(1, 2, 3)
|
414
|
+
end
|
415
|
+
|
416
|
+
it 'should pass the hookable method arguments to the hook method if the hook method takes arguments' do
|
417
|
+
@class.class_eval do
|
418
|
+
def self.hook_this(word, lol); end;
|
419
|
+
register_class_hooks(:hook_this)
|
420
|
+
def self.before_hook_this(word, lol); hi_mom!(word, lol); end;
|
421
|
+
before_class_method(:hook_this, :before_hook_this)
|
422
|
+
end
|
344
423
|
|
345
|
-
@class.should_receive(:
|
424
|
+
@class.should_receive(:hi_mom!).with("omg", "hi2u")
|
346
425
|
@class.hook_this("omg", "hi2u")
|
347
426
|
end
|
348
427
|
|
428
|
+
it "should pass the hookable method arguments to the hook block if the hook block takes arguments" do
|
429
|
+
@class.class_eval do
|
430
|
+
def self.method_with_args(word, lol); end;
|
431
|
+
before_class_method(:method_with_args) { |one, two| hi_mom!(one, two) }
|
432
|
+
end
|
433
|
+
|
434
|
+
@class.should_receive(:hi_mom!).with('omg', 'hi2u')
|
435
|
+
@class.method_with_args('omg', 'hi2u')
|
436
|
+
end
|
437
|
+
|
438
|
+
it 'should pass the hookable method arguments to the hook method if the hook method was re-defined to accept arguments' do
|
439
|
+
@class.class_eval do
|
440
|
+
def self.method_with_args(word, lol); end;
|
441
|
+
def self.before_method_with_args; hi_mom!; end;
|
442
|
+
before_class_method(:method_with_args, :before_method_with_args)
|
443
|
+
def self.before_method_with_args(word, lol); hi_dad!(word, lol); end;
|
444
|
+
end
|
445
|
+
|
446
|
+
@class.should_not_receive(:hi_mom!)
|
447
|
+
@class.should_receive(:hi_dad!).with("omg", "hi2u")
|
448
|
+
@class.method_with_args("omg", "hi2u")
|
449
|
+
end
|
450
|
+
|
349
451
|
it 'should work with glob arguments (or whatever you call em)' do
|
350
|
-
@class.class_eval
|
351
|
-
|
352
|
-
|
452
|
+
@class.class_eval do
|
453
|
+
def self.hook_this(*args); end;
|
454
|
+
def self.before_hook_this(*args); hi_mom!(*args); end;
|
455
|
+
before_class_method(:hook_this, :before_hook_this)
|
456
|
+
end
|
353
457
|
|
354
|
-
@class.should_receive(:
|
458
|
+
@class.should_receive(:hi_mom!).with("omg", "hi2u", "lolercoaster")
|
355
459
|
@class.hook_this("omg", "hi2u", "lolercoaster")
|
356
460
|
end
|
357
461
|
|
@@ -364,6 +468,19 @@ describe Extlib::Hook do
|
|
364
468
|
@class.should_receive(:last!).once.ordered
|
365
469
|
@class.clakable
|
366
470
|
end
|
471
|
+
|
472
|
+
it 'should be able to use private methods as hooks' do
|
473
|
+
@class.class_eval do
|
474
|
+
class << self
|
475
|
+
private
|
476
|
+
def nike; doit!; end;
|
477
|
+
end
|
478
|
+
before_class_method(:clakable, :nike)
|
479
|
+
end
|
480
|
+
|
481
|
+
@class.should_receive(:doit!)
|
482
|
+
@class.clakable
|
483
|
+
end
|
367
484
|
end
|
368
485
|
|
369
486
|
describe "for instance methods" do
|
@@ -384,23 +501,113 @@ describe Extlib::Hook do
|
|
384
501
|
inst.hookable
|
385
502
|
end
|
386
503
|
|
387
|
-
it
|
388
|
-
@class.class_eval
|
389
|
-
|
390
|
-
|
504
|
+
it "should not pass any of the hookable method's arguments if the hook block does not accept arguments" do
|
505
|
+
@class.class_eval do
|
506
|
+
def method_with_args(one, two, three); end;
|
507
|
+
before(:method_with_args) { hi_mom! }
|
508
|
+
end
|
509
|
+
|
510
|
+
inst = @class.new
|
511
|
+
inst.should_receive(:hi_mom!)
|
512
|
+
inst.method_with_args(1, 2, 3)
|
513
|
+
end
|
514
|
+
|
515
|
+
it "should not pass any of the hookable method's arguments if the hook method does not accept arguments" do
|
516
|
+
@class.class_eval do
|
517
|
+
def method_with_args(one, two, three); end;
|
518
|
+
def before_method_with_args; hi_mom!; end;
|
519
|
+
before(:method_with_args, :before_method_with_args)
|
520
|
+
end
|
521
|
+
|
522
|
+
inst = @class.new
|
523
|
+
inst.should_receive(:hi_mom!)
|
524
|
+
inst.method_with_args(1, 2, 3)
|
525
|
+
end
|
526
|
+
|
527
|
+
it "should not pass any of the hookable method's arguments if the hook is declared after it is registered and does not accept arguments" do
|
528
|
+
@class.class_eval do
|
529
|
+
def method_with_args(one, two, three); end;
|
530
|
+
before(:method_with_args, :before_method_with_args)
|
531
|
+
def before_method_with_args; hi_mom!; end;
|
532
|
+
end
|
533
|
+
|
534
|
+
inst = @class.new
|
535
|
+
inst.should_receive(:hi_mom!)
|
536
|
+
inst.method_with_args(1, 2, 3)
|
537
|
+
end
|
538
|
+
|
539
|
+
it "should not pass any of the hookable method's arguments if the hook has been re-defined not to accept arguments" do
|
540
|
+
@class.class_eval do
|
541
|
+
def method_with_args(one, two, three); end;
|
542
|
+
def before_method_with_args(one, two, three); hi_mom!; end;
|
543
|
+
before(:method_with_args, :before_method_with_args)
|
544
|
+
def before_method_with_args; hi_dad!; end;
|
545
|
+
end
|
391
546
|
|
392
547
|
inst = @class.new
|
393
|
-
inst.
|
394
|
-
inst.
|
548
|
+
inst.should_not_receive(:hi_mom1)
|
549
|
+
inst.should_receive(:hi_dad!)
|
550
|
+
inst.method_with_args(1, 2, 3)
|
551
|
+
end
|
552
|
+
|
553
|
+
it 'should pass the hookable method arguments to the hook method if the hook method takes arguments' do
|
554
|
+
@class.class_eval do
|
555
|
+
def method_with_args(word, lol); end;
|
556
|
+
def before_method_with_args(one, two); hi_mom!(one, two); end;
|
557
|
+
before(:method_with_args, :before_method_with_args)
|
558
|
+
end
|
559
|
+
|
560
|
+
inst = @class.new
|
561
|
+
inst.should_receive(:hi_mom!).with("omg", "hi2u")
|
562
|
+
inst.method_with_args("omg", "hi2u")
|
563
|
+
end
|
564
|
+
|
565
|
+
it "should pass the hookable method arguments to the hook block if the hook block takes arguments" do
|
566
|
+
@class.class_eval do
|
567
|
+
def method_with_args(word, lol); end;
|
568
|
+
before(:method_with_args) { |one, two| hi_mom!(one, two) }
|
569
|
+
end
|
570
|
+
|
571
|
+
inst = @class.new
|
572
|
+
inst.should_receive(:hi_mom!).with('omg', 'hi2u')
|
573
|
+
inst.method_with_args('omg', 'hi2u')
|
574
|
+
end
|
575
|
+
|
576
|
+
it 'should pass the hookable method arguments to the hook method if the hook method was re-defined to accept arguments' do
|
577
|
+
@class.class_eval do
|
578
|
+
def method_with_args(word, lol); end;
|
579
|
+
def before_method_with_args; hi_mom!; end;
|
580
|
+
before(:method_with_args, :before_method_with_args)
|
581
|
+
def before_method_with_args(word, lol); hi_dad!(word, lol); end;
|
582
|
+
end
|
583
|
+
|
584
|
+
inst = @class.new
|
585
|
+
inst.should_not_receive(:hi_mom!)
|
586
|
+
inst.should_receive(:hi_dad!).with("omg", "hi2u")
|
587
|
+
inst.method_with_args("omg", "hi2u")
|
588
|
+
end
|
589
|
+
|
590
|
+
it "should not pass the method return value to the after hook if the method does not take arguments" do
|
591
|
+
@class.class_eval do
|
592
|
+
def method_with_ret_val; 'hello'; end;
|
593
|
+
def after_method_with_ret_val; hi_mom!; end;
|
594
|
+
after(:method_with_ret_val, :after_method_with_ret_val)
|
595
|
+
end
|
596
|
+
|
597
|
+
inst = @class.new
|
598
|
+
inst.should_receive(:hi_mom!)
|
599
|
+
inst.method_with_ret_val
|
395
600
|
end
|
396
601
|
|
397
602
|
it 'should work with glob arguments (or whatever you call em)' do
|
398
|
-
@class.class_eval
|
399
|
-
|
400
|
-
|
603
|
+
@class.class_eval do
|
604
|
+
def hook_this(*args); end;
|
605
|
+
def before_hook_this(*args); hi_mom!(*args) end;
|
606
|
+
before(:hook_this, :before_hook_this)
|
607
|
+
end
|
401
608
|
|
402
609
|
inst = @class.new
|
403
|
-
inst.should_receive(:
|
610
|
+
inst.should_receive(:hi_mom!).with("omg", "hi2u", "lolercoaster")
|
404
611
|
inst.hook_this("omg", "hi2u", "lolercoaster")
|
405
612
|
end
|
406
613
|
|
@@ -540,8 +747,6 @@ describe Extlib::Hook do
|
|
540
747
|
inst.hookable
|
541
748
|
end
|
542
749
|
|
543
|
-
|
544
|
-
|
545
750
|
it 'should not call the hook stack if the hookable method is overwritten and does not call super' do
|
546
751
|
@class.before(:hookable) { hi_mom! }
|
547
752
|
@child = Class.new(@class) do
|
@@ -736,6 +941,36 @@ describe Extlib::Hook do
|
|
736
941
|
@class.hello.should == "hello world"
|
737
942
|
end
|
738
943
|
|
944
|
+
it "should pass the return value to a hook method" do
|
945
|
+
@class.class_eval do
|
946
|
+
def self.with_return_val; 'hello'; end;
|
947
|
+
def self.after_with_return_val(retval); retval.should == 'hello'; end;
|
948
|
+
after_class_method(:with_return_val, :after_with_return_val)
|
949
|
+
end
|
950
|
+
|
951
|
+
@class.with_return_val
|
952
|
+
end
|
953
|
+
|
954
|
+
it "should pass the return value to a hook block" do
|
955
|
+
@class.class_eval do
|
956
|
+
def self.with_return_val; 'hello'; end;
|
957
|
+
after_class_method(:with_return_val) { |ret| ret.should == 'hello' }
|
958
|
+
end
|
959
|
+
|
960
|
+
@class.with_return_val
|
961
|
+
end
|
962
|
+
|
963
|
+
it "should pass the return value and method arguments to a hook block" do
|
964
|
+
@class.class_eval do
|
965
|
+
def self.with_args_and_return_val(world); 'hello'; end;
|
966
|
+
after_class_method(:with_args_and_return_val) do |hello, world|
|
967
|
+
hello.should == "hello"
|
968
|
+
world.should == "world"
|
969
|
+
end
|
970
|
+
end
|
971
|
+
|
972
|
+
@class.with_args_and_return_val('world')
|
973
|
+
end
|
739
974
|
end
|
740
975
|
|
741
976
|
describe "for instance methods" do
|
@@ -771,6 +1006,44 @@ describe Extlib::Hook do
|
|
771
1006
|
@class.new.hello.should == "hello world"
|
772
1007
|
end
|
773
1008
|
|
1009
|
+
it "should return nil if an after hook throws :halt without a return value" do
|
1010
|
+
@class.class_eval %{def with_value; "hello"; end;}
|
1011
|
+
@class.register_instance_hooks(:with_value)
|
1012
|
+
@class.after(:with_value) { throw :halt }
|
1013
|
+
|
1014
|
+
@class.new.with_value.should be_nil
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
it "should pass the return value to a hook method" do
|
1018
|
+
@class.class_eval do
|
1019
|
+
def with_return_val; 'hello'; end;
|
1020
|
+
def after_with_return_val(retval); retval.should == 'hello'; end;
|
1021
|
+
after(:with_return_val, :after_with_return_val)
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
@class.new.with_return_val
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
it "should pass the return value to a hook block" do
|
1028
|
+
@class.class_eval do
|
1029
|
+
def with_return_val; 'hello'; end;
|
1030
|
+
after(:with_return_val) { |ret| ret.should == 'hello' }
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
@class.new.with_return_val
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
it "should pass the return value and method arguments to a hook block" do
|
1037
|
+
@class.class_eval do
|
1038
|
+
def with_args_and_return_val(world); 'hello'; end;
|
1039
|
+
after(:with_args_and_return_val) do |hello, world|
|
1040
|
+
hello.should == "hello"
|
1041
|
+
world.should == "world"
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
@class.new.with_args_and_return_val('world')
|
1046
|
+
end
|
774
1047
|
end
|
775
1048
|
|
776
1049
|
end
|
@@ -815,12 +1088,12 @@ describe Extlib::Hook do
|
|
815
1088
|
lambda { @class.clakable }.should_not throw_symbol(:halt)
|
816
1089
|
end
|
817
1090
|
|
818
|
-
it "should
|
1091
|
+
it "should return nil if an after hook throws :halt without a return value" do
|
819
1092
|
@class.class_eval %{def self.with_value; "hello"; end;}
|
820
1093
|
@class.register_class_hooks(:with_value)
|
821
1094
|
@class.after_class_method(:with_value) { throw :halt }
|
822
1095
|
|
823
|
-
@class.with_value.should
|
1096
|
+
@class.with_value.should be_nil
|
824
1097
|
end
|
825
1098
|
end
|
826
1099
|
|
@@ -864,14 +1137,42 @@ describe Extlib::Hook do
|
|
864
1137
|
inst.should_not_receive(:never_see_me!)
|
865
1138
|
lambda { inst.hookable }.should_not throw_symbol(:halt)
|
866
1139
|
end
|
1140
|
+
end
|
867
1141
|
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
describe 'aborting with return values' do
|
1145
|
+
|
1146
|
+
describe "for class methods" do
|
872
1147
|
|
873
|
-
|
1148
|
+
it "should be able to abort from a before hook with a return value" do
|
1149
|
+
@class.before_class_method(:clakable) { throw :halt, 'omg' }
|
1150
|
+
@class.clakable.should == 'omg'
|
874
1151
|
end
|
1152
|
+
|
1153
|
+
it "should be able to abort from an after hook with a return value" do
|
1154
|
+
@class.after_class_method(:clakable) { throw :halt, 'omg' }
|
1155
|
+
@class.clakable.should == 'omg'
|
1156
|
+
end
|
1157
|
+
|
1158
|
+
end
|
1159
|
+
|
1160
|
+
describe "for instance methods" do
|
1161
|
+
|
1162
|
+
it "should be able to abort from a before hook with a return value" do
|
1163
|
+
@class.before(:hookable) { throw :halt, 'omg' }
|
1164
|
+
|
1165
|
+
inst = @class.new
|
1166
|
+
inst.hookable.should == 'omg'
|
1167
|
+
end
|
1168
|
+
|
1169
|
+
it "should be able to abort from an after hook with a return value" do
|
1170
|
+
@class.after(:hookable) { throw :halt, 'omg' }
|
1171
|
+
|
1172
|
+
inst = @class.new
|
1173
|
+
inst.hookable.should == 'omg'
|
1174
|
+
end
|
1175
|
+
|
875
1176
|
end
|
876
1177
|
|
877
1178
|
end
|
@@ -888,9 +1189,9 @@ describe Extlib::Hook do
|
|
888
1189
|
end
|
889
1190
|
end
|
890
1191
|
|
891
|
-
@class.args_for(@class.instance_method(:hookable)).should == ""
|
892
|
-
@class.args_for(@class.instance_method(:some_method)).should == "_1, _2, _3"
|
893
|
-
@class.args_for(@class.instance_method(:yet_another)).should == "_1, *args"
|
1192
|
+
@class.args_for(@class.instance_method(:hookable)).should == "&block"
|
1193
|
+
@class.args_for(@class.instance_method(:some_method)).should == "_1, _2, _3, &block"
|
1194
|
+
@class.args_for(@class.instance_method(:yet_another)).should == "_1, *args, &block"
|
894
1195
|
end
|
895
1196
|
end
|
896
1197
|
|