sundbp-extlib 0.9.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/.autotest +21 -0
  2. data/.document +5 -0
  3. data/.gitignore +22 -0
  4. data/LICENSE +47 -0
  5. data/README.rdoc +17 -0
  6. data/Rakefile +28 -0
  7. data/VERSION +1 -0
  8. data/extlib.gemspec +146 -0
  9. data/lib/extlib.rb +50 -0
  10. data/lib/extlib/array.rb +36 -0
  11. data/lib/extlib/assertions.rb +8 -0
  12. data/lib/extlib/blank.rb +89 -0
  13. data/lib/extlib/boolean.rb +11 -0
  14. data/lib/extlib/byte_array.rb +6 -0
  15. data/lib/extlib/class.rb +177 -0
  16. data/lib/extlib/datetime.rb +29 -0
  17. data/lib/extlib/dictionary.rb +433 -0
  18. data/lib/extlib/hash.rb +442 -0
  19. data/lib/extlib/hook.rb +403 -0
  20. data/lib/extlib/inflection.rb +440 -0
  21. data/lib/extlib/lazy_array.rb +451 -0
  22. data/lib/extlib/lazy_module.rb +18 -0
  23. data/lib/extlib/logger.rb +198 -0
  24. data/lib/extlib/mash.rb +155 -0
  25. data/lib/extlib/module.rb +47 -0
  26. data/lib/extlib/nil.rb +5 -0
  27. data/lib/extlib/numeric.rb +5 -0
  28. data/lib/extlib/object.rb +175 -0
  29. data/lib/extlib/object_space.rb +13 -0
  30. data/lib/extlib/pathname.rb +20 -0
  31. data/lib/extlib/pooling.rb +235 -0
  32. data/lib/extlib/rubygems.rb +38 -0
  33. data/lib/extlib/simple_set.rb +66 -0
  34. data/lib/extlib/string.rb +176 -0
  35. data/lib/extlib/struct.rb +17 -0
  36. data/lib/extlib/symbol.rb +21 -0
  37. data/lib/extlib/time.rb +43 -0
  38. data/lib/extlib/virtual_file.rb +10 -0
  39. data/spec/array_spec.rb +39 -0
  40. data/spec/blank_spec.rb +85 -0
  41. data/spec/byte_array_spec.rb +7 -0
  42. data/spec/class_spec.rb +157 -0
  43. data/spec/datetime_spec.rb +22 -0
  44. data/spec/hash_spec.rb +537 -0
  45. data/spec/hook_spec.rb +1234 -0
  46. data/spec/inflection/plural_spec.rb +564 -0
  47. data/spec/inflection/singular_spec.rb +497 -0
  48. data/spec/inflection_extras_spec.rb +110 -0
  49. data/spec/lazy_array_spec.rb +1957 -0
  50. data/spec/lazy_module_spec.rb +38 -0
  51. data/spec/mash_spec.rb +311 -0
  52. data/spec/module_spec.rb +70 -0
  53. data/spec/object_space_spec.rb +9 -0
  54. data/spec/object_spec.rb +114 -0
  55. data/spec/pooling_spec.rb +511 -0
  56. data/spec/rcov.opts +6 -0
  57. data/spec/simple_set_spec.rb +57 -0
  58. data/spec/spec.opts +4 -0
  59. data/spec/spec_helper.rb +10 -0
  60. data/spec/string_spec.rb +221 -0
  61. data/spec/struct_spec.rb +12 -0
  62. data/spec/symbol_spec.rb +8 -0
  63. data/spec/time_spec.rb +29 -0
  64. data/spec/try_call_spec.rb +73 -0
  65. data/spec/try_dup_spec.rb +45 -0
  66. data/spec/virtual_file_spec.rb +21 -0
  67. data/tasks/ci.rake +1 -0
  68. data/tasks/metrics.rake +36 -0
  69. data/tasks/spec.rake +25 -0
  70. data/tasks/yard.rake +9 -0
  71. data/tasks/yardstick.rake +19 -0
  72. metadata +180 -0
@@ -0,0 +1,511 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+ require 'timeout'
3
+
4
+ module Extlib::Pooling
5
+ class << self
6
+ remove_method :scavenger_interval if instance_methods(false).any? { |m| m.to_sym == :scavenger_interval }
7
+ def scavenger_interval
8
+ 1
9
+ end
10
+ end
11
+ end
12
+
13
+ describe "Extlib::Pooling" do
14
+ before do
15
+
16
+ Object.send(:remove_const, :Person) if defined?(Person)
17
+ class ::Person
18
+ include Extlib::Pooling
19
+
20
+ attr_accessor :name
21
+
22
+ def initialize(name)
23
+ @name = name
24
+ end
25
+
26
+ def dispose
27
+ @name = nil
28
+ end
29
+ end
30
+
31
+ Object.send(:remove_const, :Overwriter) if defined?(Overwriter)
32
+ class ::Overwriter
33
+
34
+ def self.new(*args)
35
+ instance = allocate
36
+ instance.send(:initialize, *args)
37
+ instance.overwritten = true
38
+ instance
39
+ end
40
+
41
+ include Extlib::Pooling
42
+
43
+ attr_accessor :name
44
+
45
+ def initialize(name)
46
+ @name = name
47
+ @overwritten = false
48
+ end
49
+
50
+ def overwritten?
51
+ @overwritten
52
+ end
53
+
54
+ def overwritten=(value)
55
+ @overwritten = value
56
+ end
57
+
58
+ class << self
59
+ remove_method :pool_size if instance_methods(false).any? { |m| m.to_sym == :pool_size }
60
+ def pool_size
61
+ pool_size = if RUBY_PLATFORM =~ /java/
62
+ 20
63
+ else
64
+ 2
65
+ end
66
+ pool_size
67
+ end
68
+ end
69
+
70
+ def dispose
71
+ @name = nil
72
+ end
73
+ end
74
+ end
75
+
76
+ after :each do
77
+ Extlib::Pooling.lock.synchronize do
78
+ Extlib::Pooling.pools.each do |pool|
79
+ pool.lock.synchronize do
80
+ pool.dispose
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ it "should track the initialized pools" do
87
+ bob = Person.new('Bob') # Ensure the pool is "primed"
88
+ bob.name.should == 'Bob'
89
+ bob.instance_variable_get(:@__pool).should_not be_nil
90
+ Person.__pools.size.should == 1
91
+ bob.release
92
+ Person.__pools.size.should == 1
93
+
94
+ Extlib::Pooling::pools.should_not be_empty
95
+
96
+ sleep(1.2)
97
+
98
+ Extlib::Pooling::pools.should be_empty
99
+ bob.name.should be_nil
100
+ end
101
+
102
+ it "should maintain a size of 1" do
103
+ bob = Person.new('Bob')
104
+ fred = Person.new('Fred')
105
+ ted = Person.new('Ted')
106
+
107
+ Person.__pools.each do |args, pool|
108
+ pool.size.should == 1
109
+ end
110
+
111
+ bob.release
112
+ fred.release
113
+ ted.release
114
+
115
+ Person.__pools.each do |args, pool|
116
+ pool.size.should == 1
117
+ end
118
+ end
119
+
120
+ it "should allow you to overwrite Class#new" do
121
+ bob = Overwriter.new('Bob')
122
+ bob.should be_overwritten
123
+ bob.release
124
+ end
125
+
126
+ it "should allow multiple threads to access the pool" do
127
+ t1 = Thread.new do
128
+ bob = Person.new('Bob')
129
+ sleep(1)
130
+ bob.release
131
+ end
132
+
133
+ lambda do
134
+ bob = Person.new('Bob')
135
+ t1.join
136
+ bob.release
137
+ end.should_not raise_error
138
+ end
139
+
140
+ it "should allow you to flush a pool" do
141
+ bob = Overwriter.new('Bob')
142
+ Overwriter.new('Bob').release
143
+ bob.release
144
+
145
+ bob.name.should == 'Bob'
146
+
147
+ Overwriter.__pools[['Bob']].size.should == 2
148
+ Overwriter.__pools[['Bob']].flush!
149
+ Overwriter.__pools[['Bob']].size.should == 0
150
+
151
+ bob.name.should be_nil
152
+ end
153
+
154
+ it "should wake up the scavenger thread when exiting" do
155
+ bob = Person.new('Bob')
156
+ bob.release
157
+ Extlib.exiting = true
158
+ sleep(0.1)
159
+ Extlib::Pooling.scavenger?.should be_false
160
+ end
161
+
162
+ it "should be able to detach an instance from the pool" do
163
+ bob = Person.new('Bob')
164
+ Person.__pools[['Bob']].size.should == 1
165
+ bob.detach
166
+ Person.__pools[['Bob']].size.should == 0
167
+ end
168
+
169
+ end
170
+
171
+ # describe Extlib::Pooling::ResourcePool do
172
+ # before :each do
173
+ # @pool = Extlib::Pooling::ResourcePool.new(7, DisposableResource, :expiration_period => 50)
174
+ # end
175
+ #
176
+ # it "responds to flush!" do
177
+ # @pool.should respond_to(:flush!)
178
+ # end
179
+ #
180
+ # it "responds to acquire" do
181
+ # @pool.should respond_to(:acquire)
182
+ # end
183
+ #
184
+ # it "responds to release" do
185
+ # @pool.should respond_to(:release)
186
+ # end
187
+ #
188
+ # it "responds to :available?" do
189
+ # @pool.should respond_to(:available?)
190
+ # end
191
+ #
192
+ # it "has a size limit" do
193
+ # @pool.size_limit.should == 7
194
+ # end
195
+ #
196
+ # it "has initial size of zero" do
197
+ # @pool.size.should == 0
198
+ # end
199
+ #
200
+ # it "has a set of reserved resources" do
201
+ # @pool.instance_variable_get("@reserved").should be_empty
202
+ # end
203
+ #
204
+ # it "has a set of available resources" do
205
+ # @pool.instance_variable_get("@available").should be_empty
206
+ # end
207
+ #
208
+ # it "knows class of resources (objects) it works with" do
209
+ # @pool.class_of_resources.should == DisposableResource
210
+ # end
211
+ #
212
+ # it "raises exception when given anything but class for resources class" do
213
+ # lambda {
214
+ # @pool = Extlib::Pooling::ResourcePool.new(7, "Hooray!", {})
215
+ # }.should raise_error(ArgumentError, /class/)
216
+ # end
217
+ #
218
+ # it "requires class of resources (objects) it works with to have a dispose instance method" do
219
+ # lambda {
220
+ # @pool = Extlib::Pooling::ResourcePool.new(3, UndisposableResource, {})
221
+ # }.should raise_error(ArgumentError, /dispose/)
222
+ # end
223
+ #
224
+ # it "may take initialization arguments" do
225
+ # @pool = Extlib::Pooling::ResourcePool.new(7, DisposableResource, { :initialization_args => ["paper"] })
226
+ # @pool.instance_variable_get("@initialization_args").should == ["paper"]
227
+ # end
228
+ #
229
+ # it "may take expiration period option" do
230
+ # @pool = Extlib::Pooling::ResourcePool.new(7, DisposableResource, { :expiration_period => 100 })
231
+ # @pool.expiration_period.should == 100
232
+ # end
233
+ #
234
+ # it "has default expiration period of one minute" do
235
+ # @pool = Extlib::Pooling::ResourcePool.new(7, DisposableResource, {})
236
+ # @pool.expiration_period.should == 60
237
+ # end
238
+ #
239
+ # it "spawns a thread to dispose objects haven't been used for a while" do
240
+ # @pool = Extlib::Pooling::ResourcePool.new(7, DisposableResource, {})
241
+ # @pool.instance_variable_get("@pool_expiration_thread").should be_an_instance_of(Thread)
242
+ # end
243
+ # end
244
+ #
245
+ #
246
+ #
247
+ # describe "Acquire from constant size pool" do
248
+ # before :each do
249
+ # DisposableResource.initialize_pool(2)
250
+ # end
251
+ #
252
+ # after :each do
253
+ # DisposableResource.instance_variable_set("@__pool", nil)
254
+ # end
255
+ #
256
+ # it "increased size of the pool" do
257
+ # @time = DisposableResource.pool.acquire
258
+ # DisposableResource.pool.size.should == 1
259
+ # end
260
+ #
261
+ # it "places initialized instance in the reserved set" do
262
+ # @time = DisposableResource.pool.acquire
263
+ # DisposableResource.pool.instance_variable_get("@reserved").size.should == 1
264
+ # end
265
+ #
266
+ # it "raises an exception when pool size limit is hit" do
267
+ # @t1 = DisposableResource.pool.acquire
268
+ # @t2 = DisposableResource.pool.acquire
269
+ #
270
+ # lambda { DisposableResource.pool.acquire }.should raise_error(RuntimeError)
271
+ # end
272
+ #
273
+ # it "returns last released resource" do
274
+ # @t1 = DisposableResource.pool.acquire
275
+ # @t2 = DisposableResource.pool.acquire
276
+ # DisposableResource.pool.release(@t1)
277
+ #
278
+ # DisposableResource.pool.acquire.should == @t1
279
+ # end
280
+ #
281
+ # it "really truly returns last released resource" do
282
+ # @t1 = DisposableResource.pool.acquire
283
+ # DisposableResource.pool.release(@t1)
284
+ #
285
+ # @t2 = DisposableResource.pool.acquire
286
+ # DisposableResource.pool.release(@t2)
287
+ #
288
+ # @t3 = DisposableResource.pool.acquire
289
+ # DisposableResource.pool.release(@t3)
290
+ #
291
+ # DisposableResource.pool.acquire.should == @t1
292
+ # @t1.should == @t3
293
+ # end
294
+ #
295
+ # it "sets allocation timestamp on resource instance" do
296
+ # @t1 = DisposableResource.new
297
+ # @t1.instance_variable_get("@__pool_acquire_timestamp").should be_close(Time.now, 2)
298
+ # end
299
+ # end
300
+ #
301
+ #
302
+ #
303
+ # describe "Releasing from constant size pool" do
304
+ # before :each do
305
+ # DisposableResource.initialize_pool(2)
306
+ # end
307
+ #
308
+ # after :each do
309
+ # DisposableResource.instance_variable_set("@__pool", nil)
310
+ # end
311
+ #
312
+ # it "decreases size of the pool" do
313
+ # @t1 = DisposableResource.pool.acquire
314
+ # @t2 = DisposableResource.pool.acquire
315
+ # DisposableResource.pool.release(@t1)
316
+ #
317
+ # DisposableResource.pool.size.should == 1
318
+ # end
319
+ #
320
+ # it "raises an exception on attempt to releases object not in pool" do
321
+ # @t1 = DisposableResource.new
322
+ # @t2 = Set.new
323
+ #
324
+ # DisposableResource.pool.release(@t1)
325
+ # lambda { DisposableResource.pool.release(@t2) }.should raise_error(RuntimeError)
326
+ # end
327
+ #
328
+ # it "removes released object from reserved set" do
329
+ # @t1 = DisposableResource.pool.acquire
330
+ #
331
+ # lambda {
332
+ # DisposableResource.pool.release(@t1)
333
+ # }.should change(DisposableResource.pool.instance_variable_get("@reserved"), :size).by(-1)
334
+ # end
335
+ #
336
+ # it "returns released object back to available set" do
337
+ # @t1 = DisposableResource.pool.acquire
338
+ #
339
+ # lambda {
340
+ # DisposableResource.pool.release(@t1)
341
+ # }.should change(DisposableResource.pool.instance_variable_get("@available"), :size).by(1)
342
+ # end
343
+ #
344
+ # it "updates acquire timestamp on already allocated resource instance" do
345
+ # # acquire it once
346
+ # @t1 = DisposableResource.new
347
+ # # wait a bit
348
+ # sleep 3
349
+ #
350
+ # # check old timestamp
351
+ # @t1.instance_variable_get("@__pool_acquire_timestamp").should be_close(Time.now, 4)
352
+ #
353
+ # # re-acquire
354
+ # DisposableResource.pool.release(@t1)
355
+ # @t1 = DisposableResource.new
356
+ # # see timestamp is updated
357
+ # @t1.instance_variable_get("@__pool_acquire_timestamp").should be_close(Time.now, 2)
358
+ # end
359
+ # end
360
+ #
361
+ #
362
+ #
363
+ # describe Extlib::Pooling::ResourcePool, "#available?" do
364
+ # before :each do
365
+ # DisposableResource.initialize_pool(2)
366
+ # DisposableResource.new
367
+ # end
368
+ #
369
+ # after :each do
370
+ # DisposableResource.instance_variable_set("@__pool", nil)
371
+ # end
372
+ #
373
+ # it "returns true when pool has available instances" do
374
+ # DisposableResource.pool.should be_available
375
+ # end
376
+ #
377
+ # it "returns false when pool is exhausted" do
378
+ # # acquires the last available resource
379
+ # DisposableResource.new
380
+ # DisposableResource.pool.should_not be_available
381
+ # end
382
+ # end
383
+ #
384
+ #
385
+ #
386
+ # describe "Flushing of constant size pool" do
387
+ # before :each do
388
+ # DisposableResource.initialize_pool(2)
389
+ #
390
+ # @t1 = DisposableResource.new
391
+ # @t2 = DisposableResource.new
392
+ #
393
+ # # sanity check
394
+ # DisposableResource.pool.instance_variable_get("@reserved").should_not be_empty
395
+ # end
396
+ #
397
+ # after :each do
398
+ # DisposableResource.instance_variable_set("@__pool", nil)
399
+ # end
400
+ #
401
+ # it "disposes all pooled objects" do
402
+ # [@t1, @t2].each { |instance| instance.should_receive(:dispose) }
403
+ #
404
+ # DisposableResource.pool.flush!
405
+ # end
406
+ #
407
+ # it "empties reserved set" do
408
+ # DisposableResource.pool.flush!
409
+ #
410
+ # DisposableResource.pool.instance_variable_get("@reserved").should be_empty
411
+ # end
412
+ #
413
+ # it "returns all instances to available set" do
414
+ # DisposableResource.pool.flush!
415
+ #
416
+ # DisposableResource.pool.instance_variable_get("@available").size.should == 2
417
+ # end
418
+ # end
419
+ #
420
+ #
421
+ #
422
+ # describe "Poolable resource class" do
423
+ # before :each do
424
+ # DisposableResource.initialize_pool(3, :initialization_args => ["paper"])
425
+ # end
426
+ #
427
+ # after :each do
428
+ # DisposableResource.instance_variable_set("@__pool", nil)
429
+ # end
430
+ #
431
+ # it "acquires new instances from pool" do
432
+ # @instance_one = DisposableResource.new
433
+ #
434
+ # DisposableResource.pool.acquired?(@instance_one).should be_true
435
+ # end
436
+ #
437
+ # it "flushed existing pool on re-initialization" do
438
+ # DisposableResource.pool.should_receive(:flush!)
439
+ # DisposableResource.initialize_pool(5)
440
+ # end
441
+ #
442
+ # it "replaces pool on re-initialization" do
443
+ # DisposableResource.initialize_pool(5)
444
+ # DisposableResource.pool.size_limit.should == 5
445
+ # end
446
+ #
447
+ # it "passes initialization parameters to newly created resource instances" do
448
+ # DisposableResource.new.name.should == "paper"
449
+ # end
450
+ # end
451
+ #
452
+ #
453
+ #
454
+ # describe "Pooled object", "on initialization" do
455
+ # after :each do
456
+ # DisposableResource.instance_variable_set("@__pool", nil)
457
+ # end
458
+ #
459
+ # it "does not flush pool" do
460
+ # # using pool here initializes the pool first
461
+ # # so we use instance variable directly
462
+ # DisposableResource.instance_variable_get("@__pool").should_not_receive(:flush!)
463
+ # DisposableResource.initialize_pool(23)
464
+ # end
465
+ #
466
+ # it "flushes pool first when re-initialized" do
467
+ # DisposableResource.initialize_pool(5)
468
+ # DisposableResource.pool.should_receive(:flush!)
469
+ # DisposableResource.initialize_pool(23)
470
+ # end
471
+ # end
472
+ #
473
+ #
474
+ #
475
+ # describe Extlib::Pooling::ResourcePool, "#time_to_dispose?" do
476
+ # before :each do
477
+ # DisposableResource.initialize_pool(7, :expiration_period => 2)
478
+ # end
479
+ #
480
+ # after :each do
481
+ # DisposableResource.instance_variable_set("@__pool", nil)
482
+ # end
483
+ #
484
+ # it "returns true when object's last aquisition time is greater than limit" do
485
+ # @t1 = DisposableResource.new
486
+ # DisposableResource.pool.time_to_release?(@t1).should be_false
487
+ #
488
+ # sleep 3
489
+ # DisposableResource.pool.time_to_release?(@t1).should be_true
490
+ # end
491
+ # end
492
+ #
493
+ #
494
+ #
495
+ # describe Extlib::Pooling::ResourcePool, "#dispose_outdated" do
496
+ # before :each do
497
+ # DisposableResource.initialize_pool(7, :expiration_period => 2)
498
+ # end
499
+ #
500
+ # after :each do
501
+ # DisposableResource.instance_variable_set("@__pool", nil)
502
+ # end
503
+ #
504
+ # it "releases and thus disposes outdated instances" do
505
+ # @t1 = DisposableResource.new
506
+ # DisposableResource.pool.should_receive(:time_to_release?).with(@t1).and_return(true)
507
+ # DisposableResource.pool.should_receive(:release).with(@t1)
508
+ #
509
+ # DisposableResource.pool.dispose_outdated
510
+ # end
511
+ # end