socketpool 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +28 -0
- data/LICENSE.txt +12 -0
- data/README.rdoc +44 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/lib/socketpool.rb +174 -0
- data/spec/socketpool_spec.rb +75 -0
- data/spec/spec_helper.rb +12 -0
- metadata +155 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "rspec", "~> 2.3.0"
|
10
|
+
gem "bundler", "~> 1.0.0"
|
11
|
+
gem "jeweler", "~> 1.5.2"
|
12
|
+
gem "rcov", ">= 0"
|
13
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
git (1.2.5)
|
6
|
+
jeweler (1.5.2)
|
7
|
+
bundler (~> 1.0.0)
|
8
|
+
git (>= 1.2.5)
|
9
|
+
rake
|
10
|
+
rake (0.8.7)
|
11
|
+
rcov (0.9.9)
|
12
|
+
rspec (2.3.0)
|
13
|
+
rspec-core (~> 2.3.0)
|
14
|
+
rspec-expectations (~> 2.3.0)
|
15
|
+
rspec-mocks (~> 2.3.0)
|
16
|
+
rspec-core (2.3.1)
|
17
|
+
rspec-expectations (2.3.0)
|
18
|
+
diff-lcs (~> 1.1.2)
|
19
|
+
rspec-mocks (2.3.0)
|
20
|
+
|
21
|
+
PLATFORMS
|
22
|
+
ruby
|
23
|
+
|
24
|
+
DEPENDENCIES
|
25
|
+
bundler (~> 1.0.0)
|
26
|
+
jeweler (~> 1.5.2)
|
27
|
+
rcov
|
28
|
+
rspec (~> 2.3.0)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
3
|
+
you may not use this file except in compliance with the License.
|
4
|
+
You may obtain a copy of the License at
|
5
|
+
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
|
8
|
+
Unless required by applicable law or agreed to in writing, software
|
9
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
10
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
11
|
+
See the License for the specific language governing permissions and
|
12
|
+
limitations under the License.
|
data/README.rdoc
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
= socketpool
|
2
|
+
|
3
|
+
Class for managing a pool of sockets
|
4
|
+
|
5
|
+
== Using socketpool
|
6
|
+
|
7
|
+
Install:
|
8
|
+
|
9
|
+
gem install socketpool
|
10
|
+
|
11
|
+
Initialize a socket pool:
|
12
|
+
|
13
|
+
pool = SocketPool.new("127.0.0.1", "11211") # => a socket pool with a max size of 2, connected via tcp to 127.0.0.1:11211
|
14
|
+
pool = SocketPool.new("127.0.0.1", "11211", :size => 10) # => a socket pool with a max size of 10, connected via tcp to 127.0.0.1:11211
|
15
|
+
pool = SocketPool.new("127.0.0.1", "11211", :size => 10, :type => :udp) # => a socket pool with a max size of 10, connected via udp to 127.0.0.1:11211
|
16
|
+
|
17
|
+
s = pool.checkout #=> gets socket from pool
|
18
|
+
pool.checkin(s) #=> puts socket back in pool
|
19
|
+
|
20
|
+
Initialization Options:
|
21
|
+
:size #=> determines the max size of the socket pool (number of sockets that can eventually be in the pool)
|
22
|
+
:type #=> the "type" of socket in the pool: must be one of [:udp, :udp6, :tcp, :tcp6, :unix, :unigram]
|
23
|
+
#=> :unigram specifies a datagram unix socket; if using a unix socket then set host and port to the "path"
|
24
|
+
|
25
|
+
:eager #=> default false, if set to "true" then all sockets will be initialized on pool initialization
|
26
|
+
:timeout #=> defaults to 5.0, the number of seconds to wait for an unused socket from the pool to be freed
|
27
|
+
:socketopts #=> an array of options to be set (via setsockopts) on each socket initialization
|
28
|
+
#=> example: [{:level => Socket::IPPROTO_TCP, :optname => Socket::TCP_NODELAY, :optval => 1}]
|
29
|
+
|
30
|
+
== Credits
|
31
|
+
* "socketpool" is heavily influenced by utils/pool.rb from MongoDB (Apache 2.0 licensed).
|
32
|
+
The socket checkout/checkin functionality is a direct copy, unfortunately all of the functionality I wanted (like eager initialization) was not
|
33
|
+
implemented so I augmented it for "socketpool".
|
34
|
+
|
35
|
+
== Contributing to socketpool
|
36
|
+
|
37
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
38
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
39
|
+
* Fork the project
|
40
|
+
* Start a feature/bugfix branch
|
41
|
+
* Commit and push until you are happy with your contribution
|
42
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
43
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
44
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'rake'
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
gem.name = "socketpool"
|
15
|
+
gem.homepage = "http://github.com/bdewitt/socketpool"
|
16
|
+
gem.license = "Apache 2.0"
|
17
|
+
gem.summary = "Provides class for managing a socket pool"
|
18
|
+
gem.description = "SocketPool class to mangage socket based client access [based on MongoDB pool class]"
|
19
|
+
gem.email = "brandon+socketpool@myjibe.com"
|
20
|
+
gem.authors = ["Brandon Dewitt"]
|
21
|
+
gem.add_development_dependency 'rspec', '> 2.0'
|
22
|
+
end
|
23
|
+
Jeweler::RubygemsDotOrgTasks.new
|
24
|
+
|
25
|
+
require 'rspec/core'
|
26
|
+
require 'rspec/core/rake_task'
|
27
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
28
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
29
|
+
end
|
30
|
+
|
31
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
32
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
33
|
+
spec.rcov = true
|
34
|
+
end
|
35
|
+
|
36
|
+
task :default => :spec
|
37
|
+
|
38
|
+
require 'rake/rdoctask'
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
41
|
+
|
42
|
+
rdoc.rdoc_dir = 'rdoc'
|
43
|
+
rdoc.title = "socketpool #{version}"
|
44
|
+
rdoc.rdoc_files.include('README*')
|
45
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
46
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/socketpool.rb
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
#
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
3
|
+
# you may not use this file except in compliance with the License.
|
4
|
+
# You may obtain a copy of the License at
|
5
|
+
#
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
#
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
11
|
+
# See the License for the specific language governing permissions and
|
12
|
+
# limitations under the License.
|
13
|
+
|
14
|
+
require 'socket'
|
15
|
+
require 'thread'
|
16
|
+
|
17
|
+
class SocketPool
|
18
|
+
|
19
|
+
attr_accessor :host, :port, :size, :timeout, :checked_out
|
20
|
+
|
21
|
+
# Create a new socket pool
|
22
|
+
#
|
23
|
+
def initialize(host, port, opts={})
|
24
|
+
@host, @port = host, port
|
25
|
+
|
26
|
+
# Pool size and timeout.
|
27
|
+
@size = opts[:size] || 2
|
28
|
+
@timeout = opts[:timeout] || 5.0
|
29
|
+
@eager = opts[:eager] || false
|
30
|
+
|
31
|
+
# Mutex for synchronizing pool access
|
32
|
+
@connection_mutex = Mutex.new
|
33
|
+
|
34
|
+
# Condition variable for signal and wait
|
35
|
+
@queue = ConditionVariable.new
|
36
|
+
|
37
|
+
@socktype = opts[:type] || :tcp
|
38
|
+
@sockopts = opts[:socketopts].nil? ? [] : [opts[:socketopts]].flatten.inject([]){|s, so| s << so}
|
39
|
+
@sockets = []
|
40
|
+
@pids = {}
|
41
|
+
@checked_out = []
|
42
|
+
|
43
|
+
initialize_socketpool if @eager
|
44
|
+
end
|
45
|
+
|
46
|
+
def close
|
47
|
+
@sockets.each do |sock|
|
48
|
+
begin
|
49
|
+
sock.close
|
50
|
+
rescue IOError => ex
|
51
|
+
warn "IOError when attempting to close socket connected to #{@host}:#{@port}: #{ex.inspect}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
@host = @port = nil
|
55
|
+
@sockets.clear
|
56
|
+
@pids.clear
|
57
|
+
@checked_out.clear
|
58
|
+
end
|
59
|
+
|
60
|
+
# Return a socket to the pool.
|
61
|
+
def checkin(socket)
|
62
|
+
@connection_mutex.synchronize do
|
63
|
+
@checked_out.delete(socket)
|
64
|
+
@queue.signal
|
65
|
+
end
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
# Adds a new socket to the pool and checks it out.
|
70
|
+
#
|
71
|
+
# This method is called exclusively from #checkout;
|
72
|
+
# therefore, it runs within a mutex.
|
73
|
+
def checkout_new_socket
|
74
|
+
begin
|
75
|
+
socket = Socket.new(so_domain(@socktype), so_type(@socktype), 0)
|
76
|
+
@sockaddr ||= Socket.pack_sockaddr_in(@port, @host) if ![:unix, :unigram].include?(@socktype)
|
77
|
+
@sockaddr ||= Socket.pack_sockaddr_un(@host) if [:unix, :unigram].include?(@socktype)
|
78
|
+
socket.connect(@sockaddr)
|
79
|
+
if @sockopts.size > 0
|
80
|
+
@sockopts.each{ |opt| socket.setsockopt(opt[:level], opt[:optname], opt[:optval]) }
|
81
|
+
end
|
82
|
+
rescue => ex
|
83
|
+
raise ConnectionFailure, "Failed to connect to host #{@host} and port #{@port}: #{ex}"
|
84
|
+
end
|
85
|
+
|
86
|
+
@sockets << socket
|
87
|
+
@pids[socket] = Process.pid
|
88
|
+
@checked_out << socket
|
89
|
+
socket
|
90
|
+
end
|
91
|
+
|
92
|
+
# Checks out the first available socket from the pool.
|
93
|
+
#
|
94
|
+
# If the pid has changed, remove the socket and check out
|
95
|
+
# new one.
|
96
|
+
#
|
97
|
+
# This method is called exclusively from #checkout;
|
98
|
+
# therefore, it runs within a mutex.
|
99
|
+
def checkout_existing_socket
|
100
|
+
socket = (@sockets - @checked_out).first
|
101
|
+
if @pids[socket] != Process.pid
|
102
|
+
@pids[socket] = nil
|
103
|
+
@sockets.delete(socket)
|
104
|
+
socket.close
|
105
|
+
checkout_new_socket
|
106
|
+
else
|
107
|
+
@checked_out << socket
|
108
|
+
socket
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Check out an existing socket or create a new socket if the maximum
|
113
|
+
# pool size has not been exceeded. Otherwise, wait for the next
|
114
|
+
# available socket.
|
115
|
+
def checkout
|
116
|
+
start_time = Time.now
|
117
|
+
loop do
|
118
|
+
if (Time.now - start_time) > @timeout
|
119
|
+
raise ConnectionTimeoutError, "could not obtain connection within " +
|
120
|
+
"#{@timeout} seconds. The max pool size is currently #{@size}; " +
|
121
|
+
"consider increasing the pool size or timeout."
|
122
|
+
end
|
123
|
+
|
124
|
+
@connection_mutex.synchronize do
|
125
|
+
socket = if @checked_out.size < @sockets.size
|
126
|
+
checkout_existing_socket
|
127
|
+
elsif @sockets.size < @size
|
128
|
+
checkout_new_socket
|
129
|
+
end
|
130
|
+
|
131
|
+
if socket
|
132
|
+
return socket
|
133
|
+
else
|
134
|
+
# Otherwise, wait
|
135
|
+
@queue.wait(@connection_mutex)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def so_type(val)
|
142
|
+
val = val.downcase.to_sym if val.respond_to?(:downcase) && val.respond_to?(:to_sym)
|
143
|
+
@so_type ||= {
|
144
|
+
:tcp => Socket::SOCK_STREAM,
|
145
|
+
:tcp6 => Socket::SOCK_STREAM,
|
146
|
+
:udp => Socket::SOCK_DGRAM,
|
147
|
+
:udp6 => Socket::SOCK_DGRAM,
|
148
|
+
:unix => Socket::SOCK_STREAM,
|
149
|
+
:unigram => Socket::SOCK_DGRAM
|
150
|
+
}[val]
|
151
|
+
end
|
152
|
+
|
153
|
+
def so_domain(val)
|
154
|
+
val = val.downcase.to_sym if val.respond_to?(:downcase) && val.respond_to?(:to_sym)
|
155
|
+
@so_domain ||= {
|
156
|
+
:tcp => Socket::AF_INET,
|
157
|
+
:tcp6 => Socket::AF_INET6,
|
158
|
+
:udp => Socket::AF_INET,
|
159
|
+
:udp6 => Socket::AF_INET6,
|
160
|
+
:unix => Socket::AF_UNIX,
|
161
|
+
:unigram => Socket::AF_UNIX
|
162
|
+
}[val]
|
163
|
+
end
|
164
|
+
|
165
|
+
private
|
166
|
+
|
167
|
+
def initialize_socketpool
|
168
|
+
begin
|
169
|
+
@size.times{ checkout_new_socket }
|
170
|
+
ensure
|
171
|
+
@checked_out = []
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "SocketPool arguments" do
|
4
|
+
describe SocketPool.new('127.0.0.1', '11222') do
|
5
|
+
specify { subject.port.should eq('11222')}
|
6
|
+
specify { subject.host.should eq('127.0.0.1')}
|
7
|
+
specify { subject.size.should eq(2)}
|
8
|
+
specify { subject.timeout.should eq(5.0)}
|
9
|
+
specify { subject.instance_variable_get(:@sockets).should eq([])}
|
10
|
+
specify { subject.instance_variable_get(:@checked_out).should eq([])}
|
11
|
+
specify { subject.instance_variable_get(:@pids).should eq({})}
|
12
|
+
specify { subject.instance_variable_get(:@eager).should eq(false)}
|
13
|
+
specify { subject.instance_variable_get(:@socktype).should eq(:tcp)}
|
14
|
+
specify { subject.instance_variable_get(:@sockopts).should eq([])}
|
15
|
+
|
16
|
+
it "should create socket on checkout" do
|
17
|
+
s = subject.checkout
|
18
|
+
subject.instance_variable_get(:@sockets).should_not eq([])
|
19
|
+
subject.instance_variable_get(:@sockets).size.should eq(1)
|
20
|
+
subject.instance_variable_get(:@checked_out).size.should eq(1)
|
21
|
+
|
22
|
+
subject.checkin(s)
|
23
|
+
subject.instance_variable_get(:@checked_out).size.should eq(0)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "UDP => Eager SocketPool" do
|
28
|
+
subject { SocketPool.new('127.0.0.1', '11222', :type => :udp, :eager => true) }
|
29
|
+
|
30
|
+
specify { subject.port.should eq('11222')}
|
31
|
+
specify { subject.host.should eq('127.0.0.1')}
|
32
|
+
specify { subject.size.should eq(2)}
|
33
|
+
specify { subject.timeout.should eq(5.0)}
|
34
|
+
specify { subject.instance_variable_get(:@sockets).size.should eq(2)}
|
35
|
+
specify { subject.instance_variable_get(:@checked_out).should eq([])}
|
36
|
+
specify { subject.instance_variable_get(:@eager).should eq(true)}
|
37
|
+
specify { subject.instance_variable_get(:@socktype).should eq(:udp)}
|
38
|
+
specify { subject.instance_variable_get(:@sockopts).should eq([])}
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "UDP => Eager SocketPool => resized, short timeout" do
|
42
|
+
subject { SocketPool.new('127.0.0.1', '11222', :type => :udp, :eager => true, :size => 19, :timeout => 1) }
|
43
|
+
|
44
|
+
specify { subject.port.should eq('11222')}
|
45
|
+
specify { subject.host.should eq('127.0.0.1')}
|
46
|
+
specify { subject.size.should eq(19)}
|
47
|
+
specify { subject.timeout.should eq(1.0)}
|
48
|
+
specify { subject.instance_variable_get(:@sockets).size.should eq(19)}
|
49
|
+
specify { subject.instance_variable_get(:@checked_out).should eq([])}
|
50
|
+
specify { subject.instance_variable_get(:@eager).should eq(true)}
|
51
|
+
specify { subject.instance_variable_get(:@socktype).should eq(:udp)}
|
52
|
+
specify { subject.instance_variable_get(:@sockopts).should eq([])}
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "TCP => Eager SocketPool => resized, short timeout => TCP_NODELAY" do
|
56
|
+
subject {
|
57
|
+
SocketPool.new('127.0.0.1', '11222',
|
58
|
+
:type => :tcp,
|
59
|
+
:eager => true,
|
60
|
+
:size => 19,
|
61
|
+
:timeout => 1,
|
62
|
+
:socketopts => [{:level => Socket::IPPROTO_TCP, :optname => Socket::TCP_NODELAY, :optval => 1}])
|
63
|
+
}
|
64
|
+
|
65
|
+
specify { subject.port.should eq('11222')}
|
66
|
+
specify { subject.host.should eq('127.0.0.1')}
|
67
|
+
specify { subject.size.should eq(19)}
|
68
|
+
specify { subject.timeout.should eq(1.0)}
|
69
|
+
specify { subject.instance_variable_get(:@sockets).size.should eq(19)}
|
70
|
+
specify { subject.instance_variable_get(:@checked_out).should eq([])}
|
71
|
+
specify { subject.instance_variable_get(:@eager).should eq(true)}
|
72
|
+
specify { subject.instance_variable_get(:@socktype).should eq(:tcp)}
|
73
|
+
specify { subject.instance_variable_get(:@sockopts).should_not eq([])}
|
74
|
+
end
|
75
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'socketpool'
|
5
|
+
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
7
|
+
# in ./support/ and its subdirectories.
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
|
12
|
+
end
|
metadata
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: socketpool
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Brandon Dewitt
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-04-03 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
type: :development
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 2
|
31
|
+
- 3
|
32
|
+
- 0
|
33
|
+
version: 2.3.0
|
34
|
+
name: rspec
|
35
|
+
version_requirements: *id001
|
36
|
+
prerelease: false
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
type: :development
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 23
|
45
|
+
segments:
|
46
|
+
- 1
|
47
|
+
- 0
|
48
|
+
- 0
|
49
|
+
version: 1.0.0
|
50
|
+
name: bundler
|
51
|
+
version_requirements: *id002
|
52
|
+
prerelease: false
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
type: :development
|
55
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ~>
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 7
|
61
|
+
segments:
|
62
|
+
- 1
|
63
|
+
- 5
|
64
|
+
- 2
|
65
|
+
version: 1.5.2
|
66
|
+
name: jeweler
|
67
|
+
version_requirements: *id003
|
68
|
+
prerelease: false
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
type: :development
|
71
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
hash: 3
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
version: "0"
|
80
|
+
name: rcov
|
81
|
+
version_requirements: *id004
|
82
|
+
prerelease: false
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
type: :development
|
85
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
hash: 3
|
91
|
+
segments:
|
92
|
+
- 2
|
93
|
+
- 0
|
94
|
+
version: "2.0"
|
95
|
+
name: rspec
|
96
|
+
version_requirements: *id005
|
97
|
+
prerelease: false
|
98
|
+
description: SocketPool class to mangage socket based client access [based on MongoDB pool class]
|
99
|
+
email: brandon+socketpool@myjibe.com
|
100
|
+
executables: []
|
101
|
+
|
102
|
+
extensions: []
|
103
|
+
|
104
|
+
extra_rdoc_files:
|
105
|
+
- LICENSE.txt
|
106
|
+
- README.rdoc
|
107
|
+
files:
|
108
|
+
- .document
|
109
|
+
- .rspec
|
110
|
+
- Gemfile
|
111
|
+
- Gemfile.lock
|
112
|
+
- LICENSE.txt
|
113
|
+
- README.rdoc
|
114
|
+
- Rakefile
|
115
|
+
- VERSION
|
116
|
+
- lib/socketpool.rb
|
117
|
+
- spec/socketpool_spec.rb
|
118
|
+
- spec/spec_helper.rb
|
119
|
+
has_rdoc: true
|
120
|
+
homepage: http://github.com/bdewitt/socketpool
|
121
|
+
licenses:
|
122
|
+
- Apache 2.0
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
|
126
|
+
require_paths:
|
127
|
+
- lib
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
hash: 3
|
134
|
+
segments:
|
135
|
+
- 0
|
136
|
+
version: "0"
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
hash: 3
|
143
|
+
segments:
|
144
|
+
- 0
|
145
|
+
version: "0"
|
146
|
+
requirements: []
|
147
|
+
|
148
|
+
rubyforge_project:
|
149
|
+
rubygems_version: 1.6.2
|
150
|
+
signing_key:
|
151
|
+
specification_version: 3
|
152
|
+
summary: Provides class for managing a socket pool
|
153
|
+
test_files:
|
154
|
+
- spec/socketpool_spec.rb
|
155
|
+
- spec/spec_helper.rb
|