ardm-transactions 1.2.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 +7 -0
- data/.document +5 -0
- data/.gitignore +36 -0
- data/.travis.yml +11 -0
- data/Gemfile +47 -0
- data/LICENSE +20 -0
- data/README.rdoc +23 -0
- data/Rakefile +4 -0
- data/ardm-transactions.gemspec +25 -0
- data/lib/ardm-transactions.rb +1 -0
- data/lib/dm-transactions.rb +443 -0
- data/lib/dm-transactions/adapters/dm-do-adapter.rb +112 -0
- data/lib/dm-transactions/adapters/dm-mysql-adapter.rb +15 -0
- data/lib/dm-transactions/adapters/dm-oracle-adapter.rb +11 -0
- data/lib/dm-transactions/adapters/dm-postgres-adapter.rb +15 -0
- data/lib/dm-transactions/adapters/dm-sqlite-adapter.rb +11 -0
- data/lib/dm-transactions/adapters/dm-sqlserver-adapter.rb +11 -0
- data/lib/dm-transactions/version.rb +5 -0
- data/spec/isolated/require_after_setup_spec.rb +21 -0
- data/spec/isolated/require_before_setup_spec.rb +21 -0
- data/spec/isolated/require_spec.rb +15 -0
- data/spec/public/dm-transactions_spec.rb +222 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +20 -0
- data/tasks/spec.rake +38 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +19 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 10896a2c7320a29dcc5ed6a1f64a228dd8c7df05
|
4
|
+
data.tar.gz: 3d7cc2c2e29e306e83f45f2b87f37b62b80e8b4f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5eb9144e58d1b7f58928ef452b652773fd4423c6bbcdba01189f690ea68fa6d48ffb982fa8cfc352765f60c26bca1f255da0942162db7ffa5998afa32d9542bc
|
7
|
+
data.tar.gz: 8788e5183a35cc4d3208d0cc601dca0482c6118ca195006803b7ca4d4c4b955a53b3d9686f847456e383f6a657f402ef009c22ca6fe770efa040e370b41a6f67
|
data/.document
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
## MAC OS
|
2
|
+
.DS_Store
|
3
|
+
|
4
|
+
## TEXTMATE
|
5
|
+
*.tmproj
|
6
|
+
tmtags
|
7
|
+
|
8
|
+
## EMACS
|
9
|
+
*~
|
10
|
+
\#*
|
11
|
+
.\#*
|
12
|
+
|
13
|
+
## VIM
|
14
|
+
*.swp
|
15
|
+
|
16
|
+
## Rubinius
|
17
|
+
*.rbc
|
18
|
+
|
19
|
+
## PROJECT::GENERAL
|
20
|
+
*.gem
|
21
|
+
coverage
|
22
|
+
rdoc
|
23
|
+
pkg
|
24
|
+
tmp
|
25
|
+
doc
|
26
|
+
log
|
27
|
+
.yardoc
|
28
|
+
measurements
|
29
|
+
|
30
|
+
## BUNDLER
|
31
|
+
.bundle
|
32
|
+
Gemfile.*
|
33
|
+
|
34
|
+
## PROJECT::SPECIFIC
|
35
|
+
spec/db/
|
36
|
+
spec/log/
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
gemspec
|
6
|
+
|
7
|
+
SOURCE = ENV.fetch('SOURCE', :git).to_sym
|
8
|
+
REPO_POSTFIX = SOURCE == :path ? '' : '.git'
|
9
|
+
DATAMAPPER = SOURCE == :path ? Pathname(__FILE__).dirname.parent : 'http://github.com/ar-dm'
|
10
|
+
DM_VERSION = '~> 1.2.0'
|
11
|
+
DO_VERSION = '~> 0.10.6'
|
12
|
+
DM_DO_ADAPTERS = %w[ sqlite postgres mysql oracle sqlserver ]
|
13
|
+
CURRENT_BRANCH = ENV.fetch('GIT_BRANCH', 'master')
|
14
|
+
|
15
|
+
gem 'ardm-core', DM_VERSION, SOURCE => "#{DATAMAPPER}/ardm-core#{REPO_POSTFIX}", :branch => CURRENT_BRANCH
|
16
|
+
|
17
|
+
group :datamapper do
|
18
|
+
|
19
|
+
adapters = ENV['ADAPTER'] || ENV['ADAPTERS']
|
20
|
+
adapters = adapters.to_s.tr(',', ' ').split.uniq - %w[ in_memory ]
|
21
|
+
|
22
|
+
if (do_adapters = DM_DO_ADAPTERS & adapters).any?
|
23
|
+
do_options = {}
|
24
|
+
do_options[:git] = "#{DATAMAPPER}/do#{REPO_POSTFIX}" if ENV['DO_GIT'] == 'true'
|
25
|
+
|
26
|
+
gem 'data_objects', DO_VERSION, do_options.dup
|
27
|
+
|
28
|
+
do_adapters.each do |adapter|
|
29
|
+
adapter = 'sqlite3' if adapter == 'sqlite'
|
30
|
+
gem "do_#{adapter}", DO_VERSION, do_options.dup
|
31
|
+
end
|
32
|
+
|
33
|
+
gem 'ardm-do-adapter', DM_VERSION, SOURCE => "#{DATAMAPPER}/ardm-do-adapter#{REPO_POSTFIX}", :branch => CURRENT_BRANCH
|
34
|
+
end
|
35
|
+
|
36
|
+
adapters.each do |adapter|
|
37
|
+
gem "ardm-#{adapter}-adapter", DM_VERSION, SOURCE => "#{DATAMAPPER}/ardm-#{adapter}-adapter#{REPO_POSTFIX}", :branch => CURRENT_BRANCH
|
38
|
+
end
|
39
|
+
|
40
|
+
plugins = ENV['PLUGINS'] || ENV['PLUGIN']
|
41
|
+
plugins = plugins.to_s.tr(',', ' ').split.push('ardm-migrations').uniq
|
42
|
+
|
43
|
+
plugins.each do |plugin|
|
44
|
+
gem plugin, DM_VERSION, SOURCE => "#{DATAMAPPER}/#{plugin}#{REPO_POSTFIX}", :branch => CURRENT_BRANCH
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 snusnu
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
= dm-transactions
|
2
|
+
|
3
|
+
This gem adds transaction support for datamapper. The currently supported adapters are
|
4
|
+
|
5
|
+
* postgres
|
6
|
+
* mysql
|
7
|
+
* sqlite3
|
8
|
+
* oracle
|
9
|
+
* sqlserver
|
10
|
+
|
11
|
+
== Note on Patches/Pull Requests
|
12
|
+
|
13
|
+
* Fork the project.
|
14
|
+
* Make your feature addition or bug fix.
|
15
|
+
* Add tests for it. This is important so I don't break it in a
|
16
|
+
future version unintentionally.
|
17
|
+
* Commit, do not mess with rakefile, version, or history.
|
18
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
19
|
+
* Send me a pull request. Bonus points for topic branches.
|
20
|
+
|
21
|
+
== Copyright
|
22
|
+
|
23
|
+
Copyright (c) 2011 snusnu. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/dm-transactions/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = "ardm-transactions"
|
6
|
+
gem.version = DataMapper::Transactions::VERSION
|
7
|
+
|
8
|
+
gem.authors = [ 'Martin Emde', 'Dirkjan Bussink (dbussink)', 'Dan Kubb (dkubb)' ]
|
9
|
+
gem.email = [ 'me@martinemde.com', "gamsnjaga@gmail.com" ]
|
10
|
+
gem.summary = "Ardm fork of dm-transactions"
|
11
|
+
gem.description = "Makes transaction support available for adapters that support them"
|
12
|
+
gem.homepage = "https://github.com/ar-dm/ardm-transactions"
|
13
|
+
gem.license = 'MIT'
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split("\n")
|
16
|
+
gem.test_files = `git ls-files -- {spec}/*`.split("\n")
|
17
|
+
gem.extra_rdoc_files = %w[LICENSE README.rdoc]
|
18
|
+
|
19
|
+
gem.require_paths = [ "lib" ]
|
20
|
+
|
21
|
+
gem.add_runtime_dependency 'ardm-core', '~> 1.2'
|
22
|
+
|
23
|
+
gem.add_development_dependency 'rake', '~> 0.9'
|
24
|
+
gem.add_development_dependency 'rspec', '~> 1.3'
|
25
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'dm-transactions'
|
@@ -0,0 +1,443 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
class Transaction
|
5
|
+
extend Chainable
|
6
|
+
|
7
|
+
# @api private
|
8
|
+
attr_accessor :state
|
9
|
+
|
10
|
+
# @api private
|
11
|
+
def none?
|
12
|
+
state == :none
|
13
|
+
end
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
def begin?
|
17
|
+
state == :begin
|
18
|
+
end
|
19
|
+
|
20
|
+
# @api private
|
21
|
+
def rollback?
|
22
|
+
state == :rollback
|
23
|
+
end
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
def commit?
|
27
|
+
state == :commit
|
28
|
+
end
|
29
|
+
|
30
|
+
# Create a new Transaction
|
31
|
+
#
|
32
|
+
# @see Transaction#link
|
33
|
+
#
|
34
|
+
# In fact, it just calls #link with the given arguments at the end of the
|
35
|
+
# constructor.
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
def initialize(*things)
|
39
|
+
@transaction_primitives = {}
|
40
|
+
self.state = :none
|
41
|
+
@adapters = {}
|
42
|
+
link(*things)
|
43
|
+
if block_given?
|
44
|
+
warn "Passing block to #{self.class.name}.new is deprecated (#{caller[0]})"
|
45
|
+
commit { |*block_args| yield(*block_args) }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Associate this Transaction with some things.
|
50
|
+
#
|
51
|
+
# @param [Object] things
|
52
|
+
# the things you want this Transaction associated with:
|
53
|
+
#
|
54
|
+
# Adapters::AbstractAdapter subclasses will be added as
|
55
|
+
# adapters as is.
|
56
|
+
# Arrays will have their elements added.
|
57
|
+
# Repository will have it's own @adapters added.
|
58
|
+
# Resource subclasses will have all the repositories of all
|
59
|
+
# their properties added.
|
60
|
+
# Resource instances will have all repositories of all their
|
61
|
+
# properties added.
|
62
|
+
#
|
63
|
+
# @param [Proc] block
|
64
|
+
# a block (taking one argument, the Transaction) to execute within
|
65
|
+
# this transaction. The transaction will begin and commit around
|
66
|
+
# the block, and rollback if an exception is raised.
|
67
|
+
#
|
68
|
+
# @api private
|
69
|
+
def link(*things)
|
70
|
+
unless none?
|
71
|
+
raise "Illegal state for link: #{state}"
|
72
|
+
end
|
73
|
+
|
74
|
+
things.each do |thing|
|
75
|
+
case thing
|
76
|
+
when DataMapper::Adapters::AbstractAdapter
|
77
|
+
@adapters[thing] = :none
|
78
|
+
when DataMapper::Repository
|
79
|
+
link(thing.adapter)
|
80
|
+
when DataMapper::Model
|
81
|
+
link(*thing.repositories)
|
82
|
+
when DataMapper::Resource
|
83
|
+
link(thing.model)
|
84
|
+
when Array
|
85
|
+
link(*thing)
|
86
|
+
else
|
87
|
+
raise "Unknown argument to #{self.class}#link: #{thing.inspect} (#{thing.class})"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
if block_given?
|
92
|
+
commit { |*block_args| yield(*block_args) }
|
93
|
+
else
|
94
|
+
self
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Begin the transaction
|
99
|
+
#
|
100
|
+
# Before #begin is called, the transaction is not valid and can not be used.
|
101
|
+
#
|
102
|
+
# @api private
|
103
|
+
def begin
|
104
|
+
unless none?
|
105
|
+
raise "Illegal state for begin: #{state}"
|
106
|
+
end
|
107
|
+
|
108
|
+
each_adapter(:connect_adapter, [:log_fatal_transaction_breakage])
|
109
|
+
each_adapter(:begin_adapter, [:rollback_and_close_adapter_if_begin, :close_adapter_if_none])
|
110
|
+
self.state = :begin
|
111
|
+
end
|
112
|
+
|
113
|
+
# Commit the transaction
|
114
|
+
#
|
115
|
+
# If no block is given, it will simply commit any changes made since the
|
116
|
+
# Transaction did #begin.
|
117
|
+
#
|
118
|
+
# @param block<Block> a block (taking the one argument, the Transaction) to
|
119
|
+
# execute within this transaction. The transaction will begin and commit
|
120
|
+
# around the block, and roll back if an exception is raised.
|
121
|
+
#
|
122
|
+
# @api private
|
123
|
+
def commit
|
124
|
+
if block_given?
|
125
|
+
unless none?
|
126
|
+
raise "Illegal state for commit with block: #{state}"
|
127
|
+
end
|
128
|
+
|
129
|
+
begin
|
130
|
+
self.begin
|
131
|
+
rval = within { |*block_args| yield(*block_args) }
|
132
|
+
rescue Exception => exception
|
133
|
+
if begin?
|
134
|
+
rollback
|
135
|
+
end
|
136
|
+
raise exception
|
137
|
+
ensure
|
138
|
+
unless exception
|
139
|
+
if begin?
|
140
|
+
commit
|
141
|
+
end
|
142
|
+
return rval
|
143
|
+
end
|
144
|
+
end
|
145
|
+
else
|
146
|
+
unless begin?
|
147
|
+
raise "Illegal state for commit without block: #{state}"
|
148
|
+
end
|
149
|
+
each_adapter(:commit_adapter, [:log_fatal_transaction_breakage])
|
150
|
+
each_adapter(:close_adapter, [:log_fatal_transaction_breakage])
|
151
|
+
self.state = :commit
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Rollback the transaction
|
156
|
+
#
|
157
|
+
# Will undo all changes made during the transaction.
|
158
|
+
#
|
159
|
+
# @api private
|
160
|
+
def rollback
|
161
|
+
unless begin?
|
162
|
+
raise "Illegal state for rollback: #{state}"
|
163
|
+
end
|
164
|
+
each_adapter(:rollback_adapter_if_begin, [:rollback_and_close_adapter_if_begin, :close_adapter_if_none])
|
165
|
+
each_adapter(:close_adapter_if_open, [:log_fatal_transaction_breakage])
|
166
|
+
self.state = :rollback
|
167
|
+
end
|
168
|
+
|
169
|
+
# Execute a block within this Transaction.
|
170
|
+
#
|
171
|
+
# No #begin, #commit or #rollback is performed in #within, but this
|
172
|
+
# Transaction will pushed on the per thread stack of transactions for each
|
173
|
+
# adapter it is associated with, and it will ensures that it will pop the
|
174
|
+
# Transaction away again after the block is finished.
|
175
|
+
#
|
176
|
+
# @param block<Block> the block of code to execute.
|
177
|
+
#
|
178
|
+
# @api private
|
179
|
+
def within
|
180
|
+
unless block_given?
|
181
|
+
raise 'No block provided'
|
182
|
+
end
|
183
|
+
|
184
|
+
unless begin?
|
185
|
+
raise "Illegal state for within: #{state}"
|
186
|
+
end
|
187
|
+
|
188
|
+
adapters = @adapters
|
189
|
+
|
190
|
+
adapters.each_key do |adapter|
|
191
|
+
adapter.push_transaction(self)
|
192
|
+
end
|
193
|
+
|
194
|
+
begin
|
195
|
+
yield self
|
196
|
+
ensure
|
197
|
+
adapters.each_key do |adapter|
|
198
|
+
adapter.pop_transaction
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# @api private
|
204
|
+
def method_missing(method, *args, &block)
|
205
|
+
first_arg = args.first
|
206
|
+
|
207
|
+
return super unless args.size == 1 && first_arg.kind_of?(Adapters::AbstractAdapter)
|
208
|
+
return super unless match = method.to_s.match(/\A(.*)_(if|unless)_(none|begin|rollback|commit)\z/)
|
209
|
+
|
210
|
+
action, condition, expected_state = match.captures
|
211
|
+
return super unless respond_to?(action, true)
|
212
|
+
|
213
|
+
state = state_for(first_arg).to_s
|
214
|
+
execute = (condition == 'if') == (state == expected_state)
|
215
|
+
|
216
|
+
send(action, first_arg) if execute
|
217
|
+
end
|
218
|
+
|
219
|
+
# @api private
|
220
|
+
def primitive_for(adapter)
|
221
|
+
unless @adapters.include?(adapter)
|
222
|
+
raise "Unknown adapter #{adapter}"
|
223
|
+
end
|
224
|
+
|
225
|
+
unless @transaction_primitives.include?(adapter)
|
226
|
+
raise "No primitive for #{adapter}"
|
227
|
+
end
|
228
|
+
|
229
|
+
@transaction_primitives[adapter]
|
230
|
+
end
|
231
|
+
|
232
|
+
private
|
233
|
+
|
234
|
+
# @api private
|
235
|
+
def validate_primitive(primitive)
|
236
|
+
[:close, :begin, :rollback, :commit].each do |meth|
|
237
|
+
unless primitive.respond_to?(meth)
|
238
|
+
raise "Invalid primitive #{primitive}: doesnt respond_to?(#{meth.inspect})"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
primitive
|
243
|
+
end
|
244
|
+
|
245
|
+
# @api private
|
246
|
+
def each_adapter(method, on_fail)
|
247
|
+
adapters = @adapters
|
248
|
+
begin
|
249
|
+
adapters.each_key do |adapter|
|
250
|
+
send(method, adapter)
|
251
|
+
end
|
252
|
+
rescue Exception => exception
|
253
|
+
adapters.each_key do |adapter|
|
254
|
+
on_fail.each do |fail_handler|
|
255
|
+
begin
|
256
|
+
send(fail_handler, adapter)
|
257
|
+
rescue Exception => inner_exception
|
258
|
+
DataMapper.logger.fatal("#{self}#each_adapter(#{method.inspect}, #{on_fail.inspect}) failed with #{exception.inspect}: #{exception.backtrace.join("\n")} - and when sending #{fail_handler} to #{adapter} we failed again with #{inner_exception.inspect}: #{inner_exception.backtrace.join("\n")}")
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
raise exception
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
# @api private
|
267
|
+
def state_for(adapter)
|
268
|
+
unless @adapters.include?(adapter)
|
269
|
+
raise "Unknown adapter #{adapter}"
|
270
|
+
end
|
271
|
+
|
272
|
+
@adapters[adapter]
|
273
|
+
end
|
274
|
+
|
275
|
+
# @api private
|
276
|
+
def do_adapter(adapter, what, prerequisite)
|
277
|
+
unless @transaction_primitives.include?(adapter)
|
278
|
+
raise "No primitive for #{adapter}"
|
279
|
+
end
|
280
|
+
|
281
|
+
state = state_for(adapter)
|
282
|
+
|
283
|
+
unless state == prerequisite
|
284
|
+
raise "Illegal state for #{what}: #{state}"
|
285
|
+
end
|
286
|
+
|
287
|
+
DataMapper.logger.debug("#{adapter.name}: #{what}")
|
288
|
+
@transaction_primitives[adapter].send(what)
|
289
|
+
@adapters[adapter] = what
|
290
|
+
end
|
291
|
+
|
292
|
+
# @api private
|
293
|
+
def log_fatal_transaction_breakage(adapter)
|
294
|
+
DataMapper.logger.fatal("#{self} experienced a totally broken transaction execution. Presenting member #{adapter.inspect}.")
|
295
|
+
end
|
296
|
+
|
297
|
+
# @api private
|
298
|
+
def connect_adapter(adapter)
|
299
|
+
if @transaction_primitives.key?(adapter)
|
300
|
+
raise "Already a primitive for adapter #{adapter}"
|
301
|
+
end
|
302
|
+
|
303
|
+
@transaction_primitives[adapter] = validate_primitive(adapter.transaction_primitive)
|
304
|
+
end
|
305
|
+
|
306
|
+
# @api private
|
307
|
+
def close_adapter_if_open(adapter)
|
308
|
+
if @transaction_primitives.include?(adapter)
|
309
|
+
close_adapter(adapter)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# @api private
|
314
|
+
def close_adapter(adapter)
|
315
|
+
unless @transaction_primitives.include?(adapter)
|
316
|
+
raise 'No primitive for adapter'
|
317
|
+
end
|
318
|
+
|
319
|
+
@transaction_primitives[adapter].close
|
320
|
+
@transaction_primitives.delete(adapter)
|
321
|
+
end
|
322
|
+
|
323
|
+
# @api private
|
324
|
+
def begin_adapter(adapter)
|
325
|
+
do_adapter(adapter, :begin, :none)
|
326
|
+
end
|
327
|
+
|
328
|
+
# @api private
|
329
|
+
def commit_adapter(adapter)
|
330
|
+
do_adapter(adapter, :commit, :begin)
|
331
|
+
end
|
332
|
+
|
333
|
+
# @api private
|
334
|
+
def rollback_adapter(adapter)
|
335
|
+
do_adapter(adapter, :rollback, :begin)
|
336
|
+
end
|
337
|
+
|
338
|
+
# @api private
|
339
|
+
def rollback_and_close_adapter(adapter)
|
340
|
+
rollback_adapter(adapter)
|
341
|
+
close_adapter(adapter)
|
342
|
+
end
|
343
|
+
|
344
|
+
module Repository
|
345
|
+
|
346
|
+
# Produce a new Transaction for this Repository
|
347
|
+
#
|
348
|
+
# @return [Adapters::Transaction]
|
349
|
+
# a new Transaction (in state :none) that can be used
|
350
|
+
# to execute code #with_transaction
|
351
|
+
#
|
352
|
+
# @api public
|
353
|
+
def transaction
|
354
|
+
Transaction.new(self)
|
355
|
+
end
|
356
|
+
end # module Repository
|
357
|
+
|
358
|
+
module Model
|
359
|
+
# @api private
|
360
|
+
def self.included(mod)
|
361
|
+
mod.descendants.each { |model| model.extend self }
|
362
|
+
end
|
363
|
+
|
364
|
+
# Produce a new Transaction for this Resource class
|
365
|
+
#
|
366
|
+
# @return <Adapters::Transaction
|
367
|
+
# a new Adapters::Transaction with all Repositories
|
368
|
+
# of the class of this Resource added.
|
369
|
+
#
|
370
|
+
# @api public
|
371
|
+
def transaction
|
372
|
+
transaction = Transaction.new(self)
|
373
|
+
transaction.commit { |block_args| yield(*block_args) }
|
374
|
+
end
|
375
|
+
end # module Model
|
376
|
+
|
377
|
+
module Resource
|
378
|
+
|
379
|
+
# Produce a new Transaction for the class of this Resource
|
380
|
+
#
|
381
|
+
# @return [Adapters::Transaction]
|
382
|
+
# a new Adapters::Transaction for the Repository
|
383
|
+
# of the class of this Resource added.
|
384
|
+
#
|
385
|
+
# @api public
|
386
|
+
def transaction
|
387
|
+
model.transaction { |*block_args| yield(*block_args) }
|
388
|
+
end
|
389
|
+
end # module Resource
|
390
|
+
|
391
|
+
def self.include_transaction_api
|
392
|
+
[ :Repository, :Model, :Resource ].each do |name|
|
393
|
+
DataMapper.const_get(name).send(:include, const_get(name))
|
394
|
+
end
|
395
|
+
Adapters::AbstractAdapter.descendants.each do |adapter_class|
|
396
|
+
Adapters.include_transaction_api(DataMapper::Inflector.demodulize(adapter_class.name))
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
end # class Transaction
|
401
|
+
|
402
|
+
module Adapters
|
403
|
+
|
404
|
+
def self.include_transaction_api(const_name)
|
405
|
+
require transaction_extensions(const_name)
|
406
|
+
if Transaction.const_defined?(const_name)
|
407
|
+
adapter = const_get(const_name)
|
408
|
+
adapter.send(:include, transaction_module(const_name))
|
409
|
+
end
|
410
|
+
rescue LoadError
|
411
|
+
# Silently ignore the fact that no adapter extensions could be required
|
412
|
+
# This means that the adapter in use doesn't support transactions
|
413
|
+
end
|
414
|
+
|
415
|
+
def self.transaction_module(const_name)
|
416
|
+
Transaction.const_get(const_name)
|
417
|
+
end
|
418
|
+
|
419
|
+
class << self
|
420
|
+
private
|
421
|
+
|
422
|
+
# @api private
|
423
|
+
def transaction_extensions(const_name)
|
424
|
+
name = adapter_name(const_name)
|
425
|
+
name = 'do' if name == 'dataobjects'
|
426
|
+
"dm-transactions/adapters/dm-#{name}-adapter"
|
427
|
+
end
|
428
|
+
|
429
|
+
end
|
430
|
+
|
431
|
+
extendable do
|
432
|
+
# @api private
|
433
|
+
def const_added(const_name)
|
434
|
+
include_transaction_api(const_name)
|
435
|
+
super
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
end # module Adapters
|
440
|
+
|
441
|
+
Transaction.include_transaction_api
|
442
|
+
|
443
|
+
end # module DataMapper
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module DataMapper
|
2
|
+
class Transaction
|
3
|
+
|
4
|
+
module DataObjectsAdapter
|
5
|
+
extend Chainable
|
6
|
+
|
7
|
+
# Produces a fresh transaction primitive for this Adapter
|
8
|
+
#
|
9
|
+
# Used by Transaction to perform its various tasks.
|
10
|
+
#
|
11
|
+
# @return [Object]
|
12
|
+
# a new Object that responds to :close, :begin, :commit,
|
13
|
+
# and :rollback,
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
def transaction_primitive
|
17
|
+
if current_transaction && supports_savepoints?
|
18
|
+
DataObjects::SavePoint.create_for_uri(normalized_uri, current_connection)
|
19
|
+
else
|
20
|
+
DataObjects::Transaction.create_for_uri(normalized_uri)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Pushes the given Transaction onto the per thread Transaction stack so
|
25
|
+
# that everything done by this Adapter is done within the context of said
|
26
|
+
# Transaction.
|
27
|
+
#
|
28
|
+
# @param [Transaction] transaction
|
29
|
+
# a Transaction to be the 'current' transaction until popped.
|
30
|
+
#
|
31
|
+
# @return [Array(Transaction)]
|
32
|
+
# the stack of active transactions for the current thread
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
def push_transaction(transaction)
|
36
|
+
transactions << transaction
|
37
|
+
end
|
38
|
+
|
39
|
+
# Pop the 'current' Transaction from the per thread Transaction stack so
|
40
|
+
# that everything done by this Adapter is no longer necessarily within the
|
41
|
+
# context of said Transaction.
|
42
|
+
#
|
43
|
+
# @return [Transaction]
|
44
|
+
# the former 'current' transaction.
|
45
|
+
#
|
46
|
+
# @api private
|
47
|
+
def pop_transaction
|
48
|
+
transactions.pop
|
49
|
+
end
|
50
|
+
|
51
|
+
# Retrieve the current transaction for this Adapter.
|
52
|
+
#
|
53
|
+
# Everything done by this Adapter is done within the context of this
|
54
|
+
# Transaction.
|
55
|
+
#
|
56
|
+
# @return [Transaction]
|
57
|
+
# the 'current' transaction for this Adapter.
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
def current_transaction
|
61
|
+
transactions.last
|
62
|
+
end
|
63
|
+
|
64
|
+
chainable do
|
65
|
+
protected
|
66
|
+
|
67
|
+
# @api semipublic
|
68
|
+
def open_connection
|
69
|
+
current_connection || super
|
70
|
+
end
|
71
|
+
|
72
|
+
# @api semipublic
|
73
|
+
def close_connection(connection)
|
74
|
+
super unless current_connection.equal?(connection)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
# @api private
|
81
|
+
def transactions
|
82
|
+
Thread.current[:dm_transactions] ||= {}
|
83
|
+
Thread.current[:dm_transactions][object_id] ||= []
|
84
|
+
end
|
85
|
+
|
86
|
+
# Retrieve the current connection for this Adapter.
|
87
|
+
#
|
88
|
+
# @return [Transaction]
|
89
|
+
# the 'current' connection for this Adapter.
|
90
|
+
#
|
91
|
+
# @api private
|
92
|
+
def current_connection
|
93
|
+
if transaction = current_transaction
|
94
|
+
transaction.primitive_for(self).connection
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Indicate whether adapter supports transactional savepoints. Not all DO
|
99
|
+
# adapters do, so default to false.
|
100
|
+
#
|
101
|
+
# @return [Boolean]
|
102
|
+
# whether or not the adapter supports savepoints
|
103
|
+
#
|
104
|
+
# @api private
|
105
|
+
def supports_savepoints?
|
106
|
+
false
|
107
|
+
end
|
108
|
+
|
109
|
+
end # module DataObjectsAdapter
|
110
|
+
|
111
|
+
end # class Transaction
|
112
|
+
end # module DataMapper
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec'
|
2
|
+
require 'isolated/require_spec'
|
3
|
+
require 'dm-core/spec/setup'
|
4
|
+
|
5
|
+
# To really test this behavior, this spec needs to be run in isolation and not
|
6
|
+
# as part of the typical rake spec run, which requires dm-transactions upfront
|
7
|
+
|
8
|
+
if %w[ postgres mysql sqlite oracle sqlserver ].include?(ENV['ADAPTER'])
|
9
|
+
|
10
|
+
describe "require 'dm-transactions after calling DataMapper.setup" do
|
11
|
+
|
12
|
+
before(:all) do
|
13
|
+
@adapter = DataMapper::Spec.adapter
|
14
|
+
require 'dm-transactions'
|
15
|
+
end
|
16
|
+
|
17
|
+
it_should_behave_like "require 'dm-transactions'"
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec'
|
2
|
+
require 'isolated/require_spec'
|
3
|
+
require 'dm-core/spec/setup'
|
4
|
+
|
5
|
+
# To really test this behavior, this spec needs to be run in isolation and not
|
6
|
+
# as part of the typical rake spec run, which requires dm-transactions upfront
|
7
|
+
|
8
|
+
if %w[ postgres mysql sqlite oracle sqlserver ].include?(ENV['ADAPTER'])
|
9
|
+
|
10
|
+
describe "require 'dm-transactions' before calling DataMapper.setup" do
|
11
|
+
|
12
|
+
before(:all) do
|
13
|
+
require 'dm-transactions'
|
14
|
+
@adapter = DataMapper::Spec.adapter
|
15
|
+
end
|
16
|
+
|
17
|
+
it_should_behave_like "require 'dm-transactions'"
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
shared_examples_for "require 'dm-transactions'" do
|
2
|
+
|
3
|
+
%w[ Repository Model Resource ].each do |name|
|
4
|
+
it "should include the transaction api in DataMapper::#{name}" do
|
5
|
+
(DataMapper.const_get(name) < DataMapper::Transaction.const_get(name)).should be(true)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should include the transaction api into the adapter" do
|
10
|
+
@adapter.respond_to?(:push_transaction ).should be(true)
|
11
|
+
@adapter.respond_to?(:pop_transaction ).should be(true)
|
12
|
+
@adapter.respond_to?(:current_transaction).should be(true)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DataMapper::Resource, 'Transactions' do
|
4
|
+
before :all do
|
5
|
+
module ::Blog
|
6
|
+
class User
|
7
|
+
include DataMapper::Resource
|
8
|
+
|
9
|
+
property :name, String, :key => true
|
10
|
+
property :age, Integer
|
11
|
+
property :summary, Text
|
12
|
+
property :description, Text
|
13
|
+
property :admin, Boolean, :accessor => :private
|
14
|
+
|
15
|
+
belongs_to :parent, self, :required => false
|
16
|
+
has n, :children, self, :inverse => :parent
|
17
|
+
|
18
|
+
belongs_to :referrer, self, :required => false
|
19
|
+
has n, :comments
|
20
|
+
|
21
|
+
# FIXME: figure out a different approach than stubbing things out
|
22
|
+
def comment=(*)
|
23
|
+
# do nothing with comment
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Author < User; end
|
28
|
+
|
29
|
+
class Comment
|
30
|
+
include DataMapper::Resource
|
31
|
+
|
32
|
+
property :id, Serial
|
33
|
+
property :body, Text
|
34
|
+
|
35
|
+
belongs_to :user
|
36
|
+
end
|
37
|
+
|
38
|
+
class Article
|
39
|
+
include DataMapper::Resource
|
40
|
+
|
41
|
+
property :id, Serial
|
42
|
+
property :body, Text
|
43
|
+
|
44
|
+
has n, :paragraphs
|
45
|
+
end
|
46
|
+
|
47
|
+
class Paragraph
|
48
|
+
include DataMapper::Resource
|
49
|
+
|
50
|
+
property :id, Serial
|
51
|
+
property :text, String
|
52
|
+
|
53
|
+
belongs_to :article
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class ::Default
|
58
|
+
include DataMapper::Resource
|
59
|
+
|
60
|
+
property :name, String, :key => true, :default => 'a default value'
|
61
|
+
end
|
62
|
+
|
63
|
+
@user_model = Blog::User
|
64
|
+
@author_model = Blog::Author
|
65
|
+
@comment_model = Blog::Comment
|
66
|
+
@article_model = Blog::Article
|
67
|
+
@paragraph_model = Blog::Paragraph
|
68
|
+
end
|
69
|
+
|
70
|
+
supported_by :postgres, :mysql, :sqlite, :oracle, :sqlserver do
|
71
|
+
before :all do
|
72
|
+
user = @user_model.create(:name => 'dbussink', :age => 25, :description => 'Test')
|
73
|
+
|
74
|
+
@user = @user_model.get(*user.key)
|
75
|
+
end
|
76
|
+
|
77
|
+
before do
|
78
|
+
# --- Temporary private api use to get around rspec limitations ---
|
79
|
+
@repository.scope do |repository|
|
80
|
+
transaction = DataMapper::Transaction.new(repository)
|
81
|
+
transaction.begin
|
82
|
+
repository.adapter.push_transaction(transaction)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
after do
|
87
|
+
while @repository.adapter.current_transaction
|
88
|
+
@repository.adapter.pop_transaction.rollback
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
it_should_behave_like 'A public Resource'
|
93
|
+
it_should_behave_like 'A Resource supporting Strategic Eager Loading'
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#transaction' do
|
97
|
+
before :all do
|
98
|
+
class ::Author
|
99
|
+
include DataMapper::Resource
|
100
|
+
|
101
|
+
property :name, String, :key => true
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
supported_by :postgres, :mysql do
|
106
|
+
before do
|
107
|
+
@user_model.destroy!
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should support nested transactions' do
|
111
|
+
# can't assume dm-aggregates
|
112
|
+
begin
|
113
|
+
@user_model.all.length.should == 0
|
114
|
+
|
115
|
+
@user_model.transaction do # txn 1
|
116
|
+
@user_model.create(:name => 'jpr5')
|
117
|
+
|
118
|
+
@user_model.all.length.should == 1
|
119
|
+
|
120
|
+
begin
|
121
|
+
@user_model.transaction do # savepoint 1
|
122
|
+
@user_model.create(:name => 'dkubb')
|
123
|
+
@user_model.all.length.should == 2
|
124
|
+
|
125
|
+
raise
|
126
|
+
end
|
127
|
+
rescue => e
|
128
|
+
@user_model.all.length.should == 1
|
129
|
+
end
|
130
|
+
|
131
|
+
raise
|
132
|
+
end
|
133
|
+
rescue => e
|
134
|
+
@user_model.all.length.should == 0
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
supported_by :postgres, :mysql, :sqlite, :oracle, :sqlserver do
|
140
|
+
before do
|
141
|
+
@user_model.destroy!
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'should have access to resources presisted before the transaction' do
|
145
|
+
@user_model.create(:name => 'carllerche')
|
146
|
+
@user_model.transaction do
|
147
|
+
@user_model.first.name.should == 'carllerche'
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should have access to resources persisted in the transaction' do
|
152
|
+
@user_model.transaction do
|
153
|
+
@user_model.create(:name => 'carllerche')
|
154
|
+
@user_model.first.name.should == 'carllerche'
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'should not mark saved resources as new records' do
|
159
|
+
@user_model.transaction do
|
160
|
+
@user_model.create(:name => 'carllerche').should_not be_new
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should rollback when an error is raised in a transaction' do
|
165
|
+
@user_model.all.size.should == 0
|
166
|
+
lambda {
|
167
|
+
@user_model.transaction do
|
168
|
+
@user_model.create(:name => 'carllerche')
|
169
|
+
raise 'I love coffee'
|
170
|
+
end
|
171
|
+
}.should raise_error('I love coffee')
|
172
|
+
@user_model.all.size.should == 0
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'should close the transaction if return is called within the closure' do
|
176
|
+
@txn = nil
|
177
|
+
|
178
|
+
def doit
|
179
|
+
@user_model.transaction do |transaction|
|
180
|
+
@txn = transaction
|
181
|
+
return
|
182
|
+
end
|
183
|
+
end
|
184
|
+
doit
|
185
|
+
|
186
|
+
@txn.instance_variable_get(:@state).should == :commit
|
187
|
+
@txn = nil
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'should return the last statement in the transaction block' do
|
191
|
+
@user_model.transaction { 1 }.should == 1
|
192
|
+
end
|
193
|
+
|
194
|
+
with_alternate_adapter do
|
195
|
+
before :all do
|
196
|
+
class ::Article
|
197
|
+
include DataMapper::Resource
|
198
|
+
|
199
|
+
def self.default_repository_name
|
200
|
+
:alternate
|
201
|
+
end
|
202
|
+
|
203
|
+
property :title, String, :key => true
|
204
|
+
end
|
205
|
+
|
206
|
+
DataMapper.auto_migrate!(:alternate)
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'should work with other repositories' do
|
210
|
+
expect {
|
211
|
+
DataMapper.repository.transaction.commit do
|
212
|
+
Author.create(:name => 'Dan Kubb')
|
213
|
+
|
214
|
+
# save a resource to another repository
|
215
|
+
Article.create(:title => 'DataMapper Rocks!')
|
216
|
+
end
|
217
|
+
}.should_not raise_error
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
data/spec/rcov.opts
ADDED
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'dm-transactions'
|
2
|
+
|
3
|
+
require 'dm-core/spec/setup'
|
4
|
+
require 'dm-core/spec/lib/spec_helper'
|
5
|
+
require 'dm-core/spec/lib/pending_helpers'
|
6
|
+
require 'dm-core/spec/lib/adapter_helpers'
|
7
|
+
require 'dm-core/spec/lib/counter_adapter'
|
8
|
+
require 'dm-core/spec/shared/resource_spec'
|
9
|
+
require 'dm-core/spec/shared/sel_spec'
|
10
|
+
|
11
|
+
Spec::Runner.configure do |config|
|
12
|
+
|
13
|
+
config.extend(DataMapper::Spec::Adapters::Helpers)
|
14
|
+
config.include(DataMapper::Spec::PendingHelpers)
|
15
|
+
|
16
|
+
config.after :all do
|
17
|
+
DataMapper::Spec.cleanup_models
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/tasks/spec.rake
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
spec_defaults = lambda do |spec|
|
2
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
3
|
+
spec.libs << 'lib' << 'spec'
|
4
|
+
spec.spec_opts << '--options' << 'spec/spec.opts'
|
5
|
+
end
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'spec/rake/spectask'
|
9
|
+
|
10
|
+
Spec::Rake::SpecTask.new(:spec, &spec_defaults)
|
11
|
+
rescue LoadError
|
12
|
+
task :spec do
|
13
|
+
abort 'rspec is not available. In order to run spec, you must: gem install rspec'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
begin
|
18
|
+
require 'rcov'
|
19
|
+
require 'spec/rake/verify_rcov'
|
20
|
+
|
21
|
+
Spec::Rake::SpecTask.new(:rcov) do |rcov|
|
22
|
+
spec_defaults.call(rcov)
|
23
|
+
rcov.rcov = true
|
24
|
+
rcov.rcov_opts = File.read('spec/rcov.opts').split(/\s+/)
|
25
|
+
end
|
26
|
+
|
27
|
+
RCov::VerifyTask.new(:verify_rcov => :rcov) do |rcov|
|
28
|
+
rcov.threshold = 100
|
29
|
+
end
|
30
|
+
rescue LoadError
|
31
|
+
%w[ rcov verify_rcov ].each do |name|
|
32
|
+
task name do
|
33
|
+
abort "rcov is not available. In order to run #{name}, you must: gem install rcov"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
task :default => :spec
|
data/tasks/yard.rake
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
begin
|
2
|
+
require 'pathname'
|
3
|
+
require 'yardstick/rake/measurement'
|
4
|
+
require 'yardstick/rake/verify'
|
5
|
+
|
6
|
+
# yardstick_measure task
|
7
|
+
Yardstick::Rake::Measurement.new
|
8
|
+
|
9
|
+
# verify_measurements task
|
10
|
+
Yardstick::Rake::Verify.new do |verify|
|
11
|
+
verify.threshold = 100
|
12
|
+
end
|
13
|
+
rescue LoadError
|
14
|
+
%w[ yardstick_measure verify_measurements ].each do |name|
|
15
|
+
task name.to_s do
|
16
|
+
abort "Yardstick is not available. In order to run #{name}, you must: gem install yardstick"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ardm-transactions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Martin Emde
|
8
|
+
- Dirkjan Bussink (dbussink)
|
9
|
+
- Dan Kubb (dkubb)
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2015-01-29 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: ardm-core
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "~>"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.2'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '1.2'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: rake
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0.9'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0.9'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: rspec
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '1.3'
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - "~>"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '1.3'
|
57
|
+
description: Makes transaction support available for adapters that support them
|
58
|
+
email:
|
59
|
+
- me@martinemde.com
|
60
|
+
- gamsnjaga@gmail.com
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files:
|
64
|
+
- LICENSE
|
65
|
+
- README.rdoc
|
66
|
+
files:
|
67
|
+
- ".document"
|
68
|
+
- ".gitignore"
|
69
|
+
- ".travis.yml"
|
70
|
+
- Gemfile
|
71
|
+
- LICENSE
|
72
|
+
- README.rdoc
|
73
|
+
- Rakefile
|
74
|
+
- ardm-transactions.gemspec
|
75
|
+
- lib/ardm-transactions.rb
|
76
|
+
- lib/dm-transactions.rb
|
77
|
+
- lib/dm-transactions/adapters/dm-do-adapter.rb
|
78
|
+
- lib/dm-transactions/adapters/dm-mysql-adapter.rb
|
79
|
+
- lib/dm-transactions/adapters/dm-oracle-adapter.rb
|
80
|
+
- lib/dm-transactions/adapters/dm-postgres-adapter.rb
|
81
|
+
- lib/dm-transactions/adapters/dm-sqlite-adapter.rb
|
82
|
+
- lib/dm-transactions/adapters/dm-sqlserver-adapter.rb
|
83
|
+
- lib/dm-transactions/version.rb
|
84
|
+
- spec/isolated/require_after_setup_spec.rb
|
85
|
+
- spec/isolated/require_before_setup_spec.rb
|
86
|
+
- spec/isolated/require_spec.rb
|
87
|
+
- spec/public/dm-transactions_spec.rb
|
88
|
+
- spec/rcov.opts
|
89
|
+
- spec/spec.opts
|
90
|
+
- spec/spec_helper.rb
|
91
|
+
- tasks/spec.rake
|
92
|
+
- tasks/yard.rake
|
93
|
+
- tasks/yardstick.rake
|
94
|
+
homepage: https://github.com/ar-dm/ardm-transactions
|
95
|
+
licenses:
|
96
|
+
- MIT
|
97
|
+
metadata: {}
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
requirements: []
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 2.2.2
|
115
|
+
signing_key:
|
116
|
+
specification_version: 4
|
117
|
+
summary: Ardm fork of dm-transactions
|
118
|
+
test_files: []
|
119
|
+
has_rdoc:
|