fish_transactions 1.0.0

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.
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