fish_transactions 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a822130f177c9753a9d30a248208ae38d46e29c7
4
+ data.tar.gz: 051ec846fc08b2a295d8f88601c4da608c73f7f0
5
+ SHA512:
6
+ metadata.gz: 5c9a9eb96340b83db54f2f20679616af083b25bd02892c6aceb5438de74c2a5318c3741ba26ea81679d8c5e5d02dd5cc453949d6f1779073382e6f20145d1ec6
7
+ data.tar.gz: d7a17433321b20d4ccea1320b5c956efe518e514c5e0c814867fbcd8040ce110697692901f66f7433830b698581235c78fcada6815876fc80bbc63b1eb09d4fc
data/MIT-LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 John Owen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # FishTransactions
2
+
3
+ Fish Transactions allows to add transaction callbacks anywhere.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'fish_transactions'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install fish_transactions
20
+
21
+ ## Usage
22
+
23
+ First you need to include `FishTransactions#Callbacks` module into the class
24
+ you want to use it.
25
+ Once included, you can directly call `after_commit` or `after_rollback` with
26
+ the code you wanna run on such events.
27
+
28
+
29
+ #### Example
30
+
31
+ ```ruby
32
+ class SomeClass
33
+
34
+ include FishTransaction::Callbacks
35
+
36
+ # ...
37
+
38
+ def some_method
39
+ # ...
40
+
41
+ ActiveRecord::Base.transaction do
42
+ # executes some code
43
+ puts "runs within transaction"
44
+
45
+ after_commit do
46
+
47
+ # things to do after transaction
48
+ puts "runs after transaction"
49
+
50
+ end
51
+
52
+ # executes more code
53
+ puts "again runs within transaction"
54
+ end
55
+ # ...
56
+
57
+ end
58
+
59
+ # ...
60
+
61
+ end
62
+
63
+ ```
64
+ will output
65
+ ```
66
+ runs within transaction
67
+ again runs within transaction
68
+ runs after transaction
69
+ ```
70
+
71
+ Please see [FishTransactions::Callbacks](FishTransactions/Callbacks.html) for more details.
72
+
73
+ ## Contributing
74
+
75
+ Bug reports and pull requests are welcome on GitHub at
76
+ [beetrack/fish_transactions](https://github.com/beetrack/fish_transactions). This project is intended to be
77
+ a safe, welcoming space for collaboration, and contributors are expected to
78
+ adhere to the [Contributor Covenant](http://contributor-covenant.org) code
79
+ of conduct.
80
+
81
+
82
+ ## Development
83
+
84
+ This gem is inspired on [AR After Transaction gem](https://github.com/grosser/ar_after_transaction).
85
+
86
+
87
+ ## License
88
+
89
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
90
+
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rdoc/task'
3
+ task :default => :spec
4
+
5
+ desc 'Generate documentation for FishTransactions.'
6
+ Rake::RDocTask.new(:rdoc) do |rdoc|
7
+ rdoc.rdoc_dir = 'doc'
8
+ rdoc.title = 'Fish Transactions'
9
+ rdoc.rdoc_files.include('README.md')
10
+ rdoc.rdoc_files.include('lib/**/*.rb')
11
+ rdoc.main = 'README.md'
12
+ end
@@ -0,0 +1,67 @@
1
+ require 'fish_transactions/callbacks_storage'
2
+
3
+ module FishTransactions
4
+
5
+ ##
6
+ # Module that modifies ActiveRecord transactions to capture events
7
+ module ActiveRecordMods
8
+ ##
9
+ # Modifications for ActiveRecord::Base class
10
+ # All methods here will be class level methods
11
+ module Base
12
+
13
+ ##
14
+ # When extended, this module will:
15
+ #
16
+ # * alias the +:transaction+ method and them override it
17
+ def self.extended( base )
18
+
19
+ base.class_eval do
20
+ class << self
21
+ # create an alias for the original +transaction+ method
22
+ alias_method :original_ar_transaction, :transaction
23
+ # and we 'rename' the new method as transaction
24
+ alias_method :transaction, :transaction_with_callbacks
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+
31
+
32
+ ##
33
+ # Wrapper of original transaction.
34
+ # Captures and then raises Rollback exception
35
+ # to know there were a rollback
36
+ def transaction_with_callbacks(*args)
37
+
38
+ committed = true
39
+
40
+ original_ar_transaction(*args) do
41
+ begin
42
+ yield
43
+ rescue ActiveRecord::Rollback
44
+ committed = false
45
+ raise
46
+ end
47
+ end
48
+ rescue Exception
49
+ committed = false
50
+ raise
51
+ ensure
52
+ if committed
53
+ callbacks.committed!
54
+ else
55
+ callbacks.rolledback!
56
+ end
57
+ end
58
+
59
+ ##
60
+ # read-access to callbacks storage
61
+ def callbacks
62
+ connection.fish_callbacks_storage ||= FishTransactions::CallbacksStorage.new
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,20 @@
1
+ module FishTransactions
2
+
3
+ # :nodoc:
4
+ module ActiveRecordMods
5
+
6
+ ##
7
+ # Modifications for ActiveRecord::ConnectionAdapters::AbstractAdapter class
8
+ module ConnectionAbstractAdapter
9
+
10
+ ##
11
+ # When included this module, will add:
12
+ #
13
+ # * <tt>attr_accessor fish_callbacks_storage</tt>
14
+ def self.included(base)
15
+ base.send(:attr_accessor,:fish_callbacks_storage)
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,6 @@
1
+ require 'fish_transactions/active_record_mods/connection_abstract_adapter'
2
+ require 'fish_transactions/active_record_mods/base'
3
+
4
+ # :nodoc: all
5
+ ActiveRecord::Base.extend FishTransactions::ActiveRecordMods::Base
6
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, FishTransactions::ActiveRecordMods::ConnectionAbstractAdapter)
@@ -0,0 +1,102 @@
1
+ module FishTransactions
2
+
3
+ ##
4
+ # = Fish Transactions Callbacks
5
+ #
6
+ # This module allows to add transaction callbacks anywhere.
7
+ # You just need to include this module and you will able to
8
+ # use it.
9
+ #
10
+ module Callbacks
11
+
12
+ ##
13
+ # Allows to execute any block of code after transaction completes.
14
+ # If no transaction is actually open, the code runs immediately.
15
+ #
16
+ # Accepts the following options that modifies this behavior:
17
+ #
18
+ # * <tt>:only</tt> - Execute this code only on commit or only on
19
+ # rollback. Accepts one of the following symbols: <tt>:commit</tt>,
20
+ # <tt>:rollback</tt>.
21
+ # * <tt>:if_no_transaction</tt> - Specifies what to do if there is no
22
+ # active transaction. Accepts one of the following symbols:
23
+ # <tt>:run</tt> (default), <tt>:skip</tt> (do not run).
24
+ #
25
+ # Example of use:
26
+ #
27
+ # ActiveRecord::Base.transaction do
28
+ # # executes some code
29
+ # puts "runs within transaction"
30
+ # after_transaction do
31
+ # # things to do after transaction
32
+ # puts "runs after transaction"
33
+ # end
34
+ # # executes more code
35
+ # puts "again runs within transaction"
36
+ # end
37
+ #
38
+ # will output
39
+ #
40
+ # runs within transaction
41
+ # again runs within transaction
42
+ # runs after transaction
43
+ #
44
+ #
45
+ #
46
+ def after_transaction(opts = {}, &block)
47
+
48
+ # default options
49
+ default_options = { only: nil, if_no_transaction: :run}
50
+ opts = default_options.merge(opts)
51
+
52
+ # normalize opts to string keys
53
+ normalized = opts.dup
54
+ opts.each{ |k,v| normalized[k.to_s] = v }
55
+ opts = normalized
56
+
57
+
58
+ if ActiveRecord::Base.connection.open_transactions > 0
59
+ callbacks = ActiveRecord::Base.callbacks
60
+
61
+ case opts['only']
62
+ when :commit
63
+ callbacks.store(:commit,&block)
64
+ when :rollback
65
+ callbacks.store(:rollback,&block)
66
+ else
67
+ # both cases
68
+ callbacks.store(:commit,&block)
69
+ callbacks.store(:rollback,&block)
70
+ end
71
+ else
72
+ if opts['if_no_transaction'] == :run
73
+ block.call
74
+ end
75
+ end
76
+ end
77
+ alias after_tx after_transaction
78
+
79
+ ##
80
+ # Executes some code only after current transactions does commit.
81
+ # If no transaction is actually open, the code runs immediately.
82
+ #
83
+ # Shortcut for <tt>after_transaction(only: :commit, if_no_transaction: :run) do ... end </tt>
84
+ #
85
+ # Please use #after_transaction for more options
86
+ def after_commit(&block)
87
+ after_transaction(only: :commit, &block)
88
+ end
89
+
90
+ ##
91
+ # Executes some code only after current transaction does rollback.
92
+ # If no transaction is actually open, the code does not runs.
93
+ #
94
+ # Shortcut for <tt>after_transaction(only: :rollback, if_no_transaction: :skip) do ... end </tt>
95
+ #
96
+ # Please use #after_transaction for more options
97
+ def after_rollback(&block)
98
+ after_transaction(only: :rollback, if_no_transaction: :skip, &block)
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,58 @@
1
+ module FishTransactions
2
+ ##
3
+ # Stores callbacks to be run on certain events
4
+ # (currently, commit-only or rollback-only)
5
+ class CallbacksStorage
6
+
7
+ ##
8
+ # Creates the storage empty
9
+ def initialize
10
+ @on_commit = []
11
+ @on_rollback = []
12
+ end
13
+
14
+ ##
15
+ # Stores a callback block to run on a event
16
+ #
17
+ # An event must be one of these symbols:
18
+ #
19
+ # * +:commit+ - run callback on commit only
20
+ # * +:rollback+ - run callback on rollback only
21
+ # * otherwise will raise an exception
22
+ def store(event,&callback_block)
23
+ case event
24
+ when :commit then @on_commit << callback_block
25
+ when :rollback then @on_rollback << callback_block
26
+ else raise "unknown event #{event.inspect}"
27
+ end
28
+ end
29
+
30
+ ##
31
+ # Runs all callbacks asociated with commit event
32
+ def committed!
33
+ @on_commit.each do |callback|
34
+ callback.call
35
+ end
36
+ clear
37
+ end
38
+
39
+ ##
40
+ # Runs all callbacks asociated with rollback event
41
+ def rolledback!
42
+ @on_rollback.each do |callback|
43
+ callback.call
44
+ end
45
+ clear
46
+ end
47
+
48
+ private
49
+
50
+ ##
51
+ # Clear callbacks
52
+ def clear
53
+ @on_commit.clear
54
+ @on_rollback.clear
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,6 @@
1
+ # :nodoc:
2
+ module FishTransactions
3
+ ##
4
+ # current version
5
+ VERSION = "1.0.0"
6
+ end
@@ -0,0 +1,4 @@
1
+ require 'fish_transactions/version'
2
+ require 'fish_transactions/active_record_mods'
3
+ require 'fish_transactions/callbacks'
4
+
@@ -0,0 +1,332 @@
1
+ require 'fish_transactions'
2
+
3
+ module FishTransactions
4
+
5
+ class TestCallbacksClass
6
+ include Callbacks
7
+
8
+ def run_with_after_commit
9
+ before_the_block
10
+
11
+ after_commit do
12
+ the_after_commit_block
13
+
14
+ end
15
+ after_the_block_just_before_commit
16
+ end
17
+
18
+ def run_with_after_rollback
19
+ before_the_block
20
+
21
+ after_rollback do
22
+ the_after_rollback_block
23
+
24
+ end
25
+ after_the_block_just_before_commit
26
+
27
+ end
28
+
29
+ def run_with_after_transaction_no_args
30
+ before_the_block
31
+
32
+ after_transaction do
33
+ the_after_transaction_block
34
+
35
+ end
36
+ after_the_block_just_before_commit
37
+
38
+ end
39
+
40
+ def run_with_after_transaction(opts)
41
+ before_the_block
42
+
43
+ after_transaction(opts) do
44
+ the_after_transaction_block
45
+
46
+ end
47
+ after_the_block_just_before_commit
48
+
49
+ end
50
+
51
+ def before_the_block; end
52
+ def after_the_block_just_before_commit; end
53
+
54
+ def the_after_commit_block; end
55
+ def the_after_rollback_block; end
56
+ def the_after_transaction_block; end
57
+
58
+ end
59
+
60
+ describe Callbacks do
61
+
62
+ let(:execution_double) do
63
+ double = TestCallbacksClass.new
64
+ allow(double).to receive(:run).and_call_original
65
+ double
66
+ end
67
+
68
+ describe '#after_commit' do
69
+
70
+ context 'without transaction' do
71
+
72
+ it 'should run in place' do
73
+
74
+ expect(execution_double).to receive_in_order(
75
+ :before_the_block,
76
+ :the_after_commit_block,
77
+ :after_the_block_just_before_commit
78
+ )
79
+
80
+ execution_double.run_with_after_commit
81
+
82
+ end
83
+ end
84
+
85
+ context 'within a transaction' do
86
+
87
+ it 'should wait transaction to commit' do
88
+
89
+ expect(execution_double).to receive_in_order(
90
+ :before_the_block,
91
+ :after_the_block_just_before_commit,
92
+ :the_after_commit_block
93
+ )
94
+
95
+ ActiveRecord::Base.transaction do
96
+ execution_double.run_with_after_commit
97
+ end
98
+
99
+ end
100
+
101
+ it 'should not run on rollback' do
102
+ expect(execution_double).to receive_in_order(
103
+ :before_the_block,
104
+ :after_the_block_just_before_commit
105
+ ).but_not(
106
+ :the_after_commit_block
107
+ )
108
+
109
+ ActiveRecord::Base.transaction do
110
+ execution_double.run_with_after_commit
111
+ raise ActiveRecord::Rollback
112
+ end
113
+ end
114
+
115
+ end
116
+
117
+ end
118
+
119
+ describe '#after_rollback' do
120
+
121
+ context 'without transaction' do
122
+
123
+ it 'should not run at all' do
124
+
125
+ expect(execution_double).to receive_in_order(
126
+ :before_the_block,
127
+ :after_the_block_just_before_commit
128
+ ).but_not(
129
+ :the_after_rollback_block
130
+ )
131
+
132
+ execution_double.run_with_after_rollback
133
+
134
+ end
135
+ end
136
+
137
+ context 'within a transaction' do
138
+
139
+ it 'should not run on commit' do
140
+
141
+ expect(execution_double).to receive_in_order(
142
+ :before_the_block,
143
+ :after_the_block_just_before_commit
144
+ ).but_not(
145
+ :the_after_rollback_block
146
+ )
147
+
148
+ ActiveRecord::Base.transaction do
149
+ execution_double.run_with_after_rollback
150
+ end
151
+
152
+ end
153
+
154
+ it 'should run on rollback' do
155
+ expect(execution_double).to receive_in_order(
156
+ :before_the_block,
157
+ :after_the_block_just_before_commit,
158
+ :the_after_rollback_block
159
+ )
160
+
161
+ ActiveRecord::Base.transaction do
162
+ execution_double.run_with_after_rollback
163
+ raise ActiveRecord::Rollback
164
+ end
165
+ end
166
+
167
+ end
168
+
169
+ end
170
+
171
+ describe '#after_transaction' do
172
+
173
+ context 'without a transaction' do
174
+
175
+ context 'by default' do
176
+
177
+ it 'should executes immediately' do
178
+ expect(execution_double).to receive_in_order(
179
+ :before_the_block,
180
+ :the_after_transaction_block,
181
+ :after_the_block_just_before_commit
182
+ )
183
+ execution_double.run_with_after_transaction_no_args
184
+ end
185
+ end
186
+
187
+ context 'and with a {:if_no_transaction => :run} param' do
188
+
189
+ it 'should executes inmediately' do
190
+ expect(execution_double).to receive_in_order(
191
+ :before_the_block,
192
+ :the_after_transaction_block,
193
+ :after_the_block_just_before_commit
194
+ )
195
+ execution_double.run_with_after_transaction(if_no_transaction: :run)
196
+ end
197
+ end
198
+
199
+ context 'and with a {:if_no_transaction => :skip} param' do
200
+ it 'should not execute' do
201
+ expect(execution_double).to receive_in_order(
202
+ :before_the_block,
203
+ :after_the_block_just_before_commit
204
+ ).but_not(
205
+ :the_after_transaction_block
206
+ )
207
+ execution_double.run_with_after_transaction(if_no_transaction: :skip)
208
+ end
209
+ end
210
+
211
+ context 'and with a {:if_no_transaction => :skip} param given as string' do
212
+ it 'should not execute' do
213
+ expect(execution_double).to receive_in_order(
214
+ :before_the_block,
215
+ :after_the_block_just_before_commit
216
+ ).but_not(
217
+ :the_after_transaction_block
218
+ )
219
+ execution_double.run_with_after_transaction('if_no_transaction' => 'skip')
220
+ end
221
+ end
222
+
223
+ end
224
+
225
+ context 'within a transaction' do
226
+
227
+ context 'by default' do
228
+ it 'should executes after commit' do
229
+
230
+ expect(execution_double).to receive_in_order(
231
+ :before_the_block,
232
+ :after_the_block_just_before_commit,
233
+ :the_after_transaction_block
234
+ )
235
+ ActiveRecord::Base.transaction do
236
+ execution_double.run_with_after_transaction_no_args
237
+ end
238
+ end
239
+
240
+ it 'should executes after rollback' do
241
+
242
+ expect(execution_double).to receive_in_order(
243
+ :before_the_block,
244
+ :after_the_block_just_before_commit,
245
+ :the_after_transaction_block
246
+ )
247
+ ActiveRecord::Base.transaction do
248
+ execution_double.run_with_after_transaction_no_args
249
+ raise ActiveRecord::Rollback
250
+ end
251
+ end
252
+
253
+ it 'should executes after failure' do
254
+
255
+ expect(execution_double).to receive_in_order(
256
+ :before_the_block,
257
+ :after_the_block_just_before_commit,
258
+ :the_after_transaction_block
259
+ )
260
+ begin
261
+ ActiveRecord::Base.transaction do
262
+ execution_double.run_with_after_transaction_no_args
263
+ raise "Some other exception"
264
+ end
265
+ rescue # doesn't matter
266
+ end
267
+ end
268
+ end
269
+
270
+ context 'and with a {only: :commit} param' do
271
+ it 'should executes after commit' do
272
+
273
+ expect(execution_double).to receive_in_order(
274
+ :before_the_block,
275
+ :after_the_block_just_before_commit,
276
+ :the_after_transaction_block
277
+ )
278
+ ActiveRecord::Base.transaction do
279
+ execution_double.run_with_after_transaction(only: :commit)
280
+ end
281
+ end
282
+
283
+ it 'should not executes after rollback' do
284
+
285
+ expect(execution_double).to receive_in_order(
286
+ :before_the_block,
287
+ :after_the_block_just_before_commit
288
+ ).but_not(
289
+ :the_after_transaction_block
290
+ )
291
+ ActiveRecord::Base.transaction do
292
+ execution_double.run_with_after_transaction(only: :commit)
293
+ raise ActiveRecord::Rollback
294
+ end
295
+ end
296
+ end
297
+
298
+
299
+ context 'and with a {only: :rollback} param' do
300
+ it 'should not executes after commit' do
301
+
302
+ expect(execution_double).to receive_in_order(
303
+ :before_the_block,
304
+ :after_the_block_just_before_commit
305
+ ).but_not(
306
+ :the_after_transaction_block
307
+ )
308
+ ActiveRecord::Base.transaction do
309
+ execution_double.run_with_after_transaction(only: :rollback)
310
+ end
311
+ end
312
+
313
+ it 'should executes after rollback' do
314
+
315
+ expect(execution_double).to receive_in_order(
316
+ :before_the_block,
317
+ :after_the_block_just_before_commit,
318
+ :the_after_transaction_block
319
+ )
320
+ ActiveRecord::Base.transaction do
321
+ execution_double.run_with_after_transaction(only: :rollback)
322
+ raise ActiveRecord::Rollback
323
+ end
324
+ end
325
+ end
326
+
327
+ end
328
+
329
+ end
330
+
331
+ end
332
+ end
@@ -0,0 +1,119 @@
1
+ require 'fish_transactions/callbacks_storage'
2
+
3
+ module FishTransactions
4
+
5
+ describe CallbacksStorage do
6
+
7
+
8
+ let(:null_proc){ Proc.new{} }
9
+ subject(:storage){ CallbacksStorage.new }
10
+
11
+ # just a warm test: to raise or not to raise error
12
+ describe '#store' do
13
+ it 'accepts commit event' do
14
+ # just run and hope no exception raised
15
+ storage.store(:commit,&null_proc)
16
+ end
17
+ it 'accepts commit event' do
18
+ storage.store(:rollback,&null_proc)
19
+ end
20
+ it 'does not accepts other events' do
21
+ # I prefer to repeat this code lot of times to be more clear than DRYer
22
+
23
+ # test tx AR events
24
+ expect { storage.store(:after_commit,&null_proc) }.to raise_error(RuntimeError, /^unknown event.+$/)
25
+ expect { storage.store(:after_rollback,&null_proc) }.to raise_error(RuntimeError, /^unknown event.+$/)
26
+
27
+ # and some common AR events
28
+ expect { storage.store(:after_validation,&null_proc) }.to raise_error(RuntimeError, /^unknown event.+$/)
29
+ expect { storage.store(:after_create,&null_proc) }.to raise_error(RuntimeError, /^unknown event.+$/)
30
+ expect { storage.store(:after_update,&null_proc) }.to raise_error(RuntimeError, /^unknown event.+$/)
31
+ expect { storage.store(:after_save,&null_proc) }.to raise_error(RuntimeError, /^unknown event.+$/)
32
+
33
+ expect { storage.store(:before_validation,&null_proc) }.to raise_error(RuntimeError, /^unknown event.+$/)
34
+ expect { storage.store(:before_save,&null_proc) }.to raise_error(RuntimeError, /^unknown event.+$/)
35
+ expect { storage.store(:before_create,&null_proc) }.to raise_error(RuntimeError, /^unknown event.+$/)
36
+ expect { storage.store(:before_update,&null_proc) }.to raise_error(RuntimeError, /^unknown event.+$/)
37
+ end
38
+ end
39
+
40
+ describe '#committed!' do
41
+
42
+ it 'runs a stored block' do
43
+ expect do |test_block|
44
+ storage.store :commit, &test_block
45
+ storage.committed!
46
+ end.to yield_control
47
+ end
48
+
49
+ it 'runs any stored block' do
50
+ expect do |test_block|
51
+ # i will store test block in the middle, to be sure
52
+ # that first or last are not the only called
53
+ storage.store :commit, &null_proc
54
+ storage.store :commit, &test_block
55
+ storage.store :commit, &null_proc
56
+ storage.committed!
57
+ end.to yield_control
58
+ end
59
+
60
+ it 'does not a rollback block' do
61
+ expect do |test_block|
62
+ storage.store :rollback, &test_block
63
+ storage.committed!
64
+ end.not_to yield_control
65
+ end
66
+
67
+ it 'clears callbacks' do
68
+ expect do |test_block|
69
+ storage.store :commit, &test_block
70
+ storage.committed!
71
+
72
+ storage.committed!
73
+ end.to yield_control.once
74
+ end
75
+
76
+ end
77
+
78
+ describe '#rollbacked!' do
79
+
80
+ it 'runs a stored block' do
81
+ expect do |test_block|
82
+ storage.store :rollback, &test_block
83
+ storage.rolledback!
84
+ end.to yield_control
85
+ end
86
+
87
+ it 'runs any stored block' do
88
+ expect do |test_block|
89
+ # i will store test block in the middle, to be sure
90
+ # that first or last are not the only called
91
+ storage.store :rollback, &null_proc
92
+ storage.store :rollback, &test_block
93
+ storage.store :rollback, &null_proc
94
+ storage.rolledback!
95
+ end.to yield_control
96
+ end
97
+
98
+ it 'does not a rollback block' do
99
+ expect do |test_block|
100
+ storage.store :commit, &test_block
101
+ storage.rolledback!
102
+ end.not_to yield_control
103
+ end
104
+
105
+ it 'clears callbacks' do
106
+ expect do |test_block|
107
+ storage.store :rollback, &test_block
108
+ storage.rolledback!
109
+
110
+ storage.rolledback!
111
+ end.to yield_control.once
112
+ end
113
+
114
+
115
+ end
116
+
117
+ end
118
+
119
+ end
@@ -0,0 +1,25 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
4
+ require 'rspec'
5
+ require 'active_record'
6
+
7
+ ActiveRecord::Base.establish_connection :adapter => :nulldb
8
+
9
+ require 'rspec/expectations'
10
+
11
+ RSpec::Matchers.define :receive_in_order do |*expected_call_order|
12
+ match do |test_double|
13
+ Array.wrap(expected_call_order).each do |a_call|
14
+ expect(test_double).to receive(a_call).ordered
15
+ end
16
+ Array.wrap(@not_to_be_called).each do |avoid_call|
17
+ expect(test_double).not_to receive(avoid_call)
18
+ end
19
+ true
20
+ end
21
+
22
+ chain :but_not do |*expected_not_be_called|
23
+ @not_to_be_called = expected_not_be_called
24
+ end
25
+ end
metadata ADDED
@@ -0,0 +1,159 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fish_transactions
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - John Owen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-06-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rdoc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.12'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.11'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.11'
83
+ - !ruby/object:Gem::Dependency
84
+ name: activerecord-nulldb-adapter
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: activerecord
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '4.2'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '4.2'
111
+ description: Allows to pospose the execution of a code waiting for Active Record transactions,
112
+ on commit, on rollback or both.
113
+ email:
114
+ - john.owen@beetrack.com
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - MIT-LICENSE.txt
120
+ - README.md
121
+ - Rakefile
122
+ - lib/fish_transactions.rb
123
+ - lib/fish_transactions/active_record_mods.rb
124
+ - lib/fish_transactions/active_record_mods/base.rb
125
+ - lib/fish_transactions/active_record_mods/connection_abstract_adapter.rb
126
+ - lib/fish_transactions/callbacks.rb
127
+ - lib/fish_transactions/callbacks_storage.rb
128
+ - lib/fish_transactions/version.rb
129
+ - spec/callbacks_spec.rb
130
+ - spec/callbacks_storage_spec.rb
131
+ - spec/spec_helper.rb
132
+ homepage: https://github.com/Beetrack/fish_transactions
133
+ licenses:
134
+ - MIT
135
+ metadata: {}
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: 2.1.0
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubyforge_project:
152
+ rubygems_version: 2.4.5.1
153
+ signing_key:
154
+ specification_version: 4
155
+ summary: Callbacks for Active Record transactions that can be used anywhere.
156
+ test_files:
157
+ - spec/callbacks_spec.rb
158
+ - spec/callbacks_storage_spec.rb
159
+ - spec/spec_helper.rb