thorero 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +1 -0
- data/LICENSE +20 -0
- data/Manifest +45 -0
- data/Manifest.txt +29 -0
- data/README.txt +3 -0
- data/Rakefile +180 -0
- data/lib/extlib.rb +32 -0
- data/lib/extlib/assertions.rb +8 -0
- data/lib/extlib/blank.rb +42 -0
- data/lib/extlib/class.rb +175 -0
- data/lib/extlib/hash.rb +410 -0
- data/lib/extlib/hook.rb +366 -0
- data/lib/extlib/inflection.rb +141 -0
- data/lib/extlib/lazy_array.rb +106 -0
- data/lib/extlib/logger.rb +202 -0
- data/lib/extlib/mash.rb +143 -0
- data/lib/extlib/module.rb +37 -0
- data/lib/extlib/object.rb +165 -0
- data/lib/extlib/object_space.rb +13 -0
- data/lib/extlib/pathname.rb +5 -0
- data/lib/extlib/pooling.rb +233 -0
- data/lib/extlib/rubygems.rb +38 -0
- data/lib/extlib/simple_set.rb +39 -0
- data/lib/extlib/string.rb +132 -0
- data/lib/extlib/struct.rb +8 -0
- data/lib/extlib/tasks/release.rb +11 -0
- data/lib/extlib/time.rb +12 -0
- data/lib/extlib/version.rb +3 -0
- data/lib/extlib/virtual_file.rb +10 -0
- data/spec/blank_spec.rb +85 -0
- data/spec/hash_spec.rb +524 -0
- data/spec/hook_spec.rb +1198 -0
- data/spec/inflection_spec.rb +50 -0
- data/spec/lazy_array_spec.rb +896 -0
- data/spec/mash_spec.rb +244 -0
- data/spec/module_spec.rb +58 -0
- data/spec/object_space_spec.rb +9 -0
- data/spec/object_spec.rb +98 -0
- data/spec/pooling_spec.rb +486 -0
- data/spec/simple_set_spec.rb +26 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/string_spec.rb +200 -0
- data/spec/struct_spec.rb +12 -0
- data/spec/time_spec.rb +16 -0
- data/spec/virtual_file_spec.rb +21 -0
- data/thorero.gemspec +147 -0
- metadata +146 -0
data/lib/extlib/mash.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
# This class has dubious semantics and we only have it so that people can write
|
2
|
+
# params[:key] instead of params['key'].
|
3
|
+
class Mash < Hash
|
4
|
+
|
5
|
+
# @param constructor<Object>
|
6
|
+
# The default value for the mash. Defaults to an empty hash.
|
7
|
+
#
|
8
|
+
# @details [Alternatives]
|
9
|
+
# If constructor is a Hash, a new mash will be created based on the keys of
|
10
|
+
# the hash and no default value will be set.
|
11
|
+
def initialize(constructor = {})
|
12
|
+
if constructor.is_a?(Hash)
|
13
|
+
super()
|
14
|
+
update(constructor)
|
15
|
+
else
|
16
|
+
super(constructor)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param key<Object> The default value for the mash. Defaults to nil.
|
21
|
+
#
|
22
|
+
# @details [Alternatives]
|
23
|
+
# If key is a Symbol and it is a key in the mash, then the default value will
|
24
|
+
# be set to the value matching the key.
|
25
|
+
def default(key = nil)
|
26
|
+
if key.is_a?(Symbol) && include?(key = key.to_s)
|
27
|
+
self[key]
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
34
|
+
alias_method :regular_update, :update unless method_defined?(:regular_update)
|
35
|
+
|
36
|
+
# @param key<Object> The key to set.
|
37
|
+
# @param value<Object>
|
38
|
+
# The value to set the key to.
|
39
|
+
#
|
40
|
+
# @see Mash#convert_key
|
41
|
+
# @see Mash#convert_value
|
42
|
+
def []=(key, value)
|
43
|
+
regular_writer(convert_key(key), convert_value(value))
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param other_hash<Hash>
|
47
|
+
# A hash to update values in the mash with. The keys and the values will be
|
48
|
+
# converted to Mash format.
|
49
|
+
#
|
50
|
+
# @return <Mash> The updated mash.
|
51
|
+
def update(other_hash)
|
52
|
+
other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
alias_method :merge!, :update
|
57
|
+
|
58
|
+
# @param key<Object> The key to check for. This will be run through convert_key.
|
59
|
+
#
|
60
|
+
# @return <TrueClass, FalseClass> True if the key exists in the mash.
|
61
|
+
def key?(key)
|
62
|
+
super(convert_key(key))
|
63
|
+
end
|
64
|
+
|
65
|
+
# def include? def has_key? def member?
|
66
|
+
alias_method :include?, :key?
|
67
|
+
alias_method :has_key?, :key?
|
68
|
+
alias_method :member?, :key?
|
69
|
+
|
70
|
+
# @param key<Object> The key to fetch. This will be run through convert_key.
|
71
|
+
# @param *extras<Array> Default value.
|
72
|
+
#
|
73
|
+
# @return <Object> The value at key or the default value.
|
74
|
+
def fetch(key, *extras)
|
75
|
+
super(convert_key(key), *extras)
|
76
|
+
end
|
77
|
+
|
78
|
+
# @param *indices<Array>
|
79
|
+
# The keys to retrieve values for. These will be run through +convert_key+.
|
80
|
+
#
|
81
|
+
# @return <Array> The values at each of the provided keys
|
82
|
+
def values_at(*indices)
|
83
|
+
indices.collect {|key| self[convert_key(key)]}
|
84
|
+
end
|
85
|
+
|
86
|
+
# @return <Mash> A duplicate of this mash.
|
87
|
+
def dup
|
88
|
+
Mash.new(self)
|
89
|
+
end
|
90
|
+
|
91
|
+
# @param hash<Hash> The hash to merge with the mash.
|
92
|
+
#
|
93
|
+
# @return <Mash> A new mash with the hash values merged in.
|
94
|
+
def merge(hash)
|
95
|
+
self.dup.update(hash)
|
96
|
+
end
|
97
|
+
|
98
|
+
# @param key<Object>
|
99
|
+
# The key to delete from the mash.\
|
100
|
+
def delete(key)
|
101
|
+
super(convert_key(key))
|
102
|
+
end
|
103
|
+
|
104
|
+
# Used to provide the same interface as Hash.
|
105
|
+
#
|
106
|
+
# @return <Mash> This mash unchanged.
|
107
|
+
def stringify_keys!; self end
|
108
|
+
|
109
|
+
# @return <Hash> The mash as a Hash with string keys.
|
110
|
+
def to_hash
|
111
|
+
Hash.new(default).merge(self)
|
112
|
+
end
|
113
|
+
|
114
|
+
protected
|
115
|
+
# @param key<Object> The key to convert.
|
116
|
+
#
|
117
|
+
# @param <Object>
|
118
|
+
# The converted key. If the key was a symbol, it will be converted to a
|
119
|
+
# string.
|
120
|
+
#
|
121
|
+
# @api private
|
122
|
+
def convert_key(key)
|
123
|
+
key.kind_of?(Symbol) ? key.to_s : key
|
124
|
+
end
|
125
|
+
|
126
|
+
# @param value<Object> The value to convert.
|
127
|
+
#
|
128
|
+
# @return <Object>
|
129
|
+
# The converted value. A Hash or an Array of hashes, will be converted to
|
130
|
+
# their Mash equivalents.
|
131
|
+
#
|
132
|
+
# @api private
|
133
|
+
def convert_value(value)
|
134
|
+
case value
|
135
|
+
when Hash
|
136
|
+
value.to_mash
|
137
|
+
when Array
|
138
|
+
value.collect { |e| convert_value(e) }
|
139
|
+
else
|
140
|
+
value
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Module
|
2
|
+
def find_const(const_name)
|
3
|
+
if const_name[0..1] == '::'
|
4
|
+
Object.find_const(const_name[2..-1])
|
5
|
+
else
|
6
|
+
nested_const_lookup(const_name)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# Doesn't do any caching since constants can change with remove_const
|
13
|
+
def nested_const_lookup(const_name)
|
14
|
+
constants = [ Object ]
|
15
|
+
|
16
|
+
unless self == Object
|
17
|
+
self.name.split('::').each do |part|
|
18
|
+
constants.unshift(constants.first.const_get(part))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
parts = const_name.split('::')
|
23
|
+
|
24
|
+
# from most to least specific constant, use each as a base and try
|
25
|
+
# to find a constant with the name const_name within them
|
26
|
+
constants.each do |const|
|
27
|
+
# return the nested constant if available
|
28
|
+
return const if parts.all? do |part|
|
29
|
+
const = const.const_defined?(part) ? const.const_get(part) : nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# if we get this far then the nested constant was not found
|
34
|
+
raise NameError, "uninitialized constant #{const_name}"
|
35
|
+
end
|
36
|
+
|
37
|
+
end # class Module
|
@@ -0,0 +1,165 @@
|
|
1
|
+
class Object
|
2
|
+
# Extracts the singleton class, so that metaprogramming can be done on it.
|
3
|
+
#
|
4
|
+
# @return <Class> The meta class.
|
5
|
+
#
|
6
|
+
# @example [Setup]
|
7
|
+
# class MyString < String; end
|
8
|
+
#
|
9
|
+
# MyString.instance_eval do
|
10
|
+
# define_method :foo do
|
11
|
+
# puts self
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# MyString.meta_class.instance_eval do
|
16
|
+
# define_method :bar do
|
17
|
+
# puts self
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# def String.add_meta_var(var)
|
22
|
+
# self.meta_class.instance_eval do
|
23
|
+
# define_method var do
|
24
|
+
# puts "HELLO"
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# MyString.new("Hello").foo #=> "Hello"
|
31
|
+
# @example
|
32
|
+
# MyString.new("Hello").bar
|
33
|
+
# #=> NoMethodError: undefined method `bar' for "Hello":MyString
|
34
|
+
# @example
|
35
|
+
# MyString.foo
|
36
|
+
# #=> NoMethodError: undefined method `foo' for MyString:Class
|
37
|
+
# @example
|
38
|
+
# MyString.bar
|
39
|
+
# #=> MyString
|
40
|
+
# @example
|
41
|
+
# String.bar
|
42
|
+
# #=> NoMethodError: undefined method `bar' for String:Class
|
43
|
+
# @example
|
44
|
+
# MyString.add_meta_var(:x)
|
45
|
+
# MyString.x #=> HELLO
|
46
|
+
#
|
47
|
+
# @details [Description of Examples]
|
48
|
+
# As you can see, using #meta_class allows you to execute code (and here,
|
49
|
+
# define a method) on the metaclass itself. It also allows you to define
|
50
|
+
# class methods that can be run on subclasses, and then be able to execute
|
51
|
+
# code on the metaclass of the subclass (here MyString).
|
52
|
+
#
|
53
|
+
# In this case, we were able to define a class method (add_meta_var) on
|
54
|
+
# String that was executable by the MyString subclass. It was then able to
|
55
|
+
# define a method on the subclass by adding it to the MyString metaclass.
|
56
|
+
#
|
57
|
+
# For more information, you can check out _why's excellent article at:
|
58
|
+
# http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
|
59
|
+
def meta_class() class << self; self end end
|
60
|
+
|
61
|
+
# @return <TrueClass, FalseClass>
|
62
|
+
# True if the empty? is true or if the object responds to strip (e.g. a
|
63
|
+
# String) and strip.empty? is true, or if !self is true.
|
64
|
+
#
|
65
|
+
# @example [].blank? #=> true
|
66
|
+
# @example [1].blank? #=> false
|
67
|
+
# @example [nil].blank? #=> false
|
68
|
+
# @example nil.blank? #=> true
|
69
|
+
# @example true.blank? #=> false
|
70
|
+
# @example false.blank? #=> true
|
71
|
+
# @example "".blank? #=> true
|
72
|
+
# @example " ".blank? #=> true
|
73
|
+
# @example " hey ho ".blank? #=> false
|
74
|
+
def blank?
|
75
|
+
if respond_to?(:empty?) && respond_to?(:strip)
|
76
|
+
empty? or strip.empty?
|
77
|
+
elsif respond_to?(:empty?)
|
78
|
+
empty?
|
79
|
+
else
|
80
|
+
!self
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# @param name<String> The name of the constant to get, e.g. "Merb::Router".
|
85
|
+
#
|
86
|
+
# @return <Object> The constant corresponding to the name.
|
87
|
+
def full_const_get(name)
|
88
|
+
list = name.split("::")
|
89
|
+
list.shift if list.first.blank?
|
90
|
+
obj = self
|
91
|
+
list.each do |x|
|
92
|
+
# This is required because const_get tries to look for constants in the
|
93
|
+
# ancestor chain, but we only want constants that are HERE
|
94
|
+
obj = obj.const_defined?(x) ? obj.const_get(x) : obj.const_missing(x)
|
95
|
+
end
|
96
|
+
obj
|
97
|
+
end
|
98
|
+
|
99
|
+
# @param name<String> The name of the constant to get, e.g. "Merb::Router".
|
100
|
+
# @param value<Object> The value to assign to the constant.
|
101
|
+
#
|
102
|
+
# @return <Object> The constant corresponding to the name.
|
103
|
+
def full_const_set(name, value)
|
104
|
+
list = name.split("::")
|
105
|
+
toplevel = list.first.blank?
|
106
|
+
list.shift if toplevel
|
107
|
+
last = list.pop
|
108
|
+
obj = list.empty? ? Object : Object.full_const_get(list.join("::"))
|
109
|
+
obj.const_set(last, value) if obj && !obj.const_defined?(last)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Defines module from a string name (e.g. Foo::Bar::Baz)
|
113
|
+
# If module already exists, no exception raised.
|
114
|
+
#
|
115
|
+
# @param name<String> The name of the full module name to make
|
116
|
+
#
|
117
|
+
# @return <NilClass>
|
118
|
+
def make_module(str)
|
119
|
+
mod = str.split("::")
|
120
|
+
start = mod.map {|x| "module #{x}"}.join("; ")
|
121
|
+
ender = (["end"] * mod.size).join("; ")
|
122
|
+
self.class_eval <<-HERE
|
123
|
+
#{start}
|
124
|
+
#{ender}
|
125
|
+
HERE
|
126
|
+
end
|
127
|
+
|
128
|
+
# @param duck<Symbol, Class, Array> The thing to compare the object to.
|
129
|
+
#
|
130
|
+
# @note
|
131
|
+
# The behavior of the method depends on the type of duck as follows:
|
132
|
+
# Symbol:: Check whether the object respond_to?(duck).
|
133
|
+
# Class:: Check whether the object is_a?(duck).
|
134
|
+
# Array::
|
135
|
+
# Check whether the object quacks_like? at least one of the options in the
|
136
|
+
# array.
|
137
|
+
#
|
138
|
+
# @return <TrueClass, FalseClass>
|
139
|
+
# True if the object quacks like duck.
|
140
|
+
def quacks_like?(duck)
|
141
|
+
case duck
|
142
|
+
when Symbol
|
143
|
+
self.respond_to?(duck)
|
144
|
+
when Class
|
145
|
+
self.is_a?(duck)
|
146
|
+
when Array
|
147
|
+
duck.any? {|d| self.quacks_like?(d) }
|
148
|
+
else
|
149
|
+
false
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# @param arrayish<#include?> Container to check, to see if it includes the object.
|
154
|
+
# @param *more<Array>:: additional args, will be flattened into arrayish
|
155
|
+
#
|
156
|
+
# @return <TrueClass, FalseClass>
|
157
|
+
# True if the object is included in arrayish (+ more)
|
158
|
+
#
|
159
|
+
# @example 1.in?([1,2,3]) #=> true
|
160
|
+
# @example 1.in?(1,2,3) #=> true
|
161
|
+
def in?(arrayish,*more)
|
162
|
+
arrayish = more.unshift(arrayish) unless more.empty?
|
163
|
+
arrayish.include?(self)
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module Extlib
|
5
|
+
# ==== Notes
|
6
|
+
# Provides pooling support to class it got included in.
|
7
|
+
#
|
8
|
+
# Pooling of objects is a faster way of aquiring instances
|
9
|
+
# of objects compared to regular allocation and initialization
|
10
|
+
# because instances are keeped in memory reused.
|
11
|
+
#
|
12
|
+
# Classes that include Pooling module have re-defined new
|
13
|
+
# method that returns instances acquired from pool.
|
14
|
+
#
|
15
|
+
# Term resource is used for any type of poolable objects
|
16
|
+
# and should NOT be thought as DataMapper Resource or
|
17
|
+
# ActiveResource resource and such.
|
18
|
+
#
|
19
|
+
# In Data Objects connections are pooled so that it is
|
20
|
+
# unnecessary to allocate and initialize connection object
|
21
|
+
# each time connection is needed, like per request in a
|
22
|
+
# web application.
|
23
|
+
#
|
24
|
+
# Pool obviously has to be thread safe because state of
|
25
|
+
# object is reset when it is released.
|
26
|
+
module Pooling
|
27
|
+
|
28
|
+
def self.scavenger
|
29
|
+
@scavenger || begin
|
30
|
+
@scavenger = Thread.new do
|
31
|
+
loop do
|
32
|
+
lock.synchronize do
|
33
|
+
pools.each do |pool|
|
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
|
+
end
|
40
|
+
end
|
41
|
+
# end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
sleep(scavenger_interval)
|
45
|
+
end # loop
|
46
|
+
end
|
47
|
+
|
48
|
+
@scavenger.priority = -10
|
49
|
+
@scavenger
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.pools
|
54
|
+
@pools ||= Set.new
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.append_pool(pool)
|
58
|
+
lock.synchronize do
|
59
|
+
pools << pool
|
60
|
+
end
|
61
|
+
Extlib::Pooling::scavenger
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.lock
|
65
|
+
@lock ||= Mutex.new
|
66
|
+
end
|
67
|
+
|
68
|
+
class CrossPoolError < StandardError
|
69
|
+
end
|
70
|
+
|
71
|
+
class OrphanedObjectError < StandardError
|
72
|
+
end
|
73
|
+
|
74
|
+
class ThreadStopError < StandardError
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.included(target)
|
78
|
+
target.class_eval do
|
79
|
+
class << self
|
80
|
+
alias __new new
|
81
|
+
end
|
82
|
+
|
83
|
+
@__pools = Hash.new { |h,k| __pool_lock.synchronize { h[k] = Pool.new(target.pool_size, target, k) } }
|
84
|
+
@__pool_lock = Mutex.new
|
85
|
+
|
86
|
+
def self.__pool_lock
|
87
|
+
@__pool_lock
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.new(*args)
|
91
|
+
@__pools[args].new
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.__pools
|
95
|
+
@__pools
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.pool_size
|
99
|
+
8
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def release
|
105
|
+
@__pool.release(self) unless @__pool.nil?
|
106
|
+
end
|
107
|
+
|
108
|
+
class Pool
|
109
|
+
def initialize(max_size, resource, args)
|
110
|
+
raise ArgumentError.new("+max_size+ should be a Fixnum but was #{max_size.inspect}") unless Fixnum === max_size
|
111
|
+
raise ArgumentError.new("+resource+ should be a Class but was #{resource.inspect}") unless Class === resource
|
112
|
+
|
113
|
+
@max_size = max_size
|
114
|
+
@resource = resource
|
115
|
+
@args = args
|
116
|
+
|
117
|
+
@available = []
|
118
|
+
@reserved_count = 0
|
119
|
+
end
|
120
|
+
|
121
|
+
def lock
|
122
|
+
@resource.__pool_lock
|
123
|
+
end
|
124
|
+
|
125
|
+
def scavenge_interval
|
126
|
+
@resource.scavenge_interval
|
127
|
+
end
|
128
|
+
|
129
|
+
def new
|
130
|
+
instance = nil
|
131
|
+
|
132
|
+
lock.synchronize do
|
133
|
+
instance = acquire
|
134
|
+
end
|
135
|
+
|
136
|
+
Extlib::Pooling::append_pool(self)
|
137
|
+
|
138
|
+
if instance.nil?
|
139
|
+
# Account for the current thread, and the pool scavenger.
|
140
|
+
if ThreadGroup::Default.list.size == 2 && @reserved_count >= @max_size
|
141
|
+
raise ThreadStopError.new(size)
|
142
|
+
else
|
143
|
+
sleep(0.05)
|
144
|
+
new
|
145
|
+
end
|
146
|
+
else
|
147
|
+
instance
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def release(instance)
|
152
|
+
lock.synchronize do
|
153
|
+
instance.instance_variable_set(:@__pool, nil)
|
154
|
+
@reserved_count -= 1
|
155
|
+
@available.push(instance)
|
156
|
+
end
|
157
|
+
nil
|
158
|
+
end
|
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
|
+
|
168
|
+
def size
|
169
|
+
@available.size + @reserved_count
|
170
|
+
end
|
171
|
+
alias length size
|
172
|
+
|
173
|
+
def inspect
|
174
|
+
"#<Extlib::Pooling::Pool<#{@resource.name}> available=#{@available.size} reserved_count=#{@reserved_count}>"
|
175
|
+
end
|
176
|
+
|
177
|
+
def flush!
|
178
|
+
@available.pop.dispose until @available.empty?
|
179
|
+
end
|
180
|
+
|
181
|
+
def dispose
|
182
|
+
flush!
|
183
|
+
@resource.__pools.delete(@args)
|
184
|
+
!Extlib::Pooling::pools.delete?(self).nil?
|
185
|
+
end
|
186
|
+
|
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
|
204
|
+
end
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
def acquire
|
209
|
+
instance = if !@available.empty?
|
210
|
+
@available.pop
|
211
|
+
elsif size < @max_size
|
212
|
+
@resource.__new(*@args)
|
213
|
+
else
|
214
|
+
nil
|
215
|
+
end
|
216
|
+
|
217
|
+
if instance.nil?
|
218
|
+
instance
|
219
|
+
else
|
220
|
+
raise CrossPoolError.new(instance) if instance.instance_variable_get(:@__pool)
|
221
|
+
@reserved_count += 1
|
222
|
+
instance.instance_variable_set(:@__pool, self)
|
223
|
+
instance.instance_variable_set(:@__allocated_in_pool, Time.now)
|
224
|
+
instance
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def self.scavenger_interval
|
230
|
+
60
|
231
|
+
end
|
232
|
+
end # module Pooling
|
233
|
+
end # module Extlib
|