transaction-simple 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog +13 -2
- data/Install +5 -1
- data/Rakefile +11 -17
- data/Readme +186 -103
- data/lib/transaction/simple.rb +295 -193
- data/lib/transaction/simple/group.rb +133 -0
- data/lib/transaction/simple/threadsafe.rb +52 -0
- data/lib/transaction/simple/threadsafe/group.rb +23 -0
- data/tests/{tests.rb → tc_transaction_simple.rb} +6 -131
- data/tests/tc_transaction_simple_group.rb +44 -0
- data/tests/tc_transaction_simple_threadsafe.rb +135 -0
- data/tests/testall.rb +20 -0
- metadata +24 -13
- data/ChangeLog +0 -20
- data/README +0 -110
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'transaction/simple'
|
2
|
+
|
3
|
+
# A transaction group is an object wrapper that manages a group of objects
|
4
|
+
# as if they were a single object for the purpose of transaction
|
5
|
+
# management. All transactions for this group of objects should be
|
6
|
+
# performed against the transaction group object, not against individual
|
7
|
+
# objects in the group.
|
8
|
+
#
|
9
|
+
# == Transaction Group Usage
|
10
|
+
# require 'transaction/simple/group'
|
11
|
+
#
|
12
|
+
# x = "Hello, you."
|
13
|
+
# y = "And you, too."
|
14
|
+
#
|
15
|
+
# g = Transaction::Simple::Group.new(x, y)
|
16
|
+
# g.start_transaction(:first) # -> [ x, y ]
|
17
|
+
# g.transaction_open?(:first) # -> true
|
18
|
+
# x.transaction_open?(:first) # -> true
|
19
|
+
# y.transaction_open?(:first) # -> true
|
20
|
+
#
|
21
|
+
# x.gsub!(/you/, "world") # -> "Hello, world."
|
22
|
+
# y.gsub!(/you/, "me") # -> "And me, too."
|
23
|
+
#
|
24
|
+
# g.start_transaction(:second) # -> [ x, y ]
|
25
|
+
# x.gsub!(/world/, "HAL") # -> "Hello, HAL."
|
26
|
+
# y.gsub!(/me/, "Dave") # -> "And Dave, too."
|
27
|
+
# g.rewind_transaction(:second) # -> [ x, y ]
|
28
|
+
# x # -> "Hello, world."
|
29
|
+
# y # -> "And me, too."
|
30
|
+
#
|
31
|
+
# x.gsub!(/world/, "HAL") # -> "Hello, HAL."
|
32
|
+
# y.gsub!(/me/, "Dave") # -> "And Dave, too."
|
33
|
+
#
|
34
|
+
# g.commit_transaction(:second) # -> [ x, y ]
|
35
|
+
# x # -> "Hello, HAL."
|
36
|
+
# y # -> "And Dave, too."
|
37
|
+
#
|
38
|
+
# g.abort_transaction(:first) # -> [ x, y ]
|
39
|
+
# x = -> "Hello, you."
|
40
|
+
# y = -> "And you, too."
|
41
|
+
class Transaction::Simple::Group
|
42
|
+
# Creates a transaction group for the provided objects. If a block is
|
43
|
+
# provided, the transaction group object is yielded to the block; when
|
44
|
+
# the block is finished, the transaction group object will be cleared
|
45
|
+
# with #clear.
|
46
|
+
def initialize(*objects)
|
47
|
+
@objects = objects || []
|
48
|
+
@objects.freeze
|
49
|
+
@objects.each { |obj| obj.extend(Transaction::Simple) }
|
50
|
+
|
51
|
+
if block_given?
|
52
|
+
begin
|
53
|
+
yield self
|
54
|
+
ensure
|
55
|
+
self.clear
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the objects that are covered by this transaction group.
|
61
|
+
attr_reader :objects
|
62
|
+
|
63
|
+
# Clears the object group. Removes references to the objects so that
|
64
|
+
# they can be garbage collected.
|
65
|
+
def clear
|
66
|
+
@objects = @objects.dup.clear
|
67
|
+
end
|
68
|
+
|
69
|
+
# Tests to see if all of the objects in the group have an open
|
70
|
+
# transaction. See Transaction::Simple#transaction_open? for more
|
71
|
+
# information.
|
72
|
+
def transaction_open?(name = nil)
|
73
|
+
@objects.inject(true) do |val, obj|
|
74
|
+
val = val and obj.transaction_open?(name)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns the current name of the transaction for the group.
|
79
|
+
# Transactions not explicitly named are named +nil+.
|
80
|
+
def transaction_name
|
81
|
+
@objects[0].transaction_name
|
82
|
+
end
|
83
|
+
|
84
|
+
# Starts a transaction for the group. Stores the current object state.
|
85
|
+
# If a transaction name is specified, the transaction will be named.
|
86
|
+
# Transaction names must be unique. Transaction names of +nil+ will be
|
87
|
+
# treated as unnamed transactions.
|
88
|
+
def start_transaction(name = nil)
|
89
|
+
@objects.each { |obj| obj.start_transaction(name) }
|
90
|
+
end
|
91
|
+
|
92
|
+
# Rewinds the transaction. If +name+ is specified, then the intervening
|
93
|
+
# transactions will be aborted and the named transaction will be
|
94
|
+
# rewound. Otherwise, only the current transaction is rewound.
|
95
|
+
def rewind_transaction(name = nil)
|
96
|
+
@objects.each { |obj| obj.rewind_transaction(name) }
|
97
|
+
end
|
98
|
+
|
99
|
+
# Aborts the transaction. Resets the object state to what it was before
|
100
|
+
# the transaction was started and closes the transaction. If +name+ is
|
101
|
+
# specified, then the intervening transactions and the named transaction
|
102
|
+
# will be aborted. Otherwise, only the current transaction is aborted.
|
103
|
+
#
|
104
|
+
# If the current or named transaction has been started by a block
|
105
|
+
# (Transaction::Simple.start), then the execution of the block will be
|
106
|
+
# halted with +break+ +self+.
|
107
|
+
def abort_transaction(name = nil)
|
108
|
+
@objects.each { |obj| obj.abort_transaction(name) }
|
109
|
+
end
|
110
|
+
|
111
|
+
# If +name+ is +nil+ (default), the current transaction level is closed
|
112
|
+
# out and the changes are committed.
|
113
|
+
#
|
114
|
+
# If +name+ is specified and +name+ is in the list of named
|
115
|
+
# transactions, then all transactions are closed and committed until the
|
116
|
+
# named transaction is reached.
|
117
|
+
def commit_transaction(name = nil)
|
118
|
+
@objects.each { |obj| obj.commit_transaction(name) }
|
119
|
+
end
|
120
|
+
|
121
|
+
# Alternative method for calling the transaction methods. An optional
|
122
|
+
# name can be specified for named transaction support.
|
123
|
+
#
|
124
|
+
# #transaction(:start):: #start_transaction
|
125
|
+
# #transaction(:rewind):: #rewind_transaction
|
126
|
+
# #transaction(:abort):: #abort_transaction
|
127
|
+
# #transaction(:commit):: #commit_transaction
|
128
|
+
# #transaction(:name):: #transaction_name
|
129
|
+
# #transaction:: #transaction_open?
|
130
|
+
def transaction(action = nil, name = nil)
|
131
|
+
@objects.each { |obj| obj.transaction(action, name) }
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'transaction/simple'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
class Transaction::TransactionThreadError < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
# = Transaction::Simple::ThreadSafe
|
8
|
+
# Thread-safe simple object transaction support for Ruby.
|
9
|
+
# Transaction::Simple::ThreadSafe is used in the same way as
|
10
|
+
# Transaction::Simple. Transaction::Simple::ThreadSafe uses a Mutex object
|
11
|
+
# to ensure atomicity at the cost of performance in threaded applications.
|
12
|
+
#
|
13
|
+
# Transaction::Simple::ThreadSafe will not wait to obtain a lock; if the
|
14
|
+
# lock cannot be obtained immediately, a
|
15
|
+
# Transaction::TransactionThreadError will be raised.
|
16
|
+
#
|
17
|
+
# Thanks to Mauricio Fern�ndez for help with getting this part working.
|
18
|
+
#
|
19
|
+
# Threadsafe transactions can be used in any place that normal
|
20
|
+
# transactions would. The main difference would be in setup:
|
21
|
+
#
|
22
|
+
# require 'transaction/simple/threadsafe'
|
23
|
+
#
|
24
|
+
# x = "Hello, you."
|
25
|
+
# x.extend(Transaction::Simple::ThreadSafe) # Threadsafe
|
26
|
+
#
|
27
|
+
# y = "Hello, you."
|
28
|
+
# y.extend(Transaction::Simple) # Not threadsafe
|
29
|
+
module Transaction::Simple::ThreadSafe
|
30
|
+
include Transaction::Simple
|
31
|
+
|
32
|
+
SKIP_TRANSACTION_VARS = Transaction::Simple::SKIP_TRANSACTION_VARS.dup #:nodoc:
|
33
|
+
SKIP_TRANSACTION_VARS << "@__transaction_mutex__"
|
34
|
+
|
35
|
+
Transaction::Simple.instance_methods(false) do |meth|
|
36
|
+
next if meth == "transaction"
|
37
|
+
arg = "(name = nil)" unless meth == "transaction_name"
|
38
|
+
module_eval <<-EOS
|
39
|
+
def #{meth}#{arg}
|
40
|
+
if (@__transaction_mutex__ ||= Mutex.new).try_lock
|
41
|
+
result = super
|
42
|
+
@__transaction_mutex__.unlock
|
43
|
+
return result
|
44
|
+
else
|
45
|
+
raise TransactionThreadError, Messages[:cannot_obtain_transaction_lock] % meth
|
46
|
+
end
|
47
|
+
ensure
|
48
|
+
@__transaction_mutex__.unlock
|
49
|
+
end
|
50
|
+
EOS
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'transaction/simple/threadsafe'
|
2
|
+
|
3
|
+
# A transaction group is an object wrapper that manages a group of objects
|
4
|
+
# as if they were a single object for the purpose of transaction
|
5
|
+
# management. All transactions for this group of objects should be
|
6
|
+
# performed against the transaction group object, not against individual
|
7
|
+
# objects in the group. This is the threadsafe version of a transaction
|
8
|
+
# group.
|
9
|
+
class Transaction::Simple::ThreadSafe::Group < Transaction::Simple::Group
|
10
|
+
def initialize(*objects)
|
11
|
+
@objects = objects || []
|
12
|
+
@objects.freeze
|
13
|
+
@objects.each { |obj| obj.extend(Transaction::Simple::ThreadSafe) }
|
14
|
+
|
15
|
+
if block_given?
|
16
|
+
begin
|
17
|
+
yield self
|
18
|
+
ensure
|
19
|
+
self.clear
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -120,7 +120,6 @@ class Test__Transaction_Simple < Test::Unit::TestCase #:nodoc:
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def test_block
|
123
|
-
@value = VALUE.dup
|
124
123
|
Transaction::Simple.start(@value) do |tv|
|
125
124
|
assert_equal(true, tv.transaction_open?)
|
126
125
|
assert_nothing_raised { tv.gsub!(/men/, 'women') }
|
@@ -144,7 +143,6 @@ class Test__Transaction_Simple < Test::Unit::TestCase #:nodoc:
|
|
144
143
|
end
|
145
144
|
|
146
145
|
def test_named_block
|
147
|
-
@value = VALUE.dup
|
148
146
|
Transaction::Simple.start_named(:first, @value) do |tv|
|
149
147
|
assert_equal(true, tv.transaction_open?)
|
150
148
|
assert_equal(true, tv.transaction_open?(:first))
|
@@ -233,7 +231,6 @@ class Test__Transaction_Simple < Test::Unit::TestCase #:nodoc:
|
|
233
231
|
end
|
234
232
|
|
235
233
|
def test_multilevel_block
|
236
|
-
@value = VALUE.dup
|
237
234
|
Transaction::Simple.start_named(:outer, @value) do |tv0|
|
238
235
|
assert_equal(1, tv0.instance_variable_get(:@__transaction_level__))
|
239
236
|
assert_equal(true, tv0.transaction_open?(:outer))
|
@@ -267,136 +264,14 @@ class Test__Transaction_Simple < Test::Unit::TestCase #:nodoc:
|
|
267
264
|
assert_nothing_raised { @value.abort_transaction }
|
268
265
|
assert_equal(@orig, @value)
|
269
266
|
end
|
270
|
-
end
|
271
267
|
|
272
|
-
|
273
|
-
VALUE = "Now is the time for all good men to come to the aid of their country."
|
274
|
-
|
275
|
-
def setup
|
268
|
+
def test_instance_var
|
276
269
|
@value = VALUE.dup
|
277
|
-
@value.extend(Transaction::Simple
|
278
|
-
|
279
|
-
|
280
|
-
def test_extended
|
281
|
-
assert_respond_to(@value, :start_transaction)
|
282
|
-
end
|
283
|
-
|
284
|
-
def test_started
|
285
|
-
assert_equal(false, @value.transaction_open?)
|
286
|
-
assert_nothing_raised { @value.start_transaction }
|
287
|
-
assert_equal(true, @value.transaction_open?)
|
288
|
-
end
|
289
|
-
|
290
|
-
def test_rewind
|
291
|
-
assert_equal(false, @value.transaction_open?)
|
292
|
-
assert_raises(Transaction::TransactionError) { @value.rewind_transaction }
|
293
|
-
assert_nothing_raised { @value.start_transaction }
|
294
|
-
assert_equal(true, @value.transaction_open?)
|
295
|
-
assert_nothing_raised { @value.gsub!(/men/, 'women') }
|
296
|
-
assert_not_equal(VALUE, @value)
|
297
|
-
assert_nothing_raised { @value.rewind_transaction }
|
298
|
-
assert_equal(true, @value.transaction_open?)
|
299
|
-
assert_equal(VALUE, @value)
|
300
|
-
end
|
301
|
-
|
302
|
-
def test_abort
|
303
|
-
assert_equal(false, @value.transaction_open?)
|
304
|
-
assert_raises(Transaction::TransactionError) { @value.abort_transaction }
|
305
|
-
assert_nothing_raised { @value.start_transaction }
|
306
|
-
assert_equal(true, @value.transaction_open?)
|
307
|
-
assert_nothing_raised { @value.gsub!(/men/, 'women') }
|
308
|
-
assert_not_equal(VALUE, @value)
|
309
|
-
assert_nothing_raised { @value.abort_transaction }
|
310
|
-
assert_equal(false, @value.transaction_open?)
|
311
|
-
assert_equal(VALUE, @value)
|
312
|
-
end
|
313
|
-
|
314
|
-
def test_commit
|
315
|
-
assert_equal(false, @value.transaction_open?)
|
316
|
-
assert_raises(Transaction::TransactionError) { @value.commit_transaction }
|
317
|
-
assert_nothing_raised { @value.start_transaction }
|
318
|
-
assert_equal(true, @value.transaction_open?)
|
319
|
-
assert_nothing_raised { @value.gsub!(/men/, 'women') }
|
320
|
-
assert_not_equal(VALUE, @value)
|
321
|
-
assert_equal(true, @value.transaction_open?)
|
322
|
-
assert_nothing_raised { @value.commit_transaction }
|
323
|
-
assert_equal(false, @value.transaction_open?)
|
324
|
-
assert_not_equal(VALUE, @value)
|
325
|
-
end
|
326
|
-
|
327
|
-
def test_multilevel
|
328
|
-
assert_equal(false, @value.transaction_open?)
|
329
|
-
assert_nothing_raised { @value.start_transaction }
|
330
|
-
assert_equal(true, @value.transaction_open?)
|
331
|
-
assert_nothing_raised { @value.gsub!(/men/, 'women') }
|
332
|
-
assert_equal(VALUE.gsub(/men/, 'women'), @value)
|
333
|
-
assert_equal(true, @value.transaction_open?)
|
334
|
-
assert_nothing_raised { @value.start_transaction }
|
335
|
-
assert_nothing_raised { @value.gsub!(/country/, 'nation-state') }
|
336
|
-
assert_nothing_raised { @value.commit_transaction }
|
337
|
-
assert_equal(VALUE.gsub(/men/, 'women').gsub(/country/, 'nation-state'), @value)
|
338
|
-
assert_equal(true, @value.transaction_open?)
|
339
|
-
assert_nothing_raised { @value.abort_transaction }
|
340
|
-
assert_equal(VALUE, @value)
|
341
|
-
end
|
342
|
-
|
343
|
-
def test_multilevel_named
|
344
|
-
assert_equal(false, @value.transaction_open?)
|
345
|
-
assert_raises(Transaction::TransactionError) { @value.transaction_name }
|
346
|
-
assert_nothing_raised { @value.start_transaction(:first) } # 1
|
347
|
-
assert_raises(Transaction::TransactionError) { @value.start_transaction(:first) }
|
348
|
-
assert_equal(true, @value.transaction_open?)
|
349
|
-
assert_equal(true, @value.transaction_open?(:first))
|
350
|
-
assert_equal(:first, @value.transaction_name)
|
351
|
-
assert_nothing_raised { @value.start_transaction } # 2
|
352
|
-
assert_not_equal(:first, @value.transaction_name)
|
353
|
-
assert_equal(nil, @value.transaction_name)
|
354
|
-
assert_raises(Transaction::TransactionError) { @value.abort_transaction(:second) }
|
355
|
-
assert_nothing_raised { @value.abort_transaction(:first) }
|
356
|
-
assert_equal(false, @value.transaction_open?)
|
357
|
-
assert_nothing_raised do
|
358
|
-
@value.start_transaction(:first)
|
359
|
-
@value.gsub!(/men/, 'women')
|
360
|
-
@value.start_transaction(:second)
|
361
|
-
@value.gsub!(/women/, 'people')
|
362
|
-
@value.start_transaction
|
363
|
-
@value.gsub!(/people/, 'sentients')
|
364
|
-
end
|
365
|
-
assert_nothing_raised { @value.abort_transaction(:second) }
|
366
|
-
assert_equal(true, @value.transaction_open?(:first))
|
367
|
-
assert_equal(VALUE.gsub(/men/, 'women'), @value)
|
368
|
-
assert_nothing_raised do
|
369
|
-
@value.start_transaction(:second)
|
370
|
-
@value.gsub!(/women/, 'people')
|
371
|
-
@value.start_transaction
|
372
|
-
@value.gsub!(/people/, 'sentients')
|
373
|
-
end
|
374
|
-
assert_raises(Transaction::TransactionError) { @value.rewind_transaction(:foo) }
|
375
|
-
assert_nothing_raised { @value.rewind_transaction(:second) }
|
376
|
-
assert_equal(VALUE.gsub(/men/, 'women'), @value)
|
377
|
-
assert_nothing_raised do
|
378
|
-
@value.gsub!(/women/, 'people')
|
379
|
-
@value.start_transaction
|
380
|
-
@value.gsub!(/people/, 'sentients')
|
381
|
-
end
|
382
|
-
assert_raises(Transaction::TransactionError) { @value.commit_transaction(:foo) }
|
383
|
-
assert_nothing_raised { @value.commit_transaction(:first) }
|
384
|
-
assert_equal(VALUE.gsub(/men/, 'sentients'), @value)
|
385
|
-
assert_equal(false, @value.transaction_open?)
|
386
|
-
end
|
387
|
-
|
388
|
-
def test_array
|
389
|
-
assert_nothing_raised do
|
390
|
-
@orig = ["first", "second", "third"]
|
391
|
-
@value = ["first", "second", "third"]
|
392
|
-
@value.extend(Transaction::Simple::ThreadSafe)
|
393
|
-
end
|
394
|
-
assert_equal(@orig, @value)
|
395
|
-
assert_nothing_raised { @value.start_transaction }
|
270
|
+
@value.extend(Transaction::Simple)
|
271
|
+
@value.start_transaction
|
396
272
|
assert_equal(true, @value.transaction_open?)
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
assert_equal(@orig, @value)
|
273
|
+
@value.instance_variable_set("@foo", "bar")
|
274
|
+
@value.rewind_transaction
|
275
|
+
assert_nil(@value.instance_variable_get("@foo"))
|
401
276
|
end
|
402
277
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib") if __FILE__ == $0
|
2
|
+
|
3
|
+
require 'transaction/simple/group'
|
4
|
+
require 'test/unit'
|
5
|
+
class Test__Transaction_Simple_Group < Test::Unit::TestCase #:nodoc:
|
6
|
+
VALUE1 = "Hello, you."
|
7
|
+
VALUE2 = "And you, too."
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@x = VALUE1.dup
|
11
|
+
@y = VALUE2.dup
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_group
|
15
|
+
group = Transaction::Simple::Group.new(@x, @y)
|
16
|
+
|
17
|
+
assert_nothing_raised { group.start_transaction(:first) }
|
18
|
+
assert_equal(true, group.transaction_open?(:first))
|
19
|
+
assert_equal(true, @x.transaction_open?(:first))
|
20
|
+
assert_equal(true, @y.transaction_open?(:first))
|
21
|
+
|
22
|
+
assert_equal("Hello, world.", @x.gsub!(/you/, "world"))
|
23
|
+
assert_equal("And me, too.", @y.gsub!(/you/, "me"))
|
24
|
+
|
25
|
+
assert_nothing_raised { group.start_transaction(:second) }
|
26
|
+
assert_equal("Hello, HAL.", @x.gsub!(/world/, "HAL"))
|
27
|
+
assert_equal("And Dave, too.", @y.gsub!(/me/, "Dave"))
|
28
|
+
|
29
|
+
assert_nothing_raised { group.rewind_transaction(:second) }
|
30
|
+
assert_equal("Hello, world.", @x)
|
31
|
+
assert_equal("And me, too.", @y)
|
32
|
+
|
33
|
+
assert_equal("Hello, HAL.", @x.gsub!(/world/, "HAL"))
|
34
|
+
assert_equal("And Dave, too.", @y.gsub!(/me/, "Dave"))
|
35
|
+
|
36
|
+
assert_nothing_raised { group.commit_transaction(:second) }
|
37
|
+
assert_equal("Hello, HAL.", @x)
|
38
|
+
assert_equal("And Dave, too.", @y)
|
39
|
+
|
40
|
+
assert_nothing_raised { group.abort_transaction(:first) }
|
41
|
+
assert_equal("Hello, you.", @x)
|
42
|
+
assert_equal("And you, too.", @y)
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib") if __FILE__ == $0
|
2
|
+
|
3
|
+
require 'transaction/simple/threadsafe'
|
4
|
+
require 'test/unit'
|
5
|
+
class Test__Transaction_Simple_ThreadSafe < Test::Unit::TestCase #:nodoc:
|
6
|
+
VALUE = "Now is the time for all good men to come to the aid of their country."
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@value = VALUE.dup
|
10
|
+
@value.extend(Transaction::Simple::ThreadSafe)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_extended
|
14
|
+
assert_respond_to(@value, :start_transaction)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_started
|
18
|
+
assert_equal(false, @value.transaction_open?)
|
19
|
+
assert_nothing_raised { @value.start_transaction }
|
20
|
+
assert_equal(true, @value.transaction_open?)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_rewind
|
24
|
+
assert_equal(false, @value.transaction_open?)
|
25
|
+
assert_raises(Transaction::TransactionError) { @value.rewind_transaction }
|
26
|
+
assert_nothing_raised { @value.start_transaction }
|
27
|
+
assert_equal(true, @value.transaction_open?)
|
28
|
+
assert_nothing_raised { @value.gsub!(/men/, 'women') }
|
29
|
+
assert_not_equal(VALUE, @value)
|
30
|
+
assert_nothing_raised { @value.rewind_transaction }
|
31
|
+
assert_equal(true, @value.transaction_open?)
|
32
|
+
assert_equal(VALUE, @value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_abort
|
36
|
+
assert_equal(false, @value.transaction_open?)
|
37
|
+
assert_raises(Transaction::TransactionError) { @value.abort_transaction }
|
38
|
+
assert_nothing_raised { @value.start_transaction }
|
39
|
+
assert_equal(true, @value.transaction_open?)
|
40
|
+
assert_nothing_raised { @value.gsub!(/men/, 'women') }
|
41
|
+
assert_not_equal(VALUE, @value)
|
42
|
+
assert_nothing_raised { @value.abort_transaction }
|
43
|
+
assert_equal(false, @value.transaction_open?)
|
44
|
+
assert_equal(VALUE, @value)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_commit
|
48
|
+
assert_equal(false, @value.transaction_open?)
|
49
|
+
assert_raises(Transaction::TransactionError) { @value.commit_transaction }
|
50
|
+
assert_nothing_raised { @value.start_transaction }
|
51
|
+
assert_equal(true, @value.transaction_open?)
|
52
|
+
assert_nothing_raised { @value.gsub!(/men/, 'women') }
|
53
|
+
assert_not_equal(VALUE, @value)
|
54
|
+
assert_equal(true, @value.transaction_open?)
|
55
|
+
assert_nothing_raised { @value.commit_transaction }
|
56
|
+
assert_equal(false, @value.transaction_open?)
|
57
|
+
assert_not_equal(VALUE, @value)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_multilevel
|
61
|
+
assert_equal(false, @value.transaction_open?)
|
62
|
+
assert_nothing_raised { @value.start_transaction }
|
63
|
+
assert_equal(true, @value.transaction_open?)
|
64
|
+
assert_nothing_raised { @value.gsub!(/men/, 'women') }
|
65
|
+
assert_equal(VALUE.gsub(/men/, 'women'), @value)
|
66
|
+
assert_equal(true, @value.transaction_open?)
|
67
|
+
assert_nothing_raised { @value.start_transaction }
|
68
|
+
assert_nothing_raised { @value.gsub!(/country/, 'nation-state') }
|
69
|
+
assert_nothing_raised { @value.commit_transaction }
|
70
|
+
assert_equal(VALUE.gsub(/men/, 'women').gsub(/country/, 'nation-state'), @value)
|
71
|
+
assert_equal(true, @value.transaction_open?)
|
72
|
+
assert_nothing_raised { @value.abort_transaction }
|
73
|
+
assert_equal(VALUE, @value)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_multilevel_named
|
77
|
+
assert_equal(false, @value.transaction_open?)
|
78
|
+
assert_raises(Transaction::TransactionError) { @value.transaction_name }
|
79
|
+
assert_nothing_raised { @value.start_transaction(:first) } # 1
|
80
|
+
assert_raises(Transaction::TransactionError) { @value.start_transaction(:first) }
|
81
|
+
assert_equal(true, @value.transaction_open?)
|
82
|
+
assert_equal(true, @value.transaction_open?(:first))
|
83
|
+
assert_equal(:first, @value.transaction_name)
|
84
|
+
assert_nothing_raised { @value.start_transaction } # 2
|
85
|
+
assert_not_equal(:first, @value.transaction_name)
|
86
|
+
assert_equal(nil, @value.transaction_name)
|
87
|
+
assert_raises(Transaction::TransactionError) { @value.abort_transaction(:second) }
|
88
|
+
assert_nothing_raised { @value.abort_transaction(:first) }
|
89
|
+
assert_equal(false, @value.transaction_open?)
|
90
|
+
assert_nothing_raised do
|
91
|
+
@value.start_transaction(:first)
|
92
|
+
@value.gsub!(/men/, 'women')
|
93
|
+
@value.start_transaction(:second)
|
94
|
+
@value.gsub!(/women/, 'people')
|
95
|
+
@value.start_transaction
|
96
|
+
@value.gsub!(/people/, 'sentients')
|
97
|
+
end
|
98
|
+
assert_nothing_raised { @value.abort_transaction(:second) }
|
99
|
+
assert_equal(true, @value.transaction_open?(:first))
|
100
|
+
assert_equal(VALUE.gsub(/men/, 'women'), @value)
|
101
|
+
assert_nothing_raised do
|
102
|
+
@value.start_transaction(:second)
|
103
|
+
@value.gsub!(/women/, 'people')
|
104
|
+
@value.start_transaction
|
105
|
+
@value.gsub!(/people/, 'sentients')
|
106
|
+
end
|
107
|
+
assert_raises(Transaction::TransactionError) { @value.rewind_transaction(:foo) }
|
108
|
+
assert_nothing_raised { @value.rewind_transaction(:second) }
|
109
|
+
assert_equal(VALUE.gsub(/men/, 'women'), @value)
|
110
|
+
assert_nothing_raised do
|
111
|
+
@value.gsub!(/women/, 'people')
|
112
|
+
@value.start_transaction
|
113
|
+
@value.gsub!(/people/, 'sentients')
|
114
|
+
end
|
115
|
+
assert_raises(Transaction::TransactionError) { @value.commit_transaction(:foo) }
|
116
|
+
assert_nothing_raised { @value.commit_transaction(:first) }
|
117
|
+
assert_equal(VALUE.gsub(/men/, 'sentients'), @value)
|
118
|
+
assert_equal(false, @value.transaction_open?)
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_array
|
122
|
+
assert_nothing_raised do
|
123
|
+
@orig = ["first", "second", "third"]
|
124
|
+
@value = ["first", "second", "third"]
|
125
|
+
@value.extend(Transaction::Simple::ThreadSafe)
|
126
|
+
end
|
127
|
+
assert_equal(@orig, @value)
|
128
|
+
assert_nothing_raised { @value.start_transaction }
|
129
|
+
assert_equal(true, @value.transaction_open?)
|
130
|
+
assert_nothing_raised { @value[1].gsub!(/second/, "fourth") }
|
131
|
+
assert_not_equal(@orig, @value)
|
132
|
+
assert_nothing_raised { @value.abort_transaction }
|
133
|
+
assert_equal(@orig, @value)
|
134
|
+
end
|
135
|
+
end
|