em-pg-sequel 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -2
- data/README.md +2 -1
- data/em-pg-sequel.gemspec +3 -4
- data/lib/em-pg-sequel.rb +2 -45
- data/lib/em-pg-sequel/connection_pool.rb +73 -23
- data/spec/em-pg-sequel/sequel_spec.rb +188 -15
- data/spec/spec_helper.rb +18 -0
- metadata +15 -30
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -8,9 +8,10 @@ Usage
|
|
8
8
|
|
9
9
|
```ruby
|
10
10
|
require "em-pg-sequel"
|
11
|
+
require "em-synchrony"
|
11
12
|
EM.synchrony do
|
12
13
|
url = "postgres://postgres:postgres@localhost:5432/test"
|
13
|
-
db = Sequel.connect(url, pool_class:
|
14
|
+
db = Sequel.connect(url, pool_class: :em_synchrony)
|
14
15
|
|
15
16
|
puts db[:test].all.inspect
|
16
17
|
|
data/em-pg-sequel.gemspec
CHANGED
@@ -4,8 +4,8 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |gem|
|
6
6
|
gem.name = "em-pg-sequel"
|
7
|
-
gem.version = "0.0.
|
8
|
-
gem.authors = ["Petr Yanovich"]
|
7
|
+
gem.version = "0.0.4"
|
8
|
+
gem.authors = ["Petr Yanovich", "Rafal Michalski"]
|
9
9
|
gem.email = ["fl00r@yandex.ru"]
|
10
10
|
gem.description = %q{Sequel adapter for ruby-em-pg-client}
|
11
11
|
gem.summary = %q{Sequel adapter for ruby-em-pg-client}
|
@@ -17,8 +17,7 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.require_paths = ["lib"]
|
18
18
|
|
19
19
|
gem.add_dependency "sequel"
|
20
|
-
gem.add_dependency "em-
|
21
|
-
gem.add_dependency "em-pg-client"
|
20
|
+
gem.add_dependency "em-pg-client", ">= 0.3.0"
|
22
21
|
|
23
22
|
gem.add_development_dependency "em-synchrony"
|
24
23
|
end
|
data/lib/em-pg-sequel.rb
CHANGED
@@ -1,53 +1,10 @@
|
|
1
|
-
require 'em-
|
2
|
-
require 'em-synchrony/pg'
|
1
|
+
require 'em-pg-client'
|
3
2
|
require 'sequel'
|
4
3
|
require 'em-pg-sequel/connection_pool'
|
5
4
|
|
6
|
-
module EM::PG
|
7
|
-
class ConnectionPool < ::Sequel::ConnectionPool
|
8
|
-
DEFAULT_SIZE = 4
|
9
|
-
attr_accessor :pool
|
10
|
-
def initialize(db, opts = {})
|
11
|
-
super
|
12
|
-
size = opts[:max_connections] || DEFAULT_SIZE
|
13
|
-
@pool = ::EM::PG::Sequel::ConnectionPool.new(size: size, disconnect_class: ::Sequel::DatabaseConnectionError) do
|
14
|
-
make_new(DEFAULT_SERVER)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def size
|
19
|
-
@pool.available.size
|
20
|
-
end
|
21
|
-
|
22
|
-
def hold(server = nil, &blk)
|
23
|
-
@pool.execute(&blk)
|
24
|
-
end
|
25
|
-
|
26
|
-
def disconnect(server = nil)
|
27
|
-
@pool.available.each{ |conn| db.disconnect_connection(conn) }
|
28
|
-
@pool.available.clear
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
module PG::EM
|
34
|
-
class SyncClient < Client
|
35
|
-
# Dirty hack
|
36
|
-
# To avoid patching ruby-em-pg-client and to support Sequel API
|
37
|
-
# we should execute async_client asynchronously for em-pg and synchronously for sequel
|
38
|
-
def async_exec(*args)
|
39
|
-
if block_given?
|
40
|
-
super
|
41
|
-
else
|
42
|
-
exec(*args)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
5
|
$VERBOSE.tap do |old_verbose|
|
49
6
|
$VERBOSE = nil
|
50
|
-
PGconn = PG::EM::
|
7
|
+
PGconn = PG::EM::Client
|
51
8
|
$VERBOSE = old_verbose
|
52
9
|
end
|
53
10
|
|
@@ -1,47 +1,97 @@
|
|
1
1
|
module EM::PG
|
2
2
|
module Sequel
|
3
|
-
class ConnectionPool
|
4
|
-
attr_reader :available
|
3
|
+
class ConnectionPool < ::Sequel::ConnectionPool
|
5
4
|
|
6
|
-
|
5
|
+
DEFAULT_SIZE = 4
|
6
|
+
|
7
|
+
attr_reader :available, :allocated, :max_size
|
8
|
+
|
9
|
+
def initialize(db, opts = {})
|
10
|
+
super
|
7
11
|
@available = []
|
12
|
+
@allocated = {}
|
8
13
|
@pending = []
|
9
|
-
@acquire_blk = blk
|
10
14
|
|
11
|
-
@
|
15
|
+
@max_size = opts[:max_connections] || DEFAULT_SIZE
|
16
|
+
hold {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def size
|
20
|
+
@available.length + @allocated.length
|
21
|
+
end
|
22
|
+
|
23
|
+
def hold(server = nil)
|
24
|
+
fiber = Fiber.current
|
25
|
+
fiber_id = fiber.object_id
|
26
|
+
|
27
|
+
if conn = @allocated[fiber_id]
|
28
|
+
skip_release = true
|
29
|
+
else
|
30
|
+
conn = acquire(fiber) until conn
|
31
|
+
end
|
32
|
+
|
33
|
+
begin
|
34
|
+
yield conn
|
35
|
+
|
36
|
+
rescue ::Sequel::DatabaseDisconnectError => e
|
37
|
+
db.disconnect_connection(conn)
|
38
|
+
drop_failed(fiber_id)
|
39
|
+
skip_release = true
|
12
40
|
|
13
|
-
|
14
|
-
|
41
|
+
raise
|
42
|
+
ensure
|
43
|
+
release(fiber_id) unless skip_release
|
15
44
|
end
|
16
45
|
end
|
17
46
|
|
18
|
-
def
|
19
|
-
conn
|
20
|
-
|
21
|
-
rescue => e
|
22
|
-
conn = @acquire_blk.call if @disconnected_class && @disconnected_class === e
|
23
|
-
raise
|
24
|
-
ensure
|
25
|
-
release(conn)
|
47
|
+
def disconnect(server = nil)
|
48
|
+
@available.each{ |conn| db.disconnect_connection(conn) }
|
49
|
+
@available.clear
|
26
50
|
end
|
27
51
|
|
28
|
-
|
29
|
-
|
52
|
+
private
|
53
|
+
|
54
|
+
def acquire(fiber)
|
30
55
|
if conn = @available.pop
|
31
|
-
conn
|
56
|
+
@allocated[fiber.object_id] = conn
|
32
57
|
else
|
33
|
-
|
34
|
-
|
58
|
+
if size < max_size
|
59
|
+
allocate_new_connection(fiber.object_id)
|
60
|
+
else
|
61
|
+
@pending << fiber
|
62
|
+
Fiber.yield
|
63
|
+
end
|
35
64
|
end
|
36
65
|
end
|
37
66
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
67
|
+
def allocate_new_connection(fiber_id)
|
68
|
+
@allocated[fiber_id] = true
|
69
|
+
@allocated[fiber_id] = make_new(DEFAULT_SERVER)
|
70
|
+
rescue Exception => e
|
71
|
+
drop_failed(fiber_id)
|
72
|
+
raise e
|
73
|
+
end
|
74
|
+
|
75
|
+
# drop failed connection (or a mark) from the pool and
|
76
|
+
# ensure that the pending requests won't starve
|
77
|
+
def drop_failed(fiber_id)
|
78
|
+
@allocated.delete(fiber_id)
|
79
|
+
if pending = @pending.shift
|
80
|
+
EM.next_tick { pending.resume }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def release(fiber_id)
|
85
|
+
conn = @allocated.delete(fiber_id)
|
86
|
+
if pending = @pending.shift
|
87
|
+
@allocated[pending.object_id] = conn
|
88
|
+
EM.next_tick { pending.resume conn}
|
41
89
|
else
|
42
90
|
@available << conn
|
43
91
|
end
|
44
92
|
end
|
93
|
+
|
94
|
+
CONNECTION_POOL_MAP[:em_synchrony] = self
|
45
95
|
end
|
46
96
|
end
|
47
97
|
end
|
@@ -3,20 +3,44 @@ require 'em-synchrony'
|
|
3
3
|
require 'em-synchrony/fiber_iterator'
|
4
4
|
|
5
5
|
describe EM::PG::Sequel do
|
6
|
+
include SynchronyUtils
|
7
|
+
|
6
8
|
DELAY = 1
|
7
9
|
QUERY = "select pg_sleep(#{DELAY})"
|
8
10
|
|
9
11
|
let(:url) { DB_URL }
|
10
12
|
let(:size) { 1 }
|
11
|
-
let(:db) { Sequel.connect(url,
|
13
|
+
let(:db) { Sequel.connect(url, max_connections: size, pool_class: :em_synchrony, db_logger: Logger.new(nil)) }
|
12
14
|
let(:test) { db[:test] }
|
15
|
+
let(:fiber_iterator) { EM::Synchrony::FiberIterator }
|
16
|
+
|
17
|
+
describe "sanity" do
|
18
|
+
let(:size) { 42 }
|
19
|
+
|
20
|
+
it "should have max_size 42" do
|
21
|
+
db.pool.max_size.must_equal 42
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not release nil connection on connect error" do
|
25
|
+
synchrony do
|
26
|
+
db.disconnect
|
27
|
+
db.pool.size.must_equal 0
|
28
|
+
db.pool.stub :allocate_new_connection,
|
29
|
+
proc { raise Sequel::DatabaseConnectionError } do
|
30
|
+
|
31
|
+
proc { test.count }.must_raise Sequel::DatabaseConnectionError
|
32
|
+
db.pool.size.must_equal 0
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
13
38
|
|
14
39
|
describe "unexist table" do
|
15
40
|
it "should raise exception" do
|
16
|
-
|
41
|
+
synchrony do
|
17
42
|
proc { test.all }.must_raise Sequel::DatabaseError
|
18
43
|
|
19
|
-
EM.stop
|
20
44
|
end
|
21
45
|
end
|
22
46
|
end
|
@@ -24,30 +48,27 @@ describe EM::PG::Sequel do
|
|
24
48
|
describe "exist table" do
|
25
49
|
|
26
50
|
before do
|
27
|
-
|
51
|
+
synchrony do
|
28
52
|
db.create_table!(:test) do
|
29
53
|
text :name
|
30
54
|
integer :value, index: true
|
31
55
|
end
|
32
56
|
|
33
|
-
EM.stop
|
34
57
|
end
|
35
58
|
end
|
36
59
|
|
37
60
|
after do
|
38
|
-
|
61
|
+
synchrony do
|
39
62
|
db.drop_table?(:test)
|
40
63
|
|
41
|
-
EM.stop
|
42
64
|
end
|
43
65
|
end
|
44
66
|
|
45
67
|
it "should connect and execute query" do
|
46
|
-
|
68
|
+
synchrony do
|
47
69
|
test.insert name: "andrew", value: 42
|
48
70
|
test.where(name: "andrew").first[:value].must_equal 42
|
49
71
|
|
50
|
-
EM.stop
|
51
72
|
end
|
52
73
|
end
|
53
74
|
|
@@ -55,17 +76,16 @@ describe EM::PG::Sequel do
|
|
55
76
|
describe "pool size is exceeded" do
|
56
77
|
let(:size) { 1 }
|
57
78
|
it "should queue requests" do
|
58
|
-
|
79
|
+
synchrony do
|
59
80
|
start = Time.now.to_f
|
60
81
|
|
61
82
|
res = []
|
62
|
-
|
83
|
+
fiber_iterator.new([1,2], 1).each do |t|
|
63
84
|
res << db[QUERY].all
|
64
85
|
end
|
65
86
|
(Time.now.to_f - start.to_f).must_be_within_delta DELAY * 2, DELAY * 2 * 0.15
|
66
87
|
res.size.must_equal 2
|
67
88
|
|
68
|
-
EM.stop
|
69
89
|
end
|
70
90
|
end
|
71
91
|
end
|
@@ -73,18 +93,171 @@ describe EM::PG::Sequel do
|
|
73
93
|
describe "pool size is enough" do
|
74
94
|
let(:size) { 2 }
|
75
95
|
it "should parallel requests" do
|
76
|
-
|
96
|
+
synchrony do
|
77
97
|
start = Time.now.to_f
|
78
98
|
|
79
99
|
res = []
|
80
|
-
|
100
|
+
fiber_iterator.new([1,2], 2).each do |t|
|
81
101
|
res << db[QUERY].all
|
82
102
|
end
|
83
103
|
|
84
104
|
(Time.now.to_f - start.to_f).must_be_within_delta DELAY, DELAY * 0.30
|
85
105
|
res.size.must_equal 2
|
86
106
|
|
87
|
-
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "pool size is dynamic" do
|
112
|
+
|
113
|
+
let(:size) { 2 }
|
114
|
+
|
115
|
+
it "should have initial size of one" do
|
116
|
+
db.pool.size.must_equal 1
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should allocate second connection" do
|
120
|
+
synchrony do
|
121
|
+
res = []
|
122
|
+
res << test.first
|
123
|
+
db.pool.size.must_equal 1
|
124
|
+
fiber_iterator.new([1,2], 2).each do |t|
|
125
|
+
res << db[QUERY].all
|
126
|
+
end
|
127
|
+
db.pool.size.must_equal 2
|
128
|
+
res.size.must_equal 3
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should not create more than size connections" do
|
134
|
+
synchrony do
|
135
|
+
db.pool.size.must_equal 1
|
136
|
+
|
137
|
+
start = Time.now.to_f
|
138
|
+
res = []
|
139
|
+
fiber_iterator.new([1,1,2], 3).each do |pool_size|
|
140
|
+
db.pool.size.must_equal pool_size
|
141
|
+
res << db[QUERY].all
|
142
|
+
end
|
143
|
+
|
144
|
+
(Time.now.to_f - start.to_f).must_be_within_delta DELAY*2, DELAY * 2.60
|
145
|
+
res.size.must_equal 3
|
146
|
+
|
147
|
+
db.pool.size.must_equal size
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should clear all connections on disconnect" do
|
153
|
+
synchrony do
|
154
|
+
db.disconnect
|
155
|
+
db.pool.size.must_equal 0
|
156
|
+
res = []
|
157
|
+
fiber_iterator.new([1,2,3], 3).each do |t|
|
158
|
+
res << test.count
|
159
|
+
end
|
160
|
+
res.size.must_equal 3
|
161
|
+
db.pool.size.must_equal size
|
162
|
+
db.disconnect
|
163
|
+
db.pool.size.must_equal 0
|
164
|
+
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should re-create 1st connection" do
|
169
|
+
synchrony do
|
170
|
+
db.disconnect
|
171
|
+
db.pool.size.must_equal 0
|
172
|
+
|
173
|
+
test.count.must_equal 0
|
174
|
+
db.pool.size.must_equal 1
|
175
|
+
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
describe "on connection errors" do
|
182
|
+
|
183
|
+
let(:size) { 3 }
|
184
|
+
|
185
|
+
it "should not leave pending requests in queue" do
|
186
|
+
synchrony do
|
187
|
+
db.disconnect
|
188
|
+
fiber_iterator.new((0..size), size).each { test.count }
|
189
|
+
db.pool.available.each do |conn|
|
190
|
+
# force clients to disconnected state
|
191
|
+
conn.async_command_aborted = true
|
192
|
+
end.length.must_equal db.pool.size
|
193
|
+
|
194
|
+
db.pool.stub :make_new,
|
195
|
+
proc {
|
196
|
+
EM::Synchrony.sleep 0.1
|
197
|
+
raise Sequel::DatabaseConnectionError } do
|
198
|
+
|
199
|
+
request_counter = 0
|
200
|
+
expected_runs = db.pool.max_size + 10
|
201
|
+
expected_runs.times do |index|
|
202
|
+
Fiber.new do
|
203
|
+
|
204
|
+
pending = db.pool.instance_eval { @pending.length }
|
205
|
+
pending.must_equal [index - db.pool.max_size, 0].max
|
206
|
+
|
207
|
+
if index < db.pool.max_size
|
208
|
+
proc { test.count }.must_raise Sequel::DatabaseDisconnectError
|
209
|
+
else
|
210
|
+
proc { test.count }.must_raise Sequel::DatabaseConnectionError
|
211
|
+
end
|
212
|
+
|
213
|
+
request_counter += 1
|
214
|
+
|
215
|
+
end.resume
|
216
|
+
end
|
217
|
+
|
218
|
+
db.pool.instance_eval { @pending.length }.must_equal 10
|
219
|
+
|
220
|
+
tick_sleep while request_counter < expected_runs
|
221
|
+
|
222
|
+
db.pool.instance_eval { @pending.length }.must_equal 0
|
223
|
+
db.pool.size.must_equal 0
|
224
|
+
request_counter.must_equal expected_runs
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
describe "play nice with transactions" do
|
232
|
+
|
233
|
+
let(:size) { 2 }
|
234
|
+
|
235
|
+
it "should lock connection to fiber" do
|
236
|
+
synchrony do
|
237
|
+
db.transaction do |conn|
|
238
|
+
db.in_transaction?.must_equal true
|
239
|
+
db.transaction do |inner_conn|
|
240
|
+
inner_conn.must_be_same_as conn
|
241
|
+
db.in_transaction?.must_equal true
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
it "should allow separate transactions" do
|
249
|
+
synchrony do
|
250
|
+
db.transaction do |conn|
|
251
|
+
db.in_transaction?.must_equal true
|
252
|
+
fiber_iterator.new([1,2], 2).each do |t|
|
253
|
+
db.in_transaction?.must_equal false
|
254
|
+
db.transaction do |inner_conn|
|
255
|
+
inner_conn.wont_be_same_as conn
|
256
|
+
db.in_transaction?.must_equal true
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
88
261
|
end
|
89
262
|
end
|
90
263
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -16,6 +16,24 @@ DB_CONFIG = {
|
|
16
16
|
password: "postgres",
|
17
17
|
}
|
18
18
|
|
19
|
+
module SynchronyUtils
|
20
|
+
def tick_sleep
|
21
|
+
f = Fiber.current
|
22
|
+
EM::next_tick { f.resume }
|
23
|
+
Fiber.yield
|
24
|
+
end
|
25
|
+
|
26
|
+
def synchrony
|
27
|
+
EM.synchrony do
|
28
|
+
begin
|
29
|
+
yield
|
30
|
+
ensure
|
31
|
+
EM.stop
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
19
37
|
DB_URL = "postgres://%s:%s@%s:%d/%s" % [DB_CONFIG[:user], DB_CONFIG[:password], DB_CONFIG[:host], DB_CONFIG[:port], DB_CONFIG[:dbname]]
|
20
38
|
|
21
39
|
MiniTest::Reporters.use! MiniTest::Reporters::SpecReporter.new
|
metadata
CHANGED
@@ -1,80 +1,65 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-pg-sequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Petr Yanovich
|
9
|
+
- Rafal Michalski
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date:
|
13
|
+
date: 2014-01-03 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: sequel
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '0'
|
22
|
-
type: :runtime
|
23
17
|
prerelease: false
|
24
|
-
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ! '>='
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '0'
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: em-synchrony
|
32
18
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
19
|
requirements:
|
35
20
|
- - ! '>='
|
36
21
|
- !ruby/object:Gem::Version
|
37
22
|
version: '0'
|
23
|
+
none: false
|
38
24
|
type: :runtime
|
39
|
-
prerelease: false
|
40
25
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
26
|
requirements:
|
43
27
|
- - ! '>='
|
44
28
|
- !ruby/object:Gem::Version
|
45
29
|
version: '0'
|
30
|
+
none: false
|
46
31
|
- !ruby/object:Gem::Dependency
|
47
32
|
name: em-pg-client
|
33
|
+
prerelease: false
|
48
34
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
35
|
requirements:
|
51
36
|
- - ! '>='
|
52
37
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
38
|
+
version: 0.3.0
|
39
|
+
none: false
|
54
40
|
type: :runtime
|
55
|
-
prerelease: false
|
56
41
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
42
|
requirements:
|
59
43
|
- - ! '>='
|
60
44
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
45
|
+
version: 0.3.0
|
46
|
+
none: false
|
62
47
|
- !ruby/object:Gem::Dependency
|
63
48
|
name: em-synchrony
|
49
|
+
prerelease: false
|
64
50
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
51
|
requirements:
|
67
52
|
- - ! '>='
|
68
53
|
- !ruby/object:Gem::Version
|
69
54
|
version: '0'
|
55
|
+
none: false
|
70
56
|
type: :development
|
71
|
-
prerelease: false
|
72
57
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
58
|
requirements:
|
75
59
|
- - ! '>='
|
76
60
|
- !ruby/object:Gem::Version
|
77
61
|
version: '0'
|
62
|
+
none: false
|
78
63
|
description: Sequel adapter for ruby-em-pg-client
|
79
64
|
email:
|
80
65
|
- fl00r@yandex.ru
|
@@ -99,17 +84,17 @@ rdoc_options: []
|
|
99
84
|
require_paths:
|
100
85
|
- lib
|
101
86
|
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
-
none: false
|
103
87
|
requirements:
|
104
88
|
- - ! '>='
|
105
89
|
- !ruby/object:Gem::Version
|
106
90
|
version: '0'
|
107
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
91
|
none: false
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
93
|
requirements:
|
110
94
|
- - ! '>='
|
111
95
|
- !ruby/object:Gem::Version
|
112
96
|
version: '0'
|
97
|
+
none: false
|
113
98
|
requirements: []
|
114
99
|
rubyforge_project:
|
115
100
|
rubygems_version: 1.8.24
|