switch_point 0.5.0.pre → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.rubocop.yml +56 -0
- data/.rubocop_todo.yml +2 -0
- data/.travis.yml +21 -6
- data/Appraisals +55 -5
- data/CHANGELOG.md +23 -1
- data/Gemfile +6 -0
- data/README.md +36 -3
- data/Rakefile +12 -2
- data/assets/switch_point.svg +1 -1
- data/benchmark/proxy.rb +62 -0
- data/gemfiles/rails_3.2.gemfile +6 -2
- data/gemfiles/rails_4.0.gemfile +6 -2
- data/gemfiles/rails_4.1.gemfile +6 -2
- data/gemfiles/rails_4.2.gemfile +11 -0
- data/gemfiles/rails_5.0.gemfile +11 -0
- data/gemfiles/rails_5.1.gemfile +11 -0
- data/gemfiles/rails_5.2.gemfile +11 -0
- data/gemfiles/rails_6.0.gemfile +11 -0
- data/lib/switch_point.rb +17 -8
- data/lib/switch_point/config.rb +15 -15
- data/lib/switch_point/connection.rb +15 -14
- data/lib/switch_point/error.rb +12 -0
- data/lib/switch_point/model.rb +48 -16
- data/lib/switch_point/proxy.rb +23 -5
- data/lib/switch_point/proxy_repository.rb +2 -0
- data/lib/switch_point/query_cache.rb +22 -0
- data/lib/switch_point/version.rb +3 -1
- data/spec/models.rb +18 -5
- data/spec/spec_helper.rb +13 -3
- data/spec/switch_point/model_spec.rb +91 -18
- data/spec/switch_point/query_cache_spec.rb +78 -0
- data/spec/switch_point_spec.rb +69 -0
- data/switch_point.gemspec +22 -17
- metadata +76 -18
- data/gemfiles/rails_edge.gemfile +0 -7
data/lib/switch_point/version.rb
CHANGED
data/spec/models.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
SwitchPoint.configure do |config|
|
2
4
|
config.define_switch_point :main,
|
3
5
|
readonly: :main_readonly,
|
@@ -30,8 +32,7 @@ class Book < ActiveRecord::Base
|
|
30
32
|
|
31
33
|
private
|
32
34
|
|
33
|
-
def do_after_save
|
34
|
-
end
|
35
|
+
def do_after_save; end
|
35
36
|
end
|
36
37
|
|
37
38
|
class Book2 < ActiveRecord::Base
|
@@ -85,8 +86,13 @@ class DerivedNanika2 < AbstractNanika
|
|
85
86
|
use_switch_point :main2
|
86
87
|
end
|
87
88
|
|
88
|
-
base =
|
89
|
-
|
89
|
+
base =
|
90
|
+
if RUBY_PLATFORM == 'java'
|
91
|
+
{ adapter: 'jdbcsqlite3' }
|
92
|
+
else
|
93
|
+
{ adapter: 'sqlite3' }
|
94
|
+
end
|
95
|
+
databases = {
|
90
96
|
'main_readonly' => base.merge(database: 'main_readonly.sqlite3'),
|
91
97
|
'main_writable' => base.merge(database: 'main_writable.sqlite3'),
|
92
98
|
'main2_readonly' => base.merge(database: 'main2_readonly.sqlite3'),
|
@@ -95,8 +101,15 @@ ActiveRecord::Base.configurations = {
|
|
95
101
|
'user' => base.merge(database: 'user.sqlite3'),
|
96
102
|
'comment_readonly' => base.merge(database: 'comment_readonly.sqlite3'),
|
97
103
|
'comment_writable' => base.merge(database: 'comment_writable.sqlite3'),
|
98
|
-
'default' => base.merge(database: 'default.sqlite3')
|
104
|
+
'default' => base.merge(database: 'default.sqlite3'),
|
99
105
|
}
|
106
|
+
ActiveRecord::Base.configurations =
|
107
|
+
# ActiveRecord.gem_version was introduced in ActiveRecord 4.0
|
108
|
+
if ActiveRecord.respond_to?(:gem_version) && ActiveRecord.gem_version >= Gem::Version.new('5.1.0')
|
109
|
+
{ 'test' => databases }
|
110
|
+
else
|
111
|
+
databases
|
112
|
+
end
|
100
113
|
ActiveRecord::Base.establish_connection(:default)
|
101
114
|
|
102
115
|
# XXX: Check connection laziness
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
ENV['RAILS_ENV'] ||= 'test'
|
4
|
+
|
1
5
|
require 'coveralls'
|
2
6
|
require 'simplecov'
|
3
7
|
|
4
|
-
SimpleCov.
|
8
|
+
SimpleCov.formatters = [
|
5
9
|
SimpleCov::Formatter::HTMLFormatter,
|
6
10
|
Coveralls::SimpleCov::Formatter,
|
7
11
|
]
|
@@ -57,8 +61,14 @@ RSpec.configure do |config|
|
|
57
61
|
end
|
58
62
|
|
59
63
|
config.after(:suite) do
|
60
|
-
ActiveRecord::Base.configurations.
|
61
|
-
|
64
|
+
if ActiveRecord::Base.configurations.respond_to?(:configs_for)
|
65
|
+
ActiveRecord::Base.configurations.configs_for.each do |c|
|
66
|
+
FileUtils.rm_f(c.config['database'])
|
67
|
+
end
|
68
|
+
else
|
69
|
+
ActiveRecord::Base.configurations.each_value do |c|
|
70
|
+
FileUtils.rm_f(c[:database])
|
71
|
+
end
|
62
72
|
end
|
63
73
|
end
|
64
74
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec.describe SwitchPoint::Model do
|
2
4
|
describe '.use_switch_point' do
|
3
5
|
after do
|
@@ -33,8 +35,8 @@ RSpec.describe SwitchPoint::Model do
|
|
33
35
|
|
34
36
|
context 'when auto_writable is disabled' do
|
35
37
|
it 'raises error when destructive query is requested in readonly mode' do
|
36
|
-
expect { Book.create }.to raise_error(SwitchPoint::
|
37
|
-
expect { Book.with_readonly { Book.create } }.to raise_error(SwitchPoint::
|
38
|
+
expect { Book.create }.to raise_error(SwitchPoint::ReadonlyError)
|
39
|
+
expect { Book.with_readonly { Book.create } }.to raise_error(SwitchPoint::ReadonlyError)
|
38
40
|
expect { Book.with_writable { Book.create } }.to_not raise_error
|
39
41
|
end
|
40
42
|
end
|
@@ -69,7 +71,6 @@ RSpec.describe SwitchPoint::Model do
|
|
69
71
|
|
70
72
|
it 'works with newly checked-out connection' do
|
71
73
|
Thread.start do
|
72
|
-
expect(Book.connection.pool.connections.size).to be > 1 # Assertion
|
73
74
|
Book.with_writable do
|
74
75
|
Book.create
|
75
76
|
end
|
@@ -218,7 +219,7 @@ RSpec.describe SwitchPoint::Model do
|
|
218
219
|
expect(Book.connection.query_cache.size).to eq(1)
|
219
220
|
Book.with_writable do
|
220
221
|
Book.create
|
221
|
-
FileUtils.cp('main_writable.sqlite3', 'main_readonly.sqlite3')
|
222
|
+
FileUtils.cp('main_writable.sqlite3', 'main_readonly.sqlite3') # XXX: emulate replication
|
222
223
|
end
|
223
224
|
expect(Book.connection.query_cache.size).to eq(0)
|
224
225
|
expect(Book.count).to eq(1)
|
@@ -228,8 +229,8 @@ RSpec.describe SwitchPoint::Model do
|
|
228
229
|
end
|
229
230
|
|
230
231
|
context 'without use_switch_point' do
|
231
|
-
it '
|
232
|
-
expect
|
232
|
+
it 'raises error' do
|
233
|
+
expect { Note.with_writable { :bypass } }.to raise_error(SwitchPoint::UnconfiguredError)
|
233
234
|
end
|
234
235
|
end
|
235
236
|
|
@@ -243,6 +244,16 @@ RSpec.describe SwitchPoint::Model do
|
|
243
244
|
end
|
244
245
|
end
|
245
246
|
|
247
|
+
describe '#with_writable' do
|
248
|
+
it 'behaves like .with_writable' do
|
249
|
+
book = Book.with_writable { Book.create! }
|
250
|
+
book.with_writable do
|
251
|
+
expect(Book).to connect_to('main_writable.sqlite3')
|
252
|
+
end
|
253
|
+
expect(Book).to connect_to('main_readonly.sqlite3')
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
246
257
|
describe '.with_readonly' do
|
247
258
|
context 'when writable! is called globally' do
|
248
259
|
before do
|
@@ -262,9 +273,27 @@ RSpec.describe SwitchPoint::Model do
|
|
262
273
|
end
|
263
274
|
end
|
264
275
|
|
276
|
+
describe '#with_readonly' do
|
277
|
+
before do
|
278
|
+
SwitchPoint.writable!(:main)
|
279
|
+
end
|
280
|
+
|
281
|
+
after do
|
282
|
+
SwitchPoint.readonly!(:main)
|
283
|
+
end
|
284
|
+
|
285
|
+
it 'behaves like .with_readonly' do
|
286
|
+
book = Book.create!
|
287
|
+
book.with_readonly do
|
288
|
+
expect(Book).to connect_to('main_readonly.sqlite3')
|
289
|
+
end
|
290
|
+
expect(Book).to connect_to('main_writable.sqlite3')
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
265
294
|
describe '#with_mode' do
|
266
295
|
it 'raises error if unknown mode is given' do
|
267
|
-
expect { SwitchPoint::ProxyRepository.checkout(:main).with_mode(:typo) }.to raise_error
|
296
|
+
expect { SwitchPoint::ProxyRepository.checkout(:main).with_mode(:typo) }.to raise_error(ArgumentError)
|
268
297
|
end
|
269
298
|
end
|
270
299
|
|
@@ -292,14 +321,14 @@ RSpec.describe SwitchPoint::Model do
|
|
292
321
|
end
|
293
322
|
|
294
323
|
describe '.transaction_with' do
|
295
|
-
context
|
324
|
+
context 'when each model has a same writable' do
|
296
325
|
before do
|
297
326
|
@before_book_count = Book.count
|
298
327
|
@before_book2_count = Book2.count
|
299
328
|
|
300
329
|
Book.transaction_with(Book2) do
|
301
|
-
|
302
|
-
|
330
|
+
Book.create
|
331
|
+
Book2.create
|
303
332
|
end
|
304
333
|
|
305
334
|
@after_book_count = Book.with_writable do
|
@@ -325,25 +354,25 @@ RSpec.describe SwitchPoint::Model do
|
|
325
354
|
end
|
326
355
|
end
|
327
356
|
|
328
|
-
context
|
357
|
+
context 'when each model has a other writable' do
|
329
358
|
it {
|
330
359
|
expect {
|
331
360
|
Book.transaction_with(Book3) do
|
332
|
-
|
333
|
-
|
361
|
+
Book.create
|
362
|
+
Book3.create
|
334
363
|
end
|
335
|
-
}.to raise_error
|
364
|
+
}.to raise_error(SwitchPoint::Error)
|
336
365
|
}
|
337
366
|
end
|
338
367
|
|
339
|
-
context
|
368
|
+
context 'when raise exception in transaction that include some model, and models each have other writable' do
|
340
369
|
before do
|
341
370
|
@before_book_count = Book.count
|
342
371
|
@before_book3_count = Book3.count
|
343
372
|
|
344
373
|
Book.transaction_with(Book2) do
|
345
|
-
|
346
|
-
|
374
|
+
Book.create
|
375
|
+
Book3.with_writable do
|
347
376
|
Book3.create
|
348
377
|
end
|
349
378
|
raise ActiveRecord::Rollback
|
@@ -367,7 +396,7 @@ RSpec.describe SwitchPoint::Model do
|
|
367
396
|
end
|
368
397
|
end
|
369
398
|
|
370
|
-
context
|
399
|
+
context 'when nested transaction_with then parent transaction rollbacked' do
|
371
400
|
before do
|
372
401
|
@before_book_count = Book.count
|
373
402
|
@before_book3_count = Book3.count
|
@@ -398,4 +427,48 @@ RSpec.describe SwitchPoint::Model do
|
|
398
427
|
end
|
399
428
|
end
|
400
429
|
end
|
430
|
+
|
431
|
+
describe '#transaction_with' do
|
432
|
+
it 'behaves like .transaction_with' do
|
433
|
+
book = Book.with_writable { Book.create! }
|
434
|
+
expect(Book.with_writable { Book.count }).to eq(1)
|
435
|
+
book.transaction_with(Book2) do
|
436
|
+
Book.create!
|
437
|
+
raise ActiveRecord::Rollback
|
438
|
+
end
|
439
|
+
expect(Book.with_writable { Book.count }).to eq(1)
|
440
|
+
|
441
|
+
expect { book.transaction_with(Book3) {} }.to raise_error(SwitchPoint::Error) # rubocop:disable Lint/EmptyBlock
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
describe '.cache' do
|
446
|
+
it 'enables query cache for both readonly and writable' do
|
447
|
+
Book.connection
|
448
|
+
Book.with_writable { Book.connection }
|
449
|
+
|
450
|
+
Book.cache do
|
451
|
+
expect { Book.count }.to change { Book.connection.query_cache.size }.from(0).to(1)
|
452
|
+
Book.with_writable do
|
453
|
+
expect { Book.count }.to change { Book.connection.query_cache.size }.from(0).to(1)
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
describe '.uncached' do
|
460
|
+
it 'disables query cache for both readonly and writable' do
|
461
|
+
Book.connection
|
462
|
+
Book.with_writable { Book.connection }
|
463
|
+
|
464
|
+
Book.cache do
|
465
|
+
Book.uncached do
|
466
|
+
expect { Book.count }.to_not change { Book.connection.query_cache.size }.from(0)
|
467
|
+
Book.with_writable do
|
468
|
+
expect { Book.count }.to_not change { Book.connection.query_cache.size }.from(0)
|
469
|
+
end
|
470
|
+
end
|
471
|
+
end
|
472
|
+
end
|
473
|
+
end
|
401
474
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'rack'
|
5
|
+
|
6
|
+
class TestApp
|
7
|
+
def call(env)
|
8
|
+
state = {}
|
9
|
+
[Nanika1, Nanika2].each do |model|
|
10
|
+
r = model.with_readonly { model.connection.query_cache_enabled }
|
11
|
+
w = model.with_writable { model.connection.query_cache_enabled }
|
12
|
+
state[model.name] = { readonly: r, writable: w }
|
13
|
+
end
|
14
|
+
env[:state] = state
|
15
|
+
:result
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec.describe SwitchPoint::QueryCache do
|
20
|
+
let(:app) do
|
21
|
+
Rack::Builder.new do
|
22
|
+
use SwitchPoint::QueryCache
|
23
|
+
run TestApp.new
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#call' do
|
28
|
+
before do
|
29
|
+
# Ensure the connection is established.
|
30
|
+
# The query cache is enabled only when connected.
|
31
|
+
# https://github.com/rails/rails/commit/25fc1f584def4c1bc36be805833194d8aee55b3a
|
32
|
+
[Nanika1, Nanika2].each do |model|
|
33
|
+
model.with_readonly { model.connection }
|
34
|
+
model.with_writable { model.connection }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'enables query cache of all models' do
|
39
|
+
env = {}
|
40
|
+
expect(app.call(env)).to eq(:result)
|
41
|
+
expect(env[:state]).to eq(
|
42
|
+
'Nanika1' => { readonly: true, writable: true },
|
43
|
+
'Nanika2' => { readonly: true, writable: true },
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when names are specified' do
|
48
|
+
let(:app) do
|
49
|
+
Rack::Builder.new do
|
50
|
+
use SwitchPoint::QueryCache, %i[main nanika1]
|
51
|
+
run TestApp.new
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'enables query caches of specified models' do
|
56
|
+
env = {}
|
57
|
+
expect(app.call(env)).to eq(:result)
|
58
|
+
expect(env[:state]).to eq(
|
59
|
+
'Nanika1' => { readonly: true, writable: true },
|
60
|
+
'Nanika2' => { readonly: false, writable: true },
|
61
|
+
)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when unknown name is specified' do
|
66
|
+
let(:app) do
|
67
|
+
Rack::Builder.new do
|
68
|
+
use SwitchPoint::QueryCache, [:unknown]
|
69
|
+
run TestApp.new
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'raises error' do
|
74
|
+
expect { app.call({}) }.to raise_error(KeyError)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/spec/switch_point_spec.rb
CHANGED
@@ -1,4 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec.describe SwitchPoint do
|
4
|
+
describe '.writable_all!' do
|
5
|
+
after do
|
6
|
+
SwitchPoint.readonly_all!
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'changes connection globally' do
|
10
|
+
expect(Book).to connect_to('main_readonly.sqlite3')
|
11
|
+
expect(Book3).to connect_to('main2_readonly.sqlite3')
|
12
|
+
expect(Comment).to connect_to('comment_readonly.sqlite3')
|
13
|
+
expect(User).to connect_to('user.sqlite3')
|
14
|
+
expect(BigData).to connect_to('main_readonly_special.sqlite3')
|
15
|
+
SwitchPoint.writable_all!
|
16
|
+
expect(Book).to connect_to('main_writable.sqlite3')
|
17
|
+
expect(Book3).to connect_to('main2_writable.sqlite3')
|
18
|
+
expect(Comment).to connect_to('comment_writable.sqlite3')
|
19
|
+
expect(User).to connect_to('user.sqlite3')
|
20
|
+
expect(BigData).to connect_to('main_writable.sqlite3')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'affects thread-globally' do
|
24
|
+
SwitchPoint.writable_all!
|
25
|
+
Thread.start do
|
26
|
+
expect(Book).to connect_to('main_writable.sqlite3')
|
27
|
+
expect(Book3).to connect_to('main2_writable.sqlite3')
|
28
|
+
expect(Comment).to connect_to('comment_writable.sqlite3')
|
29
|
+
expect(User).to connect_to('user.sqlite3')
|
30
|
+
expect(BigData).to connect_to('main_writable.sqlite3')
|
31
|
+
end.join
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'within with block' do
|
35
|
+
it 'changes the current mode' do
|
36
|
+
SwitchPoint.writable_all!
|
37
|
+
Book.with_readonly do
|
38
|
+
expect(Book).to connect_to('main_readonly.sqlite3')
|
39
|
+
end
|
40
|
+
expect(Book).to connect_to('main_writable.sqlite3')
|
41
|
+
Book.with_writable do
|
42
|
+
expect(Book).to connect_to('main_writable.sqlite3')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
2
48
|
describe '.writable!' do
|
3
49
|
after do
|
4
50
|
SwitchPoint.readonly!(:main)
|
@@ -31,6 +77,12 @@ RSpec.describe SwitchPoint do
|
|
31
77
|
end
|
32
78
|
end
|
33
79
|
end
|
80
|
+
|
81
|
+
context 'with unknown name' do
|
82
|
+
it 'raises error' do
|
83
|
+
expect { SwitchPoint.writable!(:unknown) }.to raise_error(KeyError)
|
84
|
+
end
|
85
|
+
end
|
34
86
|
end
|
35
87
|
|
36
88
|
describe '.with_writable' do
|
@@ -44,5 +96,22 @@ RSpec.describe SwitchPoint do
|
|
44
96
|
expect(Publisher).to connect_to('main_readonly.sqlite3')
|
45
97
|
expect(Nanika1).to connect_to('main_readonly.sqlite3')
|
46
98
|
end
|
99
|
+
|
100
|
+
context 'with unknown name' do
|
101
|
+
it 'raises error' do
|
102
|
+
expect { SwitchPoint.with_writable(:unknown) { raise RuntimeError } }.to raise_error(KeyError)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe '.with_writable_all' do
|
108
|
+
it 'changes all connections' do
|
109
|
+
expect(Book).to connect_to('main_readonly.sqlite3')
|
110
|
+
expect(Comment).to connect_to('comment_readonly.sqlite3')
|
111
|
+
SwitchPoint.with_writable_all do
|
112
|
+
expect(Book).to connect_to('main_writable.sqlite3')
|
113
|
+
expect(Comment).to connect_to('comment_writable.sqlite3')
|
114
|
+
end
|
115
|
+
end
|
47
116
|
end
|
48
117
|
end
|
data/switch_point.gemspec
CHANGED
@@ -1,28 +1,33 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'switch_point/version'
|
5
6
|
|
6
7
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
8
|
+
spec.name = 'switch_point'
|
8
9
|
spec.version = SwitchPoint::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
10
|
+
spec.authors = ['Kohei Suzuki']
|
11
|
+
spec.email = ['eagletmt@gmail.com']
|
12
|
+
spec.summary = 'Switching database connection between readonly one and writable one.'
|
13
|
+
spec.description = 'Switching database connection between readonly one and writable one.'
|
14
|
+
spec.homepage = 'https://github.com/eagletmt/switch_point'
|
15
|
+
spec.license = 'MIT'
|
15
16
|
|
16
17
|
spec.files = `git ls-files -z`.split("\x0")
|
17
18
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
spec.required_ruby_version = '>= 2.5.0'
|
20
22
|
|
21
|
-
spec.add_development_dependency
|
22
|
-
spec.add_development_dependency
|
23
|
-
spec.add_development_dependency
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.
|
23
|
+
spec.add_development_dependency 'appraisal'
|
24
|
+
spec.add_development_dependency 'benchmark-ips'
|
25
|
+
spec.add_development_dependency 'bundler'
|
26
|
+
spec.add_development_dependency 'coveralls', '>= 0.8.22'
|
27
|
+
spec.add_development_dependency 'rack'
|
28
|
+
spec.add_development_dependency 'rake'
|
29
|
+
spec.add_development_dependency 'rspec', '>= 3.0'
|
30
|
+
spec.add_development_dependency 'rubocop', '>= 0.50.0'
|
31
|
+
spec.add_development_dependency 'simplecov', '~> 0.16.1' # XXX: The latest coveralls still depends on old version
|
32
|
+
spec.add_dependency 'activerecord', '>= 3.2.0', '< 6.1.0'
|
28
33
|
end
|