sundbp-extlib 0.9.14

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.
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