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/lib/extlib/object.rb CHANGED
@@ -4,4 +4,4 @@ class Object
4
4
  instance_variables.include?(method.to_s)
5
5
  end
6
6
  end
7
- end # class Object
7
+ end # class Object
@@ -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 aquired from pool.
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
- if pool.expired?
35
- pool.lock.synchronize do
36
- if pool.size == 0
37
- pool.dispose
38
- end
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
- 1
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
- @reserved = Set.new
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 = aquire
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 && @reserved.size >= @max_size
140
+ if ThreadGroup::Default.list.size == 2 && @reserved_count >= @max_size
144
141
  raise ThreadStopError.new(size)
145
142
  else
146
- sleep(0.01)
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 + @reserved.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} reserved=#{@reserved.size}>"
174
+ "#<Extlib::Pooling::Pool<#{@resource.name}> available=#{@available.size} reserved_count=#{@reserved_count}>"
170
175
  end
171
176
 
172
177
  def flush!
173
- lock.synchronize do
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
- def expired?
187
- lock.synchronize do
188
- @available.each do |instance|
189
- if instance.instance_variable_get(:@__allocated_in_pool) + scavenge_interval < Time.now
190
- instance.dispose
191
- @available.delete(instance)
192
- end
193
- end
194
-
195
- size == 0
196
- end
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 aquire
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
- @reserved << instance
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
@@ -0,0 +1,3 @@
1
+ module Extlib
2
+ VERSION = "0.9.3"
3
+ 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 'should pass the hookable method arguments to the hook method' do
341
- @class.class_eval %{def self.hook_this(word, lol); end;}
342
- @class.register_class_hooks(:hook_this)
343
- @class.before_class_method(:hook_this, :before_hook_this)
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(:before_hook_this).with("omg", "hi2u")
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 %{def self.hook_this(*args); end;}
351
- @class.register_class_hooks(:hook_this)
352
- @class.before_class_method(:hook_this, :before_hook_this)
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(:before_hook_this).with("omg", "hi2u", "lolercoaster")
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 'should pass the hookable method arguments to the hook method' do
388
- @class.class_eval %{def hook_this(word, lol); end;}
389
- @class.register_instance_hooks(:hook_this)
390
- @class.before(:hook_this, :before_hook_this)
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.should_receive(:before_hook_this).with("omg", "hi2u")
394
- inst.hook_this("omg", "hi2u")
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 %{def hook_this(*args); end;}
399
- @class.register_instance_hooks(:hook_this)
400
- @class.before(:hook_this, :before_hook_this)
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(:before_hook_this).with("omg", "hi2u", "lolercoaster")
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 still return the hookable methods return value if an after hook throws :halt" do
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 == "hello"
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
- it "should still return the hookable methods return value if an after hook throws :halt" do
869
- @class.class_eval %{def with_value; "hello"; end;}
870
- @class.register_instance_hooks(:with_value)
871
- @class.after(:with_value) { throw :halt }
1142
+ end
1143
+
1144
+ describe 'aborting with return values' do
1145
+
1146
+ describe "for class methods" do
872
1147
 
873
- @class.new.with_value.should == "hello"
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