data_objects 0.9.9 → 0.9.10

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.
data/Manifest.txt CHANGED
@@ -13,7 +13,6 @@ lib/data_objects/logger.rb
13
13
  lib/data_objects/quoting.rb
14
14
  lib/data_objects/reader.rb
15
15
  lib/data_objects/result.rb
16
- lib/data_objects/support/pooling.rb
17
16
  lib/data_objects/transaction.rb
18
17
  lib/data_objects/uri.rb
19
18
  lib/data_objects/version.rb
@@ -25,5 +24,5 @@ spec/reader_spec.rb
25
24
  spec/result_spec.rb
26
25
  spec/spec.opts
27
26
  spec/spec_helper.rb
28
- spec/support/pooling_spec.rb
29
27
  spec/transaction_spec.rb
28
+ spec/uri_spec.rb
data/Rakefile CHANGED
@@ -1,9 +1,12 @@
1
- require 'rubygems'
2
1
  require 'pathname'
2
+ require 'rubygems'
3
3
  require 'spec/rake/spectask'
4
4
  require 'lib/data_objects/version'
5
5
 
6
- ROOT = Pathname(__FILE__).dirname.expand_path
6
+ ROOT = Pathname(__FILE__).dirname.expand_path
7
+ JRUBY = RUBY_PLATFORM =~ /java/
8
+ WINDOWS = Gem.win_platform?
9
+ SUDO = (WINDOWS || JRUBY) ? '' : ('sudo' unless ENV['SUDOLESS'])
7
10
 
8
11
  AUTHOR = "Yehuda Katz"
9
12
  EMAIL = "wycats@gmail.com"
@@ -17,25 +20,29 @@ PROJECT_NAME = "dorb"
17
20
  PROJECT_URL = "http://rubyforge.org/projects/dorb"
18
21
  PROJECT_DESCRIPTION = PROJECT_SUMMARY = "The Core DataObjects class"
19
22
 
20
- DRIVER = false
23
+ JAVA_DRIVER = false
24
+
25
+ # RCov is run by default, except on the JRuby platform, or if NO_RCOV env is true
26
+ RUN_RCOV = JRUBY ? false : (ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true)
21
27
 
22
28
  if (tasks_dir = ROOT.parent + 'tasks').directory?
23
29
  require tasks_dir + 'hoe'
24
30
  end
25
31
 
26
- # Installation
32
+ def sudo_gem(cmd)
33
+ sh "#{SUDO} #{RUBY} -S gem #{cmd}", :verbose => false
34
+ end
27
35
 
28
- WINDOWS = (RUBY_PLATFORM =~ /mswin|mingw|cygwin/) rescue nil
29
- SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS'])
36
+ # Installation
30
37
 
31
- desc "Install #{GEM_NAME} #{GEM_VERSION} (default ruby)"
38
+ desc "Install #{GEM_NAME} #{GEM_VERSION}"
32
39
  task :install => [ :package ] do
33
- sh %{#{SUDO} gem install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources}, :verbose => false
40
+ sudo_gem "install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources"
34
41
  end
35
42
 
36
- desc "Uninstall #{GEM_NAME} #{GEM_VERSION} (default ruby)"
43
+ desc "Uninstall #{GEM_NAME} #{GEM_VERSION}"
37
44
  task :uninstall => [ :clobber ] do
38
- sh "#{SUDO} gem uninstall #{GEM_NAME} -v#{GEM_VERSION} -I -x", :verbose => false
45
+ sudo_gem "uninstall #{GEM_NAME} -v#{GEM_VERSION} -I -x"
39
46
  end
40
47
 
41
48
  # Specs
@@ -46,7 +53,7 @@ Spec::Rake::SpecTask.new(:spec) do |t|
46
53
  t.spec_files = Pathname.glob(ENV['FILES'] || 'spec/**/*_spec.rb')
47
54
 
48
55
  begin
49
- t.rcov = ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true
56
+ t.rcov = RUN_RCOV
50
57
  t.rcov_opts << '--exclude' << 'spec'
51
58
  t.rcov_opts << '--text-summary'
52
59
  t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
@@ -55,14 +62,6 @@ Spec::Rake::SpecTask.new(:spec) do |t|
55
62
  end
56
63
  end
57
64
 
58
- # JRuby
59
- namespace :jruby do
60
- desc "Install #{GEM_NAME} #{GEM_VERSION} with JRuby"
61
- task :install => [ :package ] do
62
- sh %{#{SUDO} jruby -S gem install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources}, :verbose => false
63
- end
64
- end
65
-
66
65
  namespace :ci do
67
66
 
68
67
  task :prepare do
@@ -88,4 +87,4 @@ namespace :ci do
88
87
 
89
88
  end
90
89
 
91
- task :ci => ["ci:spec"]
90
+ task :ci => ["ci:spec"]
@@ -8,16 +8,36 @@ end
8
8
  module DataObjects
9
9
  class Connection
10
10
 
11
- def self.new(uri)
12
- uri = DataObjects::URI::parse(uri)
11
+ def self.new(uri_s)
12
+ uri = DataObjects::URI::parse(uri_s)
13
+
14
+ case uri.scheme.to_sym
15
+ when :java
16
+ warn 'JNDI URLs (connection strings) are only for use with JRuby' unless RUBY_PLATFORM =~ /java/
17
+ # TODO: handle jndi connection strings
18
+ when :jdbc
19
+ warn 'JDBC URLs (connection strings) are only for use with JRuby' unless RUBY_PLATFORM =~ /java/
20
+
21
+ driver_name = if uri.path.split(':').first == 'sqlite'
22
+ 'sqlite3'
23
+ elsif uri.path.split(':').first == 'postgresql'
24
+ 'postgres'
25
+ else
26
+ uri.path.split(':').first
27
+ end
13
28
 
14
- if uri.scheme == 'jdbc'
15
- driver_name = uri.path.split(':').first
29
+ conn_uri = uri_s # NOTE: for now, do not reformat this JDBC connection
30
+ # string -- or, in other words, do not let
31
+ # DataObjects::URI#to_s be called -- as it is not
32
+ # correctly handling JDBC URLs, and in doing so, causing
33
+ # java.sql.DriverManager.getConnection to throw a
34
+ # 'No suitable driver found for...' exception.
16
35
  else
17
- driver_name = uri.scheme.capitalize
36
+ driver_name = uri.scheme
37
+ conn_uri = uri
18
38
  end
19
39
 
20
- DataObjects.const_get(driver_name.capitalize)::Connection.new(uri)
40
+ DataObjects.const_get(driver_name.capitalize)::Connection.new(conn_uri)
21
41
  end
22
42
 
23
43
  def self.inherited(target)
@@ -45,6 +45,7 @@ module DataObjects
45
45
  when Array then quote_array(value)
46
46
  when Range then quote_range(value)
47
47
  when Symbol then quote_symbol(value)
48
+ when Regexp then quote_regexp(value)
48
49
  else
49
50
  if value.respond_to?(:to_sql)
50
51
  value.to_sql
@@ -93,6 +94,10 @@ module DataObjects
93
94
  def quote_range(value)
94
95
  "#{quote_value(value.first)} AND #{quote_value(value.last)}"
95
96
  end
97
+
98
+ def quote_regexp(value)
99
+ quote_string(value.source)
100
+ end
96
101
  end
97
102
 
98
103
  end
@@ -8,7 +8,7 @@ module DataObjects
8
8
  def self.parse(uri)
9
9
  return uri if uri.kind_of?(self)
10
10
  uri = Addressable::URI::parse(uri) unless uri.kind_of?(Addressable::URI)
11
- self.new(uri.scheme, uri.user, uri.password, uri.host, uri.port, uri.path, uri.query, uri.fragment)
11
+ self.new(uri.scheme, uri.user, uri.password, uri.host, uri.port, uri.path, uri.query_values, uri.fragment)
12
12
  end
13
13
 
14
14
  def to_s
@@ -22,7 +22,11 @@ module DataObjects
22
22
  string << "#{host}" if host
23
23
  string << ":#{port}" if port
24
24
  string << path.to_s
25
- string << "?#{query}" if query
25
+ if query
26
+ string << "?" << query.map do |key, value|
27
+ "#{key}=#{value}"
28
+ end.join("&")
29
+ end
26
30
  string << "##{fragment}" if fragment
27
31
  string
28
32
  end
@@ -1,3 +1,3 @@
1
1
  module DataObjects
2
- VERSION = "0.9.9" unless defined?(DataObjects::VERSION)
2
+ VERSION = "0.9.10" unless defined?(DataObjects::VERSION)
3
3
  end
data/lib/data_objects.rb CHANGED
@@ -3,7 +3,7 @@ require 'rubygems'
3
3
  gem 'extlib', '~>0.9.8'
4
4
  require 'extlib'
5
5
 
6
- require File.expand_path(File.join(File.dirname(__FILE__), 'data_objects', 'support', 'pooling'))
6
+ require File.expand_path(File.join(File.dirname(__FILE__), 'data_objects', 'version'))
7
7
  require File.expand_path(File.join(File.dirname(__FILE__), 'data_objects', 'logger'))
8
8
  require File.expand_path(File.join(File.dirname(__FILE__), 'data_objects', 'connection'))
9
9
  require File.expand_path(File.join(File.dirname(__FILE__), 'data_objects', 'uri'))
@@ -40,8 +40,22 @@ describe DataObjects::Connection do
40
40
  c = DataObjects::Connection.new(Addressable::URI.parse('mock://localhost/database'))
41
41
  c.should be_kind_of(DataObjects::Mock::Connection)
42
42
 
43
- c = DataObjects::Connection.new(Addressable::URI.parse('jdbc:mock://localhost/database'))
44
- c.should be_kind_of(DataObjects::Mock::Connection)
43
+ c = DataObjects::Connection.new(Addressable::URI.parse('mock:jndi://jdbc/database'))
44
+ #c.should be_kind_of(DataObjects::Mock::Connection)
45
+ end
46
+
47
+ it "should return the Connection using username" do
48
+ c = DataObjects::Connection.new(Addressable::URI.parse('mock://root@localhost/database'))
49
+ c.instance_variable_get(:@uri).user.should == 'root'
50
+ c.instance_variable_get(:@uri).password.should be_nil
51
+
52
+ c = DataObjects::Connection.new(Addressable::URI.parse('mock://root:@localhost/database'))
53
+ c.instance_variable_get(:@uri).user.should == 'root'
54
+ c.instance_variable_get(:@uri).password.should == ''
55
+
56
+ c = DataObjects::Connection.new(Addressable::URI.parse('mock://root:pwd@localhost/database'))
57
+ c.instance_variable_get(:@uri).user.should == 'root'
58
+ c.instance_variable_get(:@uri).password.should == 'pwd'
45
59
  end
46
60
  end
47
61
  end
data/spec/uri_spec.rb ADDED
@@ -0,0 +1,44 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ describe DataObjects::URI do
4
+ before do
5
+ @uri = DataObjects::URI.parse('mock://username:password@localhost:12345/path?encoding=utf8#fragment')
6
+ end
7
+
8
+ it "should parse the scheme part" do
9
+ @uri.scheme.should == "mock"
10
+ end
11
+
12
+ it "should parse the user part" do
13
+ @uri.user.should == "username"
14
+ end
15
+
16
+ it "should parse the password part" do
17
+ @uri.password.should == "password"
18
+ end
19
+
20
+ it "should parse the host part" do
21
+ @uri.host.should == "localhost"
22
+ end
23
+
24
+ it "should parse the port part" do
25
+ @uri.port.should == 12345
26
+ end
27
+
28
+ it "should parse the path part" do
29
+ @uri.path.should == "/path"
30
+ end
31
+
32
+ it "should parse the query part" do
33
+ @uri.query.should == { "encoding" => "utf8" }
34
+ end
35
+
36
+ it "should parse the fragment part" do
37
+ @uri.fragment.should == "fragment"
38
+ end
39
+
40
+ it "should provide a correct string representation" do
41
+ @uri.to_s.should == 'mock://username:password@localhost:12345/path?encoding=utf8#fragment'
42
+ end
43
+
44
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: data_objects
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.9
4
+ version: 0.9.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yehuda Katz
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-11-27 00:00:00 -08:00
12
+ date: 2009-01-04 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -69,7 +69,6 @@ files:
69
69
  - lib/data_objects/quoting.rb
70
70
  - lib/data_objects/reader.rb
71
71
  - lib/data_objects/result.rb
72
- - lib/data_objects/support/pooling.rb
73
72
  - lib/data_objects/transaction.rb
74
73
  - lib/data_objects/uri.rb
75
74
  - lib/data_objects/version.rb
@@ -81,8 +80,8 @@ files:
81
80
  - spec/result_spec.rb
82
81
  - spec/spec.opts
83
82
  - spec/spec_helper.rb
84
- - spec/support/pooling_spec.rb
85
83
  - spec/transaction_spec.rb
84
+ - spec/uri_spec.rb
86
85
  has_rdoc: true
87
86
  homepage: http://rubyforge.org/projects/dorb
88
87
  post_install_message:
@@ -1,236 +0,0 @@
1
- require 'set'
2
-
3
- class Object
4
- # ==== Notes
5
- # Provides pooling support to class it got included in.
6
- #
7
- # Pooling of objects is a faster way of aquiring instances
8
- # of objects compared to regular allocation and initialization
9
- # because instances are keeped in memory reused.
10
- #
11
- # Classes that include Pooling module have re-defined new
12
- # method that returns instances acquired from pool.
13
- #
14
- # Term resource is used for any type of poolable objects
15
- # and should NOT be thought as DataMapper Resource or
16
- # ActiveResource resource and such.
17
- #
18
- # In Data Objects connections are pooled so that it is
19
- # unnecessary to allocate and initialize connection object
20
- # each time connection is needed, like per request in a
21
- # web application.
22
- #
23
- # Pool obviously has to be thread safe because state of
24
- # object is reset when it is released.
25
- module Pooling
26
- def self.included(base)
27
- base.send(:extend, ClassMethods)
28
- end
29
-
30
- module ClassMethods
31
- # ==== Notes
32
- # Initializes the pool and returns it.
33
- #
34
- # ==== Parameters
35
- # size_limit<Fixnum>:: maximum size of the pool.
36
- #
37
- # ==== Returns
38
- # <ResourcePool>:: initialized pool
39
- def initialize_pool(size_limit, options = {})
40
- @__pool.flush! if @__pool
41
-
42
- @__pool = ResourcePool.new(size_limit, self, options)
43
- end
44
-
45
- # ==== Notes
46
- # Instances of poolable resource are acquired from
47
- # pool. This quires a new instance from pool and
48
- # returns it.
49
- #
50
- # ==== Returns
51
- # Resource instance acquired from the pool.
52
- #
53
- # ==== Raises
54
- # ArgumentError:: when pool is exhausted and no instance
55
- # can be acquired.
56
- def new
57
- pool.acquire
58
- end
59
-
60
- # ==== Notes
61
- # Returns pool for this resource class.
62
- # Initialization is done when necessary.
63
- # Default size limit of the pool is 10.
64
- #
65
- # ==== Returns
66
- # <Object::Pooling::ResourcePool>:: pool for this resource class.
67
- def pool
68
- @__pool ||= ResourcePool.new(10, self)
69
- end
70
- end
71
-
72
- # ==== Notes
73
- # Pool
74
- #
75
- class ResourcePool
76
- attr_reader :size_limit, :class_of_resources, :expiration_period
77
-
78
- # ==== Notes
79
- # Initializes resource pool.
80
- #
81
- # ==== Parameters
82
- # size_limit<Fixnum>:: maximum number of resources in the pool.
83
- # class_of_resources<Class>:: class of resource.
84
- #
85
- # ==== Raises
86
- # ArgumentError:: when class of resource does not implement
87
- # dispose instance method or is not a Class.
88
- def initialize(size_limit, class_of_resources, options)
89
- raise ArgumentError.new("Expected class of resources to be instance of Class, got: #{class_of_resources.class}") unless class_of_resources.is_a?(Class)
90
- raise ArgumentError.new("Class #{class_of_resources} must implement dispose instance method to be poolable.") unless class_of_resources.instance_methods.include?("dispose")
91
-
92
- @size_limit = size_limit
93
- @class_of_resources = class_of_resources
94
-
95
- @reserved = Set.new
96
- @available = []
97
- @lock = Mutex.new
98
-
99
- initialization_args = options.delete(:initialization_args) || []
100
-
101
- @expiration_period = options.delete(:expiration_period) || 60
102
- @initialization_args = [*initialization_args]
103
-
104
- @pool_expiration_thread = Thread.new do
105
- while true
106
- release_outdated
107
-
108
- sleep (@expiration_period + 1)
109
- end
110
- end
111
- end
112
-
113
- # ==== Notes
114
- # Current size of pool: number of already reserved
115
- # resources.
116
- def size
117
- @reserved.size
118
- end
119
-
120
- # ==== Notes
121
- # Indicates if pool has resources to acquire.
122
- #
123
- # ==== Returns
124
- # <Boolean>:: true if pool has resources can be acquired,
125
- # false otherwise.
126
- def available?
127
- @reserved.size < size_limit
128
- end
129
-
130
- # ==== Notes
131
- # Acquires last used available resource and returns it.
132
- # If no resources available, current implementation
133
- # throws an exception.
134
- def acquire
135
- @lock.synchronize do
136
- if available?
137
- instance = prepair_available_resource
138
- @reserved << instance
139
-
140
- instance
141
- else
142
- raise RuntimeError
143
- end
144
- end
145
- end
146
-
147
- # ==== Notes
148
- # Releases previously acquired instance.
149
- #
150
- # ==== Parameters
151
- # instance <Anything>:: previosly acquired instance.
152
- #
153
- # ==== Raises
154
- # RuntimeError:: when given not pooled instance.
155
- def release(instance)
156
- @lock.synchronize do
157
- if @reserved.include?(instance)
158
- @reserved.delete(instance)
159
- instance.dispose
160
- @available << instance
161
- else
162
- raise RuntimeError
163
- end
164
- end
165
- end
166
-
167
- # ==== Notes
168
- # Releases all objects in the pool.
169
- #
170
- # ==== Returns
171
- # nil
172
- def flush!
173
- @reserved.each do |instance|
174
- self.release(instance)
175
- end
176
-
177
- nil
178
- end
179
-
180
- # ==== Notes
181
- # Check if instance has been acquired from the pool.
182
- #
183
- # ==== Returns
184
- # <Boolean>:: true if given resource instance has been acquired from pool,
185
- # false otherwise.
186
- def acquired?(instance)
187
- @reserved.include?(instance)
188
- end
189
-
190
- # ==== Notes
191
- # Releases instances that haven't been in use and
192
- # hit the expiration period.
193
- #
194
- # ==== Returns
195
- # nil
196
- def release_outdated
197
- @reserved.each do |instance|
198
- release(instance) if time_to_release?(instance)
199
- end
200
-
201
- nil
202
- end
203
-
204
- # ==== Notes
205
- # Checks if pooled resource instance is outdated and
206
- # should be released.
207
- #
208
- # ==== Returns
209
- # <Boolean>:: true if instance should be released, false otherwise.
210
- def time_to_release?(instance)
211
- (Time.now - instance.instance_variable_get("@__pool_acquire_timestamp")) > @expiration_period
212
- end
213
-
214
- protected
215
-
216
- # ==== Notes
217
- # Either allocates new resource,
218
- # or takes last used available resource from
219
- # the pool.
220
- def prepair_available_resource
221
- if @available.size > 0
222
- res = @available.pop
223
- res.instance_variable_set("@__pool_acquire_timestamp", Time.now)
224
-
225
- res
226
- else
227
- res = @class_of_resources.allocate
228
- res.send(:initialize, *@initialization_args)
229
- res.instance_variable_set("@__pool_acquire_timestamp", Time.now)
230
-
231
- res
232
- end
233
- end
234
- end # ResourcePool
235
- end
236
- end
@@ -1,374 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
- require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'data_objects', 'support', 'pooling')
3
- require 'timeout'
4
-
5
- # This implements dispose
6
- # and works perfectly with
7
- # pooling.
8
- class DisposableResource
9
- include Object::Pooling
10
- attr_reader :name
11
-
12
- def initialize(name = "")
13
- @name = name
14
- end
15
-
16
- def dispose
17
- @name = nil
18
- end
19
- end
20
-
21
- # This baby causes exceptions
22
- # to be raised when you use
23
- # it with pooling.
24
- class UndisposableResource
25
- end
26
-
27
- describe Object::Pooling::ResourcePool do
28
- before :each do
29
- @pool = Object::Pooling::ResourcePool.new(7, DisposableResource, :expiration_period => 50)
30
- end
31
-
32
- it "responds to flush!" do
33
- @pool.should respond_to(:flush!)
34
- end
35
-
36
- it "responds to acquire" do
37
- @pool.should respond_to(:acquire)
38
- end
39
-
40
- it "responds to release" do
41
- @pool.should respond_to(:release)
42
- end
43
-
44
- it "responds to :available?" do
45
- @pool.should respond_to(:available?)
46
- end
47
-
48
- it "has a size limit" do
49
- @pool.size_limit.should == 7
50
- end
51
-
52
- it "has initial size of zero" do
53
- @pool.size.should == 0
54
- end
55
-
56
- it "has a set of reserved resources" do
57
- @pool.instance_variable_get("@reserved").should be_empty
58
- end
59
-
60
- it "has a set of available resources" do
61
- @pool.instance_variable_get("@available").should be_empty
62
- end
63
-
64
- it "knows class of resources (objects) it works with" do
65
- @pool.class_of_resources.should == DisposableResource
66
- end
67
-
68
- it "raises exception when given anything but class for resources class" do
69
- lambda {
70
- @pool = Object::Pooling::ResourcePool.new(7, "Hooray!", {})
71
- }.should raise_error(ArgumentError, /class/)
72
- end
73
-
74
- it "requires class of resources (objects) it works with to have a dispose instance method" do
75
- lambda {
76
- @pool = Object::Pooling::ResourcePool.new(3, UndisposableResource, {})
77
- }.should raise_error(ArgumentError, /dispose/)
78
- end
79
-
80
- it "may take initialization arguments" do
81
- @pool = Object::Pooling::ResourcePool.new(7, DisposableResource, { :initialization_args => ["paper"] })
82
- @pool.instance_variable_get("@initialization_args").should == ["paper"]
83
- end
84
-
85
- it "may take expiration period option" do
86
- @pool = Object::Pooling::ResourcePool.new(7, DisposableResource, { :expiration_period => 100 })
87
- @pool.expiration_period.should == 100
88
- end
89
-
90
- it "has default expiration period of one minute" do
91
- @pool = Object::Pooling::ResourcePool.new(7, DisposableResource, {})
92
- @pool.expiration_period.should == 60
93
- end
94
-
95
- it "spawns a thread to dispose objects haven't been used for a while" do
96
- @pool = Object::Pooling::ResourcePool.new(7, DisposableResource, {})
97
- @pool.instance_variable_get("@pool_expiration_thread").should be_an_instance_of(Thread)
98
- end
99
- end
100
-
101
-
102
-
103
- describe "Acquire from constant size pool" do
104
- before :each do
105
- DisposableResource.initialize_pool(2)
106
- end
107
-
108
- after :each do
109
- DisposableResource.instance_variable_set("@__pool", nil)
110
- end
111
-
112
- it "increased size of the pool" do
113
- @time = DisposableResource.pool.acquire
114
- DisposableResource.pool.size.should == 1
115
- end
116
-
117
- it "places initialized instance in the reserved set" do
118
- @time = DisposableResource.pool.acquire
119
- DisposableResource.pool.instance_variable_get("@reserved").size.should == 1
120
- end
121
-
122
- it "raises an exception when pool size limit is hit" do
123
- @t1 = DisposableResource.pool.acquire
124
- @t2 = DisposableResource.pool.acquire
125
-
126
- lambda { DisposableResource.pool.acquire }.should raise_error(RuntimeError)
127
- end
128
-
129
- it "returns last released resource" do
130
- @t1 = DisposableResource.pool.acquire
131
- @t2 = DisposableResource.pool.acquire
132
- DisposableResource.pool.release(@t1)
133
-
134
- DisposableResource.pool.acquire.should == @t1
135
- end
136
-
137
- it "really truly returns last released resource" do
138
- @t1 = DisposableResource.pool.acquire
139
- DisposableResource.pool.release(@t1)
140
-
141
- @t2 = DisposableResource.pool.acquire
142
- DisposableResource.pool.release(@t2)
143
-
144
- @t3 = DisposableResource.pool.acquire
145
- DisposableResource.pool.release(@t3)
146
-
147
- DisposableResource.pool.acquire.should == @t1
148
- @t1.should == @t3
149
- end
150
-
151
- it "sets allocation timestamp on resource instance" do
152
- @t1 = DisposableResource.new
153
- @t1.instance_variable_get("@__pool_acquire_timestamp").should be_close(Time.now, 2)
154
- end
155
- end
156
-
157
-
158
-
159
- describe "Releasing from constant size pool" do
160
- before :each do
161
- DisposableResource.initialize_pool(2)
162
- end
163
-
164
- after :each do
165
- DisposableResource.instance_variable_set("@__pool", nil)
166
- end
167
-
168
- it "decreases size of the pool" do
169
- @t1 = DisposableResource.pool.acquire
170
- @t2 = DisposableResource.pool.acquire
171
- DisposableResource.pool.release(@t1)
172
-
173
- DisposableResource.pool.size.should == 1
174
- end
175
-
176
- it "raises an exception on attempt to releases object not in pool" do
177
- @t1 = DisposableResource.new
178
- @t2 = Set.new
179
-
180
- DisposableResource.pool.release(@t1)
181
- lambda { DisposableResource.pool.release(@t2) }.should raise_error(RuntimeError)
182
- end
183
-
184
- it "disposes released object" do
185
- @t1 = DisposableResource.pool.acquire
186
-
187
- @t1.should_receive(:dispose)
188
- DisposableResource.pool.release(@t1)
189
- end
190
-
191
- it "removes released object from reserved set" do
192
- @t1 = DisposableResource.pool.acquire
193
-
194
- lambda {
195
- DisposableResource.pool.release(@t1)
196
- }.should change(DisposableResource.pool.instance_variable_get("@reserved"), :size).by(-1)
197
- end
198
-
199
- it "returns released object back to available set" do
200
- @t1 = DisposableResource.pool.acquire
201
-
202
- lambda {
203
- DisposableResource.pool.release(@t1)
204
- }.should change(DisposableResource.pool.instance_variable_get("@available"), :size).by(1)
205
- end
206
-
207
- it "updates acquire timestamp on already allocated resource instance" do
208
- # acquire it once
209
- @t1 = DisposableResource.new
210
- # wait a bit
211
- sleep 3
212
-
213
- # check old timestamp
214
- @t1.instance_variable_get("@__pool_acquire_timestamp").should be_close(Time.now, 4)
215
-
216
- # re-acquire
217
- DisposableResource.pool.release(@t1)
218
- @t1 = DisposableResource.new
219
- # see timestamp is updated
220
- @t1.instance_variable_get("@__pool_acquire_timestamp").should be_close(Time.now, 2)
221
- end
222
- end
223
-
224
-
225
-
226
- describe Object::Pooling::ResourcePool, "#available?" do
227
- before :each do
228
- DisposableResource.initialize_pool(2)
229
- DisposableResource.new
230
- end
231
-
232
- after :each do
233
- DisposableResource.instance_variable_set("@__pool", nil)
234
- end
235
-
236
- it "returns true when pool has available instances" do
237
- DisposableResource.pool.should be_available
238
- end
239
-
240
- it "returns false when pool is exhausted" do
241
- # acquires the last available resource
242
- DisposableResource.new
243
- DisposableResource.pool.should_not be_available
244
- end
245
- end
246
-
247
-
248
-
249
- describe "Flushing of constant size pool" do
250
- before :each do
251
- DisposableResource.initialize_pool(2)
252
-
253
- @t1 = DisposableResource.new
254
- @t2 = DisposableResource.new
255
-
256
- # sanity check
257
- DisposableResource.pool.instance_variable_get("@reserved").should_not be_empty
258
- end
259
-
260
- after :each do
261
- DisposableResource.instance_variable_set("@__pool", nil)
262
- end
263
-
264
- it "disposes all pooled objects" do
265
- [@t1, @t2].each { |instance| instance.should_receive(:dispose) }
266
-
267
- DisposableResource.pool.flush!
268
- end
269
-
270
- it "empties reserved set" do
271
- DisposableResource.pool.flush!
272
-
273
- DisposableResource.pool.instance_variable_get("@reserved").should be_empty
274
- end
275
-
276
- it "returns all instances to available set" do
277
- DisposableResource.pool.flush!
278
-
279
- DisposableResource.pool.instance_variable_get("@available").size.should == 2
280
- end
281
- end
282
-
283
-
284
-
285
- describe "Poolable resource class" do
286
- before :each do
287
- DisposableResource.initialize_pool(3, :initialization_args => ["paper"])
288
- end
289
-
290
- after :each do
291
- DisposableResource.instance_variable_set("@__pool", nil)
292
- end
293
-
294
- it "acquires new instances from pool" do
295
- @instance_one = DisposableResource.new
296
-
297
- DisposableResource.pool.acquired?(@instance_one).should be(true)
298
- end
299
-
300
- it "flushed existing pool on re-initialization" do
301
- DisposableResource.pool.should_receive(:flush!)
302
- DisposableResource.initialize_pool(5)
303
- end
304
-
305
- it "replaces pool on re-initialization" do
306
- DisposableResource.initialize_pool(5)
307
- DisposableResource.pool.size_limit.should == 5
308
- end
309
-
310
- it "passes initialization parameters to newly created resource instances" do
311
- DisposableResource.new.name.should == "paper"
312
- end
313
- end
314
-
315
-
316
-
317
- describe "Pooled object", "on initialization" do
318
- after :each do
319
- DisposableResource.instance_variable_set("@__pool", nil)
320
- end
321
-
322
- it "does not flush pool" do
323
- # using pool here initializes the pool first
324
- # so we use instance variable directly
325
- DisposableResource.instance_variable_get("@__pool").should_not_receive(:flush!)
326
- DisposableResource.initialize_pool(23)
327
- end
328
-
329
- it "flushes pool first when re-initialized" do
330
- DisposableResource.initialize_pool(5)
331
- DisposableResource.pool.should_receive(:flush!)
332
- DisposableResource.initialize_pool(23)
333
- end
334
- end
335
-
336
-
337
-
338
- describe Object::Pooling::ResourcePool, "#time_to_dispose?" do
339
- before :each do
340
- DisposableResource.initialize_pool(7, :expiration_period => 2)
341
- end
342
-
343
- after :each do
344
- DisposableResource.instance_variable_set("@__pool", nil)
345
- end
346
-
347
- it "returns true when object's last acquisition time is greater than limit" do
348
- @t1 = DisposableResource.new
349
- DisposableResource.pool.time_to_release?(@t1).should be(false)
350
-
351
- sleep 3
352
- DisposableResource.pool.time_to_release?(@t1).should be(true)
353
- end
354
- end
355
-
356
-
357
-
358
- describe Object::Pooling::ResourcePool, "#dispose_outdated" do
359
- before :each do
360
- DisposableResource.initialize_pool(7, :expiration_period => 2)
361
- end
362
-
363
- after :each do
364
- DisposableResource.instance_variable_set("@__pool", nil)
365
- end
366
-
367
- it "releases and thus disposes outdated instances" do
368
- @t1 = DisposableResource.new
369
- DisposableResource.pool.should_receive(:time_to_release?).with(@t1).and_return(true)
370
- DisposableResource.pool.should_receive(:release).with(@t1)
371
-
372
- DisposableResource.pool.release_outdated
373
- end
374
- end