pdf-labels 1.0.0 → 1.0.1
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.
- data/History.txt +3 -0
- data/Manifest.txt +41 -64
- data/README.txt +4 -3
- data/lib/pdf_labels.rb +1 -4
- data/test/test_pdf_label_page.rb +6 -6
- data/vendor/transaction/simple.rb +390 -597
- data/vendor/transaction/simple/group.rb +13 -0
- data/vendor/transaction/simple/threadsafe.rb +18 -2
- data/vendor/transaction/simple/threadsafe/group.rb +13 -0
- data/vendor/{xml-mapping → xml}/LICENSE +0 -0
- data/vendor/{xml-mapping → xml}/README +0 -0
- data/vendor/{xml-mapping/lib/xml → xml}/mapping.rb +0 -0
- data/vendor/{xml-mapping/lib/xml → xml}/mapping/base.rb +0 -0
- data/vendor/{xml-mapping/lib/xml → xml}/mapping/standard_nodes.rb +0 -0
- data/vendor/{xml-mapping/lib/xml → xml}/mapping/version.rb +0 -0
- data/vendor/{xml-mapping/lib/xml → xml}/xxpath.rb +0 -0
- metadata +46 -71
- data/vendor/xml-mapping/ChangeLog +0 -128
- data/vendor/xml-mapping/README_XPATH +0 -175
- data/vendor/xml-mapping/Rakefile +0 -214
- data/vendor/xml-mapping/TODO.txt +0 -32
- data/vendor/xml-mapping/doc/xpath_impl_notes.txt +0 -119
- data/vendor/xml-mapping/examples/company.rb +0 -34
- data/vendor/xml-mapping/examples/company.xml +0 -26
- data/vendor/xml-mapping/examples/company_usage.intin.rb +0 -19
- data/vendor/xml-mapping/examples/company_usage.intout +0 -39
- data/vendor/xml-mapping/examples/order.rb +0 -61
- data/vendor/xml-mapping/examples/order.xml +0 -54
- data/vendor/xml-mapping/examples/order_signature_enhanced.rb +0 -7
- data/vendor/xml-mapping/examples/order_signature_enhanced.xml +0 -9
- data/vendor/xml-mapping/examples/order_signature_enhanced_usage.intin.rb +0 -12
- data/vendor/xml-mapping/examples/order_signature_enhanced_usage.intout +0 -16
- data/vendor/xml-mapping/examples/order_usage.intin.rb +0 -73
- data/vendor/xml-mapping/examples/order_usage.intout +0 -147
- data/vendor/xml-mapping/examples/time_augm.intin.rb +0 -19
- data/vendor/xml-mapping/examples/time_augm.intout +0 -23
- data/vendor/xml-mapping/examples/time_node.rb +0 -27
- data/vendor/xml-mapping/examples/xpath_create_new.intin.rb +0 -85
- data/vendor/xml-mapping/examples/xpath_create_new.intout +0 -181
- data/vendor/xml-mapping/examples/xpath_docvsroot.intin.rb +0 -30
- data/vendor/xml-mapping/examples/xpath_docvsroot.intout +0 -34
- data/vendor/xml-mapping/examples/xpath_ensure_created.intin.rb +0 -62
- data/vendor/xml-mapping/examples/xpath_ensure_created.intout +0 -114
- data/vendor/xml-mapping/examples/xpath_pathological.intin.rb +0 -42
- data/vendor/xml-mapping/examples/xpath_pathological.intout +0 -56
- data/vendor/xml-mapping/examples/xpath_usage.intin.rb +0 -51
- data/vendor/xml-mapping/examples/xpath_usage.intout +0 -57
- data/vendor/xml-mapping/install.rb +0 -40
- data/vendor/xml-mapping/test/all_tests.rb +0 -6
- data/vendor/xml-mapping/test/company.rb +0 -56
- data/vendor/xml-mapping/test/documents_folders.rb +0 -33
- data/vendor/xml-mapping/test/fixtures/bookmarks1.xml +0 -24
- data/vendor/xml-mapping/test/fixtures/company1.xml +0 -85
- data/vendor/xml-mapping/test/fixtures/documents_folders.xml +0 -71
- data/vendor/xml-mapping/test/fixtures/documents_folders2.xml +0 -30
- data/vendor/xml-mapping/test/multiple_mappings.rb +0 -80
- data/vendor/xml-mapping/test/tests_init.rb +0 -2
- data/vendor/xml-mapping/test/xml_mapping_adv_test.rb +0 -84
- data/vendor/xml-mapping/test/xml_mapping_test.rb +0 -201
- data/vendor/xml-mapping/test/xpath_test.rb +0 -273
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
History.txt
|
2
|
-
|
3
|
-
Manifest.txt
|
4
|
-
README.txt
|
5
|
-
Rakefile
|
2
|
+
lib
|
6
3
|
lib/alias.rb
|
7
4
|
lib/glabel_template.rb
|
8
5
|
lib/label.rb
|
@@ -12,6 +9,11 @@ lib/markup.rb
|
|
12
9
|
lib/pdf_label_page.rb
|
13
10
|
lib/pdf_labels.rb
|
14
11
|
lib/template.rb
|
12
|
+
LICENCE
|
13
|
+
Manifest.txt
|
14
|
+
Rakefile
|
15
|
+
README.txt
|
16
|
+
templates
|
15
17
|
templates/avery-iso-templates.xml
|
16
18
|
templates/avery-other-templates.xml
|
17
19
|
templates/avery-us-templates.xml
|
@@ -21,30 +23,39 @@ templates/misc-other-templates.xml
|
|
21
23
|
templates/misc-us-templates.xml
|
22
24
|
templates/paper-sizes.xml
|
23
25
|
templates/zweckform-iso-templates.xml
|
26
|
+
test
|
24
27
|
test/test_pdf_label_page.rb
|
25
|
-
vendor
|
28
|
+
vendor
|
29
|
+
vendor/color
|
26
30
|
vendor/color/cmyk.rb
|
27
31
|
vendor/color/css.rb
|
28
32
|
vendor/color/grayscale.rb
|
29
33
|
vendor/color/hsl.rb
|
30
|
-
vendor/color/palette
|
34
|
+
vendor/color/palette
|
31
35
|
vendor/color/palette/gimp.rb
|
32
36
|
vendor/color/palette/monocontrast.rb
|
37
|
+
vendor/color/palette.rb
|
38
|
+
vendor/color/rgb
|
39
|
+
vendor/color/rgb/metallic.rb
|
33
40
|
vendor/color/rgb-colors.rb
|
34
41
|
vendor/color/rgb.rb
|
35
|
-
vendor/color/rgb/metallic.rb
|
36
42
|
vendor/color/yiq.rb
|
37
|
-
vendor/
|
43
|
+
vendor/color.rb
|
44
|
+
vendor/pdf
|
45
|
+
vendor/pdf/charts
|
38
46
|
vendor/pdf/charts/stddev.rb
|
47
|
+
vendor/pdf/charts.rb
|
48
|
+
vendor/pdf/fonts
|
39
49
|
vendor/pdf/grid.rb
|
40
50
|
vendor/pdf/math.rb
|
41
51
|
vendor/pdf/pagenumbers.rb
|
42
52
|
vendor/pdf/quickref.rb
|
43
53
|
vendor/pdf/simpletable.rb
|
44
54
|
vendor/pdf/techbook.rb
|
45
|
-
vendor/pdf/writer
|
55
|
+
vendor/pdf/writer
|
46
56
|
vendor/pdf/writer/arc4.rb
|
47
57
|
vendor/pdf/writer/fontmetrics.rb
|
58
|
+
vendor/pdf/writer/fonts
|
48
59
|
vendor/pdf/writer/fonts/Courier-Bold.afm
|
49
60
|
vendor/pdf/writer/fonts/Courier-BoldOblique.afm
|
50
61
|
vendor/pdf/writer/fonts/Courier-Oblique.afm
|
@@ -59,11 +70,13 @@ vendor/pdf/writer/fonts/Times-BoldItalic.afm
|
|
59
70
|
vendor/pdf/writer/fonts/Times-Italic.afm
|
60
71
|
vendor/pdf/writer/fonts/Times-Roman.afm
|
61
72
|
vendor/pdf/writer/fonts/ZapfDingbats.afm
|
62
|
-
vendor/pdf/writer/graphics
|
73
|
+
vendor/pdf/writer/graphics
|
63
74
|
vendor/pdf/writer/graphics/imageinfo.rb
|
64
|
-
vendor/pdf/writer/
|
75
|
+
vendor/pdf/writer/graphics.rb
|
76
|
+
vendor/pdf/writer/lang
|
65
77
|
vendor/pdf/writer/lang/en.rb
|
66
|
-
vendor/pdf/writer/
|
78
|
+
vendor/pdf/writer/lang.rb
|
79
|
+
vendor/pdf/writer/object
|
67
80
|
vendor/pdf/writer/object/action.rb
|
68
81
|
vendor/pdf/writer/object/annotation.rb
|
69
82
|
vendor/pdf/writer/object/catalog.rb
|
@@ -81,61 +94,25 @@ vendor/pdf/writer/object/page.rb
|
|
81
94
|
vendor/pdf/writer/object/pages.rb
|
82
95
|
vendor/pdf/writer/object/procset.rb
|
83
96
|
vendor/pdf/writer/object/viewerpreferences.rb
|
97
|
+
vendor/pdf/writer/object.rb
|
84
98
|
vendor/pdf/writer/ohash.rb
|
85
99
|
vendor/pdf/writer/oreader.rb
|
86
100
|
vendor/pdf/writer/state.rb
|
87
101
|
vendor/pdf/writer/strokestyle.rb
|
88
|
-
vendor/
|
102
|
+
vendor/pdf/writer.rb
|
103
|
+
vendor/transaction
|
104
|
+
vendor/transaction/simple
|
89
105
|
vendor/transaction/simple/group.rb
|
90
|
-
vendor/transaction/simple/threadsafe
|
106
|
+
vendor/transaction/simple/threadsafe
|
91
107
|
vendor/transaction/simple/threadsafe/group.rb
|
92
|
-
vendor/
|
93
|
-
vendor/
|
94
|
-
vendor/xml
|
95
|
-
vendor/xml
|
96
|
-
vendor/xml
|
97
|
-
vendor/xml
|
98
|
-
vendor/xml
|
99
|
-
vendor/xml
|
100
|
-
vendor/xml
|
101
|
-
vendor/xml
|
102
|
-
vendor/xml
|
103
|
-
vendor/xml-mapping/examples/order.rb
|
104
|
-
vendor/xml-mapping/examples/order.xml
|
105
|
-
vendor/xml-mapping/examples/order_signature_enhanced.rb
|
106
|
-
vendor/xml-mapping/examples/order_signature_enhanced.xml
|
107
|
-
vendor/xml-mapping/examples/order_signature_enhanced_usage.intin.rb
|
108
|
-
vendor/xml-mapping/examples/order_signature_enhanced_usage.intout
|
109
|
-
vendor/xml-mapping/examples/order_usage.intin.rb
|
110
|
-
vendor/xml-mapping/examples/order_usage.intout
|
111
|
-
vendor/xml-mapping/examples/time_augm.intin.rb
|
112
|
-
vendor/xml-mapping/examples/time_augm.intout
|
113
|
-
vendor/xml-mapping/examples/time_node.rb
|
114
|
-
vendor/xml-mapping/examples/xpath_create_new.intin.rb
|
115
|
-
vendor/xml-mapping/examples/xpath_create_new.intout
|
116
|
-
vendor/xml-mapping/examples/xpath_docvsroot.intin.rb
|
117
|
-
vendor/xml-mapping/examples/xpath_docvsroot.intout
|
118
|
-
vendor/xml-mapping/examples/xpath_ensure_created.intin.rb
|
119
|
-
vendor/xml-mapping/examples/xpath_ensure_created.intout
|
120
|
-
vendor/xml-mapping/examples/xpath_pathological.intin.rb
|
121
|
-
vendor/xml-mapping/examples/xpath_pathological.intout
|
122
|
-
vendor/xml-mapping/examples/xpath_usage.intin.rb
|
123
|
-
vendor/xml-mapping/examples/xpath_usage.intout
|
124
|
-
vendor/xml-mapping/install.rb
|
125
|
-
vendor/xml-mapping/lib/xml/mapping.rb
|
126
|
-
vendor/xml-mapping/lib/xml/mapping/base.rb
|
127
|
-
vendor/xml-mapping/lib/xml/mapping/standard_nodes.rb
|
128
|
-
vendor/xml-mapping/lib/xml/mapping/version.rb
|
129
|
-
vendor/xml-mapping/lib/xml/xxpath.rb
|
130
|
-
vendor/xml-mapping/test/all_tests.rb
|
131
|
-
vendor/xml-mapping/test/company.rb
|
132
|
-
vendor/xml-mapping/test/documents_folders.rb
|
133
|
-
vendor/xml-mapping/test/fixtures/bookmarks1.xml
|
134
|
-
vendor/xml-mapping/test/fixtures/company1.xml
|
135
|
-
vendor/xml-mapping/test/fixtures/documents_folders.xml
|
136
|
-
vendor/xml-mapping/test/fixtures/documents_folders2.xml
|
137
|
-
vendor/xml-mapping/test/multiple_mappings.rb
|
138
|
-
vendor/xml-mapping/test/tests_init.rb
|
139
|
-
vendor/xml-mapping/test/xml_mapping_adv_test.rb
|
140
|
-
vendor/xml-mapping/test/xml_mapping_test.rb
|
141
|
-
vendor/xml-mapping/test/xpath_test.rb
|
108
|
+
vendor/transaction/simple/threadsafe.rb
|
109
|
+
vendor/transaction/simple.rb
|
110
|
+
vendor/xml
|
111
|
+
vendor/xml/LICENSE
|
112
|
+
vendor/xml/mapping
|
113
|
+
vendor/xml/mapping/base.rb
|
114
|
+
vendor/xml/mapping/standard_nodes.rb
|
115
|
+
vendor/xml/mapping/version.rb
|
116
|
+
vendor/xml/mapping.rb
|
117
|
+
vendor/xml/xxpath.rb
|
118
|
+
vendor/xml/README
|
data/README.txt
CHANGED
data/lib/pdf_labels.rb
CHANGED
data/test/test_pdf_label_page.rb
CHANGED
@@ -3,7 +3,7 @@ require 'test/unit'
|
|
3
3
|
require 'pdf_label_page'
|
4
4
|
|
5
5
|
class TestPDFLabelPage < Test::Unit::TestCase
|
6
|
-
|
6
|
+
ROOT = File.expand_path(File.dirname(__FILE__) + "/../")
|
7
7
|
def setup
|
8
8
|
end
|
9
9
|
|
@@ -35,13 +35,13 @@ class TestPDFLabelPage < Test::Unit::TestCase
|
|
35
35
|
#TODO other options are possible for pdf_options, we need to test those at some point
|
36
36
|
|
37
37
|
def test_PDFLabelPage_load_tempalte_set
|
38
|
-
PDFLabelPage.load_template_set(
|
38
|
+
PDFLabelPage.load_template_set("#{ROOT}/templates/avery-iso-templates.xml")
|
39
39
|
#Avery 7160 is found in avery-iso-templates
|
40
40
|
p = PDFLabelPage.new("Avery 7160")
|
41
41
|
assert p
|
42
42
|
assert_equal p.pdf.page_width, 595.28
|
43
43
|
assert_equal p.pdf.page_height, 841.89
|
44
|
-
PDFLabelPage.load_template_set(
|
44
|
+
PDFLabelPage.load_template_set("#{ROOT}/templates/avery-us-templates.xml")
|
45
45
|
end
|
46
46
|
|
47
47
|
def test_PDFLabelPage_all_template_names
|
@@ -71,7 +71,7 @@ class TestPDFLabelPage < Test::Unit::TestCase
|
|
71
71
|
p.add_label(:position => 8, :text => "This was added last and has a BIG font", :font_size => 18)
|
72
72
|
p.draw_boxes(false, true)
|
73
73
|
#TODO Anybody out there think of a better way to test this?
|
74
|
-
p.save_as("
|
74
|
+
p.save_as("#{ROOT}/test_add_label_output.pdf")
|
75
75
|
end
|
76
76
|
|
77
77
|
def test_add_many_labels
|
@@ -79,13 +79,13 @@ class TestPDFLabelPage < Test::Unit::TestCase
|
|
79
79
|
#without positoin, so start at 1
|
80
80
|
p.add_many_labels(:text => "Hello Five Times!", :count => 5)
|
81
81
|
p.add_many_labels(:text => "Hellow four more times, starting at 15", :count => 4, :position => 15)
|
82
|
-
p.save_as("
|
82
|
+
p.save_as("#{ROOT}/test_add_many_label_output.pdf")
|
83
83
|
end
|
84
84
|
|
85
85
|
def test_draw_boxes
|
86
86
|
p = PDFLabelPage.new("Avery 5366") # label is 2 x 10
|
87
87
|
p.draw_boxes
|
88
|
-
p.save_as("
|
88
|
+
p.save_as("#{ROOT}/test_draw_boxes_output.pdf")
|
89
89
|
end
|
90
90
|
|
91
91
|
end
|
@@ -1,693 +1,486 @@
|
|
1
1
|
# :title: Transaction::Simple -- Active Object Transaction Support for Ruby
|
2
|
-
# :main:
|
3
|
-
|
4
|
-
# == Licence
|
5
|
-
#
|
6
|
-
# Permission is hereby granted, free of charge, to any person obtaining a
|
7
|
-
# copy of this software and associated documentation files (the "Software"),
|
8
|
-
# to deal in the Software without restriction, including without limitation
|
9
|
-
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
10
|
-
# and/or sell copies of the Software, and to permit persons to whom the
|
11
|
-
# Software is furnished to do so, subject to the following conditions:
|
12
|
-
#
|
13
|
-
# The above copyright notice and this permission notice shall be included in
|
14
|
-
# all copies or substantial portions of the Software.
|
15
|
-
#
|
16
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19
|
-
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
-
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
22
|
-
# DEALINGS IN THE SOFTWARE.
|
2
|
+
# :main: Readme.txt
|
3
|
+
|
23
4
|
#--
|
24
5
|
# Transaction::Simple
|
25
|
-
#
|
26
|
-
#
|
6
|
+
# Simple object transaction support for Ruby
|
7
|
+
# http://rubyforge.org/projects/trans-simple/
|
8
|
+
# Version 1.4.0
|
9
|
+
#
|
10
|
+
# Licensed under a MIT-style licence. See Licence.txt in the main
|
11
|
+
# distribution for full licensing information.
|
27
12
|
#
|
28
|
-
# Copyright (c) 2003 -
|
13
|
+
# Copyright (c) 2003 - 2007 Austin Ziegler
|
29
14
|
#
|
30
|
-
# $Id: simple.rb
|
15
|
+
# $Id: simple.rb 50 2007-02-03 20:26:19Z austin $
|
31
16
|
#++
|
32
|
-
|
33
|
-
|
17
|
+
|
18
|
+
# The "Transaction" namespace can be used for additional transaction support
|
19
|
+
# objects and modules.
|
34
20
|
module Transaction
|
35
|
-
|
21
|
+
# A standard exception for transaction errors.
|
36
22
|
class TransactionError < StandardError; end
|
37
|
-
|
38
|
-
|
23
|
+
# The TransactionAborted exception is used to indicate when a transaction
|
24
|
+
# has been aborted in the block form.
|
39
25
|
class TransactionAborted < Exception; end
|
40
|
-
|
41
|
-
|
26
|
+
# The TransactionCommitted exception is used to indicate when a
|
27
|
+
# transaction has been committed in the block form.
|
42
28
|
class TransactionCommitted < Exception; end
|
43
29
|
|
44
30
|
te = "Transaction Error: %s"
|
45
31
|
|
46
|
-
Messages = {
|
47
|
-
:bad_debug_object =>
|
48
|
-
|
49
|
-
:
|
50
|
-
|
51
|
-
:
|
52
|
-
|
53
|
-
:
|
54
|
-
|
55
|
-
:
|
56
|
-
|
57
|
-
:
|
58
|
-
|
59
|
-
:
|
60
|
-
|
61
|
-
:cannot_abort_transaction_before_block =>
|
62
|
-
te % "cannot abort a transaction started before the execution block.",
|
63
|
-
:cannot_abort_named_transaction =>
|
64
|
-
te % "cannot abort nonexistant transaction %s.",
|
65
|
-
:cannot_commit_no_transaction =>
|
66
|
-
te % "cannot commit; there is no current transaction.",
|
67
|
-
:cannot_commit_transaction_before_block =>
|
68
|
-
te % "cannot commit a transaction started before the execution block.",
|
69
|
-
:cannot_commit_named_transaction =>
|
70
|
-
te % "cannot commit nonexistant transaction %s.",
|
71
|
-
:cannot_start_empty_block_transaction =>
|
72
|
-
te % "cannot start a block transaction with no objects.",
|
73
|
-
:cannot_obtain_transaction_lock =>
|
74
|
-
te % "cannot obtain transaction lock for #%s.",
|
32
|
+
Messages = { #:nodoc:
|
33
|
+
:bad_debug_object => te % "the transaction debug object must respond to #<<.",
|
34
|
+
:unique_names => te % "named transactions must be unique.",
|
35
|
+
:no_transaction_open => te % "no transaction open.",
|
36
|
+
:cannot_rewind_no_transaction => te % "cannot rewind; there is no current transaction.",
|
37
|
+
:cannot_rewind_named_transaction => te % "cannot rewind to transaction %s because it does not exist.",
|
38
|
+
:cannot_rewind_transaction_before_block => te % "cannot rewind a transaction started before the execution block.",
|
39
|
+
:cannot_abort_no_transaction => te % "cannot abort; there is no current transaction.",
|
40
|
+
:cannot_abort_transaction_before_block => te % "cannot abort a transaction started before the execution block.",
|
41
|
+
:cannot_abort_named_transaction => te % "cannot abort nonexistant transaction %s.",
|
42
|
+
:cannot_commit_no_transaction => te % "cannot commit; there is no current transaction.",
|
43
|
+
:cannot_commit_transaction_before_block => te % "cannot commit a transaction started before the execution block.",
|
44
|
+
:cannot_commit_named_transaction => te % "cannot commit nonexistant transaction %s.",
|
45
|
+
:cannot_start_empty_block_transaction => te % "cannot start a block transaction with no objects.",
|
46
|
+
:cannot_obtain_transaction_lock => te % "cannot obtain transaction lock for #%s.",
|
75
47
|
}
|
48
|
+
end
|
49
|
+
|
50
|
+
# = Transaction::Simple for Ruby
|
51
|
+
# Simple object transaction support for Ruby
|
52
|
+
module Transaction::Simple
|
53
|
+
TRANSACTION_SIMPLE_VERSION = '1.4.0'
|
76
54
|
|
77
|
-
|
78
|
-
# Simple object
|
79
|
-
#
|
80
|
-
|
81
|
-
# Transaction::Simple provides a generic way to add active transaction
|
82
|
-
# support to objects. The transaction methods added by this module will
|
83
|
-
# work with most objects, excluding those that cannot be
|
84
|
-
# <i>Marshal</i>ed (bindings, procedure objects, IO instances, or
|
85
|
-
# singleton objects).
|
86
|
-
#
|
87
|
-
# The transactions supported by Transaction::Simple are not backed
|
88
|
-
# transactions; they are not associated with any sort of data store.
|
89
|
-
# They are "live" transactions occurring in memory and in the object
|
90
|
-
# itself. This is to allow "test" changes to be made to an object
|
91
|
-
# before making the changes permanent.
|
92
|
-
#
|
93
|
-
# Transaction::Simple can handle an "infinite" number of transaction
|
94
|
-
# levels (limited only by memory). If I open two transactions, commit
|
95
|
-
# the second, but abort the first, the object will revert to the
|
96
|
-
# original version.
|
97
|
-
#
|
98
|
-
# Transaction::Simple supports "named" transactions, so that multiple
|
99
|
-
# levels of transactions can be committed, aborted, or rewound by
|
100
|
-
# referring to the appropriate name of the transaction. Names may be any
|
101
|
-
# object *except* +nil+. As with Hash keys, String names will be
|
102
|
-
# duplicated and frozen before using.
|
103
|
-
#
|
104
|
-
# Copyright:: Copyright � 2003 - 2005 by Austin Ziegler
|
105
|
-
# Version:: 1.3.0
|
106
|
-
# Licence:: MIT-Style
|
107
|
-
#
|
108
|
-
# Thanks to David Black for help with the initial concept that led to
|
109
|
-
# this library.
|
110
|
-
#
|
111
|
-
# == Usage
|
112
|
-
# include 'transaction/simple'
|
113
|
-
#
|
114
|
-
# v = "Hello, you." # -> "Hello, you."
|
115
|
-
# v.extend(Transaction::Simple) # -> "Hello, you."
|
116
|
-
#
|
117
|
-
# v.start_transaction # -> ... (a Marshal string)
|
118
|
-
# v.transaction_open? # -> true
|
119
|
-
# v.gsub!(/you/, "world") # -> "Hello, world."
|
120
|
-
#
|
121
|
-
# v.rewind_transaction # -> "Hello, you."
|
122
|
-
# v.transaction_open? # -> true
|
123
|
-
#
|
124
|
-
# v.gsub!(/you/, "HAL") # -> "Hello, HAL."
|
125
|
-
# v.abort_transaction # -> "Hello, you."
|
126
|
-
# v.transaction_open? # -> false
|
127
|
-
#
|
128
|
-
# v.start_transaction # -> ... (a Marshal string)
|
129
|
-
# v.start_transaction # -> ... (a Marshal string)
|
130
|
-
#
|
131
|
-
# v.transaction_open? # -> true
|
132
|
-
# v.gsub!(/you/, "HAL") # -> "Hello, HAL."
|
133
|
-
#
|
134
|
-
# v.commit_transaction # -> "Hello, HAL."
|
135
|
-
# v.transaction_open? # -> true
|
136
|
-
# v.abort_transaction # -> "Hello, you."
|
137
|
-
# v.transaction_open? # -> false
|
138
|
-
#
|
139
|
-
# == Named Transaction Usage
|
140
|
-
# v = "Hello, you." # -> "Hello, you."
|
141
|
-
# v.extend(Transaction::Simple) # -> "Hello, you."
|
142
|
-
#
|
143
|
-
# v.start_transaction(:first) # -> ... (a Marshal string)
|
144
|
-
# v.transaction_open? # -> true
|
145
|
-
# v.transaction_open?(:first) # -> true
|
146
|
-
# v.transaction_open?(:second) # -> false
|
147
|
-
# v.gsub!(/you/, "world") # -> "Hello, world."
|
148
|
-
#
|
149
|
-
# v.start_transaction(:second) # -> ... (a Marshal string)
|
150
|
-
# v.gsub!(/world/, "HAL") # -> "Hello, HAL."
|
151
|
-
# v.rewind_transaction(:first) # -> "Hello, you."
|
152
|
-
# v.transaction_open? # -> true
|
153
|
-
# v.transaction_open?(:first) # -> true
|
154
|
-
# v.transaction_open?(:second) # -> false
|
155
|
-
#
|
156
|
-
# v.gsub!(/you/, "world") # -> "Hello, world."
|
157
|
-
# v.start_transaction(:second) # -> ... (a Marshal string)
|
158
|
-
# v.gsub!(/world/, "HAL") # -> "Hello, HAL."
|
159
|
-
# v.transaction_name # -> :second
|
160
|
-
# v.abort_transaction(:first) # -> "Hello, you."
|
161
|
-
# v.transaction_open? # -> false
|
162
|
-
#
|
163
|
-
# v.start_transaction(:first) # -> ... (a Marshal string)
|
164
|
-
# v.gsub!(/you/, "world") # -> "Hello, world."
|
165
|
-
# v.start_transaction(:second) # -> ... (a Marshal string)
|
166
|
-
# v.gsub!(/world/, "HAL") # -> "Hello, HAL."
|
167
|
-
#
|
168
|
-
# v.commit_transaction(:first) # -> "Hello, HAL."
|
169
|
-
# v.transaction_open? # -> false
|
170
|
-
#
|
171
|
-
# == Block Usage
|
172
|
-
# v = "Hello, you." # -> "Hello, you."
|
173
|
-
# Transaction::Simple.start(v) do |tv|
|
174
|
-
# # v has been extended with Transaction::Simple and an unnamed
|
175
|
-
# # transaction has been started.
|
176
|
-
# tv.transaction_open? # -> true
|
177
|
-
# tv.gsub!(/you/, "world") # -> "Hello, world."
|
178
|
-
#
|
179
|
-
# tv.rewind_transaction # -> "Hello, you."
|
180
|
-
# tv.transaction_open? # -> true
|
181
|
-
#
|
182
|
-
# tv.gsub!(/you/, "HAL") # -> "Hello, HAL."
|
183
|
-
# # The following breaks out of the transaction block after
|
184
|
-
# # aborting the transaction.
|
185
|
-
# tv.abort_transaction # -> "Hello, you."
|
186
|
-
# end
|
187
|
-
# # v still has Transaction::Simple applied from here on out.
|
188
|
-
# v.transaction_open? # -> false
|
189
|
-
#
|
190
|
-
# Transaction::Simple.start(v) do |tv|
|
191
|
-
# tv.start_transaction # -> ... (a Marshal string)
|
192
|
-
#
|
193
|
-
# tv.transaction_open? # -> true
|
194
|
-
# tv.gsub!(/you/, "HAL") # -> "Hello, HAL."
|
195
|
-
#
|
196
|
-
# # If #commit_transaction were called without having started a
|
197
|
-
# # second transaction, then it would break out of the transaction
|
198
|
-
# # block after committing the transaction.
|
199
|
-
# tv.commit_transaction # -> "Hello, HAL."
|
200
|
-
# tv.transaction_open? # -> true
|
201
|
-
# tv.abort_transaction # -> "Hello, you."
|
202
|
-
# end
|
203
|
-
# v.transaction_open? # -> false
|
204
|
-
#
|
205
|
-
# == Named Transaction Usage
|
206
|
-
# v = "Hello, you." # -> "Hello, you."
|
207
|
-
# v.extend(Transaction::Simple) # -> "Hello, you."
|
208
|
-
#
|
209
|
-
# v.start_transaction(:first) # -> ... (a Marshal string)
|
210
|
-
# v.transaction_open? # -> true
|
211
|
-
# v.transaction_open?(:first) # -> true
|
212
|
-
# v.transaction_open?(:second) # -> false
|
213
|
-
# v.gsub!(/you/, "world") # -> "Hello, world."
|
214
|
-
#
|
215
|
-
# v.start_transaction(:second) # -> ... (a Marshal string)
|
216
|
-
# v.gsub!(/world/, "HAL") # -> "Hello, HAL."
|
217
|
-
# v.rewind_transaction(:first) # -> "Hello, you."
|
218
|
-
# v.transaction_open? # -> true
|
219
|
-
# v.transaction_open?(:first) # -> true
|
220
|
-
# v.transaction_open?(:second) # -> false
|
221
|
-
#
|
222
|
-
# v.gsub!(/you/, "world") # -> "Hello, world."
|
223
|
-
# v.start_transaction(:second) # -> ... (a Marshal string)
|
224
|
-
# v.gsub!(/world/, "HAL") # -> "Hello, HAL."
|
225
|
-
# v.transaction_name # -> :second
|
226
|
-
# v.abort_transaction(:first) # -> "Hello, you."
|
227
|
-
# v.transaction_open? # -> false
|
228
|
-
#
|
229
|
-
# v.start_transaction(:first) # -> ... (a Marshal string)
|
230
|
-
# v.gsub!(/you/, "world") # -> "Hello, world."
|
231
|
-
# v.start_transaction(:second) # -> ... (a Marshal string)
|
232
|
-
# v.gsub!(/world/, "HAL") # -> "Hello, HAL."
|
233
|
-
#
|
234
|
-
# v.commit_transaction(:first) # -> "Hello, HAL."
|
235
|
-
# v.transaction_open? # -> false
|
236
|
-
#
|
237
|
-
# == Thread Safety
|
238
|
-
# Threadsafe version of Transaction::Simple and
|
239
|
-
# Transaction::Simple::Group exist; these are loaded from
|
240
|
-
# 'transaction/simple/threadsafe' and
|
241
|
-
# 'transaction/simple/threadsafe/group', respectively, and are
|
242
|
-
# represented in Ruby code as Transaction::Simple::ThreadSafe and
|
243
|
-
# Transaction::Simple::ThreadSafe::Group, respectively.
|
244
|
-
#
|
245
|
-
# == Contraindications
|
246
|
-
# While Transaction::Simple is very useful, it has some severe
|
247
|
-
# limitations that must be understood. Transaction::Simple:
|
248
|
-
#
|
249
|
-
# * uses Marshal. Thus, any object which cannot be <i>Marshal</i>ed
|
250
|
-
# cannot use Transaction::Simple. In my experience, this affects
|
251
|
-
# singleton objects more often than any other object. It may be that
|
252
|
-
# Ruby 2.0 will solve this problem.
|
253
|
-
# * does not manage resources. Resources external to the object and its
|
254
|
-
# instance variables are not managed at all. However, all instance
|
255
|
-
# variables and objects "belonging" to those instance variables are
|
256
|
-
# managed. If there are object reference counts to be handled,
|
257
|
-
# Transaction::Simple will probably cause problems.
|
258
|
-
# * is not inherently thread-safe. In the ACID ("atomic, consistent,
|
259
|
-
# isolated, durable") test, Transaction::Simple provides CD, but it is
|
260
|
-
# up to the user of Transaction::Simple to provide isolation and
|
261
|
-
# atomicity. Transactions should be considered "critical sections" in
|
262
|
-
# multi-threaded applications. If thread safety and atomicity is
|
263
|
-
# absolutely required, use Transaction::Simple::ThreadSafe, which uses
|
264
|
-
# a Mutex object to synchronize the accesses on the object during the
|
265
|
-
# transaction operations.
|
266
|
-
# * does not necessarily maintain Object#__id__ values on rewind or
|
267
|
-
# abort. This may change for future versions that will be Ruby 1.8 or
|
268
|
-
# better *only*. Certain objects that support #replace will maintain
|
269
|
-
# Object#__id__.
|
270
|
-
# * Can be a memory hog if you use many levels of transactions on many
|
271
|
-
# objects.
|
272
|
-
#
|
273
|
-
module Simple
|
274
|
-
TRANSACTION_SIMPLE_VERSION = '1.3.0'
|
275
|
-
|
276
|
-
# Sets the Transaction::Simple debug object. It must respond to #<<.
|
277
|
-
# Sets the transaction debug object. Debugging will be performed
|
278
|
-
# automatically if there's a debug object. The generic transaction
|
279
|
-
# error class.
|
280
|
-
def self.debug_io=(io)
|
55
|
+
class << self
|
56
|
+
# Sets the Transaction::Simple debug object. It must respond to #<<.
|
57
|
+
# Debugging will be performed automatically if there's a debug object.
|
58
|
+
def debug_io=(io)
|
281
59
|
if io.nil?
|
282
60
|
@tdi = nil
|
283
61
|
@debugging = false
|
284
62
|
else
|
285
|
-
unless io.respond_to?(:<<)
|
286
|
-
raise TransactionError, Messages[:bad_debug_object]
|
287
|
-
end
|
63
|
+
raise Transaction::TransactionError, Transaction::Messages[:bad_debug_object] unless io.respond_to?(:<<)
|
288
64
|
@tdi = io
|
289
65
|
@debugging = true
|
290
66
|
end
|
291
67
|
end
|
292
68
|
|
293
|
-
|
294
|
-
def
|
295
|
-
@debugging
|
69
|
+
# Returns +true+ if we are debugging.
|
70
|
+
def debugging?
|
71
|
+
defined? @debugging and @debugging
|
296
72
|
end
|
297
73
|
|
298
|
-
|
299
|
-
|
300
|
-
def self.debug_io
|
74
|
+
# Returns the Transaction::Simple debug object. It must respond to #<<.
|
75
|
+
def debug_io
|
301
76
|
@tdi ||= ""
|
302
77
|
@tdi
|
303
78
|
end
|
79
|
+
end
|
304
80
|
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
return (not @__transaction_checkpoint__.nil?)
|
317
|
-
else
|
318
|
-
if Transaction::Simple.debugging?
|
319
|
-
Transaction::Simple.debug_io << "Transaction(#{name.inspect}) " <<
|
320
|
-
"[#{(@__transaction_checkpoint__.nil?) ? 'closed' : 'open'}]\n"
|
321
|
-
end
|
322
|
-
return ((not @__transaction_checkpoint__.nil?) and @__transaction_names__.include?(name))
|
323
|
-
end
|
81
|
+
# If +name+ is +nil+ (default), then returns +true+ if there is currently
|
82
|
+
# a transaction open. If +name+ is specified, then returns +true+ if there
|
83
|
+
# is currently a transaction known as +name+ open.
|
84
|
+
def transaction_open?(name = nil)
|
85
|
+
defined? @__transaction_checkpoint__ or @__transaction_checkpoint__ = nil
|
86
|
+
if name.nil?
|
87
|
+
Transaction::Simple.debug_io << "Transaction " << "[#{(@__transaction_checkpoint__.nil?) ? 'closed' : 'open'}]\n" if Transaction::Simple.debugging?
|
88
|
+
return (not @__transaction_checkpoint__.nil?)
|
89
|
+
else
|
90
|
+
Transaction::Simple.debug_io << "Transaction(#{name.inspect}) " << "[#{(@__transaction_checkpoint__.nil?) ? 'closed' : 'open'}]\n" if Transaction::Simple.debugging?
|
91
|
+
return ((not @__transaction_checkpoint__.nil?) and @__transaction_names__.include?(name))
|
324
92
|
end
|
93
|
+
end
|
325
94
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
end
|
336
|
-
if @__transaction_names__[-1].kind_of?(String)
|
337
|
-
@__transaction_names__[-1].dup
|
338
|
-
else
|
339
|
-
@__transaction_names__[-1]
|
340
|
-
end
|
95
|
+
# Returns the current name of the transaction. Transactions not explicitly
|
96
|
+
# named are named +nil+.
|
97
|
+
def transaction_name
|
98
|
+
raise Transaction::TransactionError, Transaction::Messages[:no_transaction_open] if @__transaction_checkpoint__.nil?
|
99
|
+
Transaction::Simple.debug_io << "#{'|' * @__transaction_level__} " << "Transaction Name: #{@__transaction_names__[-1].inspect}\n" if Transaction::Simple.debugging?
|
100
|
+
if @__transaction_names__[-1].kind_of?(String)
|
101
|
+
@__transaction_names__[-1].dup
|
102
|
+
else
|
103
|
+
@__transaction_names__[-1]
|
341
104
|
end
|
105
|
+
end
|
342
106
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
107
|
+
# Starts a transaction. Stores the current object state. If a transaction
|
108
|
+
# name is specified, the transaction will be named. Transaction names must
|
109
|
+
# be unique. Transaction names of +nil+ will be treated as unnamed
|
110
|
+
# transactions.
|
111
|
+
def start_transaction(name = nil)
|
112
|
+
@__transaction_level__ ||= 0
|
113
|
+
@__transaction_names__ ||= []
|
350
114
|
|
351
|
-
|
352
|
-
@__transaction_names__ << nil
|
353
|
-
ss = "" if Transaction::Simple.debugging?
|
354
|
-
else
|
355
|
-
if @__transaction_names__.include?(name)
|
356
|
-
raise TransactionError, Messages[:unique_names]
|
357
|
-
end
|
358
|
-
name = name.dup.freeze if name.kind_of?(String)
|
359
|
-
@__transaction_names__ << name
|
360
|
-
ss = "(#{name.inspect})" if Transaction::Simple.debugging?
|
361
|
-
end
|
362
|
-
|
363
|
-
@__transaction_level__ += 1
|
115
|
+
name = name.dup.freeze if name.kind_of?(String)
|
364
116
|
|
365
|
-
|
366
|
-
Transaction::Simple.debug_io << "#{'>' * @__transaction_level__} " <<
|
367
|
-
"Start Transaction#{ss}\n"
|
368
|
-
end
|
117
|
+
raise Transaction::TransactionError, Transaction::Messages[:unique_names] if name and @__transaction_names__.include?(name)
|
369
118
|
|
370
|
-
|
371
|
-
|
119
|
+
@__transaction_names__ << name
|
120
|
+
@__transaction_level__ += 1
|
372
121
|
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
def rewind_transaction(name = nil)
|
377
|
-
if @__transaction_checkpoint__.nil?
|
378
|
-
raise TransactionError, Messages[:cannot_rewind_no_transaction]
|
379
|
-
end
|
122
|
+
if Transaction::Simple.debugging?
|
123
|
+
ss = "(#{name.inspect})"
|
124
|
+
ss = "" unless ss
|
380
125
|
|
381
|
-
|
382
|
-
|
383
|
-
if @__transaction_block__ and name
|
384
|
-
nix = @__transaction_names__.index(name) + 1
|
385
|
-
if nix < @__transaction_block__
|
386
|
-
raise TransactionError, Messages[:cannot_rewind_transaction_before_block]
|
387
|
-
end
|
388
|
-
end
|
126
|
+
Transaction::Simple.debug_io << "#{'>' * @__transaction_level__} " << "Start Transaction#{ss}\n"
|
127
|
+
end
|
389
128
|
|
390
|
-
|
391
|
-
|
392
|
-
ss = "" if Transaction::Simple.debugging?
|
393
|
-
else
|
394
|
-
unless @__transaction_names__.include?(name)
|
395
|
-
raise TransactionError, Messages[:cannot_rewind_named_transaction] % name.inspect
|
396
|
-
end
|
397
|
-
ss = "(#{name})" if Transaction::Simple.debugging?
|
129
|
+
@__transaction_checkpoint__ = Marshal.dump(self)
|
130
|
+
end
|
398
131
|
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
132
|
+
# Rewinds the transaction. If +name+ is specified, then the intervening
|
133
|
+
# transactions will be aborted and the named transaction will be rewound.
|
134
|
+
# Otherwise, only the current transaction is rewound.
|
135
|
+
#
|
136
|
+
# After each level of transaction is rewound, if the callback method
|
137
|
+
# #_post_transaction_rewind is defined, it will be called. It is intended
|
138
|
+
# to allow a complex self-referential graph to fix itself. The simplest
|
139
|
+
# way to explain this is with an example.
|
140
|
+
#
|
141
|
+
# class Child
|
142
|
+
# attr_accessor :parent
|
143
|
+
# end
|
144
|
+
#
|
145
|
+
# class Parent
|
146
|
+
# include Transaction::Simple
|
147
|
+
#
|
148
|
+
# attr_reader :children
|
149
|
+
# def initialize
|
150
|
+
# @children = []
|
151
|
+
# end
|
152
|
+
#
|
153
|
+
# def << child
|
154
|
+
# child.parent = self
|
155
|
+
# @children << child
|
156
|
+
# end
|
157
|
+
#
|
158
|
+
# def valid?
|
159
|
+
# @children.all? { |child| child.parent == self }
|
160
|
+
# end
|
161
|
+
# end
|
162
|
+
#
|
163
|
+
# parent = Parent.new
|
164
|
+
# parent << Child.new
|
165
|
+
# parent.start_transaction
|
166
|
+
# parent << Child.new
|
167
|
+
# parent.abort_transaction
|
168
|
+
# puts parent.valid? # => false
|
169
|
+
#
|
170
|
+
# This problem can be fixed by modifying the Parent class to include the
|
171
|
+
# #_post_transaction_rewind callback.
|
172
|
+
#
|
173
|
+
# class Parent
|
174
|
+
# # Reconnect the restored children to me, instead of to the bogus me
|
175
|
+
# # that was restored to them by Marshal::load.
|
176
|
+
# def _post_transaction_rewind
|
177
|
+
# @children.each { |child| child.parent = self }
|
178
|
+
# end
|
179
|
+
# end
|
180
|
+
#
|
181
|
+
# parent = Parent.new
|
182
|
+
# parent << Child.new
|
183
|
+
# parent.start_transaction
|
184
|
+
# parent << Child.new
|
185
|
+
# parent.abort_transaction
|
186
|
+
# puts parent.valid? # => true
|
187
|
+
def rewind_transaction(name = nil)
|
188
|
+
raise Transaction::TransactionError, Transaction::Messages[:cannot_rewind_no_transaction] if @__transaction_checkpoint__.nil?
|
189
|
+
|
190
|
+
# Check to see if we are trying to rewind a transaction that is
|
191
|
+
# outside of the current transaction block.
|
192
|
+
defined? @__transaction_block__ or @__transaction_block__ = nil
|
193
|
+
if @__transaction_block__ and name
|
194
|
+
nix = @__transaction_names__.index(name) + 1
|
195
|
+
raise Transaction::TransactionError, Transaction::Messages[:cannot_rewind_transaction_before_block] if nix < @__transaction_block__
|
415
196
|
end
|
416
197
|
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
#
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
198
|
+
if name.nil?
|
199
|
+
checkpoint = @__transaction_checkpoint__
|
200
|
+
__rewind_this_transaction
|
201
|
+
@__transaction_checkpoint__ = checkpoint
|
202
|
+
ss = "" if Transaction::Simple.debugging?
|
203
|
+
else
|
204
|
+
raise Transaction::TransactionError, Transaction::Messages[:cannot_rewind_named_transaction] % name.inspect unless @__transaction_names__.include?(name)
|
205
|
+
ss = "(#{name})" if Transaction::Simple.debugging?
|
206
|
+
|
207
|
+
while @__transaction_names__[-1] != name
|
208
|
+
@__transaction_checkpoint__ = __rewind_this_transaction
|
209
|
+
Transaction::Simple.debug_io << "#{'|' * @__transaction_level__} " << "Rewind Transaction#{ss}\n" if Transaction::Simple.debugging?
|
210
|
+
@__transaction_level__ -= 1
|
211
|
+
@__transaction_names__.pop
|
429
212
|
end
|
213
|
+
checkpoint = @__transaction_checkpoint__
|
214
|
+
__rewind_this_transaction
|
215
|
+
@__transaction_checkpoint__ = checkpoint
|
216
|
+
end
|
217
|
+
Transaction::Simple.debug_io << "#{'|' * @__transaction_level__} " << "Rewind Transaction#{ss}\n" if Transaction::Simple.debugging?
|
218
|
+
self
|
219
|
+
end
|
430
220
|
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
221
|
+
# Aborts the transaction. Rewinds the object state to what it was before
|
222
|
+
# the transaction was started and closes the transaction. If +name+ is
|
223
|
+
# specified, then the intervening transactions and the named transaction
|
224
|
+
# will be aborted. Otherwise, only the current transaction is aborted.
|
225
|
+
#
|
226
|
+
# See #rewind_transaction for information about dealing with complex
|
227
|
+
# self-referential object graphs.
|
228
|
+
#
|
229
|
+
# If the current or named transaction has been started by a block
|
230
|
+
# (Transaction::Simple.start), then the execution of the block will be
|
231
|
+
# halted with +break+ +self+.
|
232
|
+
def abort_transaction(name = nil)
|
233
|
+
raise Transaction::TransactionError, Transaction::Messages[:cannot_abort_no_transaction] if @__transaction_checkpoint__.nil?
|
234
|
+
|
235
|
+
# Check to see if we are trying to abort a transaction that is outside
|
236
|
+
# of the current transaction block. Otherwise, raise TransactionAborted
|
237
|
+
# if they are the same.
|
238
|
+
defined? @__transaction_block__ or @__transaction_block__ = nil
|
239
|
+
if @__transaction_block__ and name
|
240
|
+
nix = @__transaction_names__.index(name) + 1
|
241
|
+
raise Transaction::TransactionError, Transaction::Messages[:cannot_abort_transaction_before_block] if nix < @__transaction_block__
|
242
|
+
|
243
|
+
raise Transaction::TransactionAborted if @__transaction_block__ == nix
|
244
|
+
end
|
442
245
|
|
443
|
-
|
246
|
+
raise Transaction::TransactionAborted if @__transaction_block__ == @__transaction_level__
|
444
247
|
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
end
|
451
|
-
__abort_transaction(name) while @__transaction_names__.include?(name)
|
452
|
-
end
|
453
|
-
self
|
248
|
+
if name.nil?
|
249
|
+
__abort_transaction(name)
|
250
|
+
else
|
251
|
+
raise Transaction::TransactionError, Transaction::Messages[:cannot_abort_named_transaction] % name.inspect unless @__transaction_names__.include?(name)
|
252
|
+
__abort_transaction(name) while @__transaction_names__.include?(name)
|
454
253
|
end
|
455
254
|
|
456
|
-
|
457
|
-
|
458
|
-
#
|
459
|
-
# If +name+ is specified and +name+ is in the list of named
|
460
|
-
# transactions, then all transactions are closed and committed until
|
461
|
-
# the named transaction is reached.
|
462
|
-
def commit_transaction(name = nil)
|
463
|
-
if @__transaction_checkpoint__.nil?
|
464
|
-
raise TransactionError, Messages[:cannot_commit_no_transaction]
|
465
|
-
end
|
466
|
-
@__transaction_block__ ||= nil
|
467
|
-
|
468
|
-
# Check to see if we are trying to commit a transaction that is
|
469
|
-
# outside of the current transaction block. Otherwise, raise
|
470
|
-
# TransactionCommitted if they are the same.
|
471
|
-
if @__transaction_block__ and name
|
472
|
-
nix = @__transaction_names__.index(name) + 1
|
473
|
-
if nix < @__transaction_block__
|
474
|
-
raise TransactionError, Messages[:cannot_commit_transaction_before_block]
|
475
|
-
end
|
255
|
+
self
|
256
|
+
end
|
476
257
|
|
477
|
-
|
478
|
-
|
258
|
+
# If +name+ is +nil+ (default), the current transaction level is closed
|
259
|
+
# out and the changes are committed.
|
260
|
+
#
|
261
|
+
# If +name+ is specified and +name+ is in the list of named transactions,
|
262
|
+
# then all transactions are closed and committed until the named
|
263
|
+
# transaction is reached.
|
264
|
+
def commit_transaction(name = nil)
|
265
|
+
raise Transaction::TransactionError, Transaction::Messages[:cannot_commit_no_transaction] if @__transaction_checkpoint__.nil?
|
266
|
+
@__transaction_block__ ||= nil
|
267
|
+
|
268
|
+
# Check to see if we are trying to commit a transaction that is outside
|
269
|
+
# of the current transaction block. Otherwise, raise
|
270
|
+
# TransactionCommitted if they are the same.
|
271
|
+
if @__transaction_block__ and name
|
272
|
+
nix = @__transaction_names__.index(name) + 1
|
273
|
+
raise Transaction::TransactionError, Transaction::Messages[:cannot_commit_transaction_before_block] if nix < @__transaction_block__
|
274
|
+
|
275
|
+
raise Transaction::TransactionCommitted if @__transaction_block__ == nix
|
276
|
+
end
|
479
277
|
|
480
|
-
|
278
|
+
raise Transaction::TransactionCommitted if @__transaction_block__ == @__transaction_level__
|
481
279
|
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
else
|
490
|
-
unless @__transaction_names__.include?(name)
|
491
|
-
raise TransactionError, Messages[:cannot_commit_named_transaction] % name.inspect
|
492
|
-
end
|
493
|
-
ss = "(#{name})" if Transaction::Simple.debugging?
|
280
|
+
if name.nil?
|
281
|
+
ss = "" if Transaction::Simple.debugging?
|
282
|
+
__commit_transaction
|
283
|
+
Transaction::Simple.debug_io << "#{'<' * @__transaction_level__} " << "Commit Transaction#{ss}\n" if Transaction::Simple.debugging?
|
284
|
+
else
|
285
|
+
raise Transaction::TransactionError, Transaction::Messages[:cannot_commit_named_transaction] % name.inspect unless @__transaction_names__.include?(name)
|
286
|
+
ss = "(#{name})" if Transaction::Simple.debugging?
|
494
287
|
|
495
|
-
|
496
|
-
|
497
|
-
Transaction::Simple.debug_io << "#{'<' * @__transaction_level__} " <<
|
498
|
-
"Commit Transaction#{ss}\n"
|
499
|
-
end
|
500
|
-
__commit_transaction
|
501
|
-
end
|
502
|
-
if Transaction::Simple.debugging?
|
503
|
-
Transaction::Simple.debug_io << "#{'<' * @__transaction_level__} " <<
|
504
|
-
"Commit Transaction#{ss}\n"
|
505
|
-
end
|
288
|
+
while @__transaction_names__[-1] != name
|
289
|
+
Transaction::Simple.debug_io << "#{'<' * @__transaction_level__} " << "Commit Transaction#{ss}\n" if Transaction::Simple.debugging?
|
506
290
|
__commit_transaction
|
507
291
|
end
|
508
|
-
|
509
|
-
|
292
|
+
Transaction::Simple.debug_io << "#{'<' * @__transaction_level__} " << "Commit Transaction#{ss}\n" if Transaction::Simple.debugging?
|
293
|
+
__commit_transaction
|
510
294
|
end
|
511
295
|
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
296
|
+
self
|
297
|
+
end
|
298
|
+
|
299
|
+
# Alternative method for calling the transaction methods. An optional name
|
300
|
+
# can be specified for named transaction support. This method is
|
301
|
+
# deprecated and will be removed in Transaction::Simple 2.0.
|
302
|
+
#
|
303
|
+
# #transaction(:start):: #start_transaction
|
304
|
+
# #transaction(:rewind):: #rewind_transaction
|
305
|
+
# #transaction(:abort):: #abort_transaction
|
306
|
+
# #transaction(:commit):: #commit_transaction
|
307
|
+
# #transaction(:name):: #transaction_name
|
308
|
+
# #transaction:: #transaction_open?
|
309
|
+
def transaction(action = nil, name = nil)
|
310
|
+
_method = case action
|
311
|
+
when :start then :start_transaction
|
312
|
+
when :rewind then :rewind_transaction
|
313
|
+
when :abort then :abort_transaction
|
314
|
+
when :commit then :commit_transaction
|
315
|
+
when :name then :transaction_name
|
316
|
+
when nil then :transaction_open?
|
317
|
+
else nil
|
318
|
+
end
|
319
|
+
|
320
|
+
if method
|
321
|
+
warn "The #transaction method has been deprecated. Use #{method} instead."
|
322
|
+
else
|
323
|
+
warn "The #transaction method has been deprecated."
|
536
324
|
end
|
537
325
|
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
326
|
+
case method
|
327
|
+
when :transaction_name
|
328
|
+
__send__ method
|
329
|
+
when nil
|
330
|
+
nil
|
331
|
+
else
|
332
|
+
__send__ method, name
|
545
333
|
end
|
334
|
+
end
|
546
335
|
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
336
|
+
# Allows specific variables to be excluded from transaction support. Must
|
337
|
+
# be done after extending the object but before starting the first
|
338
|
+
# transaction on the object.
|
339
|
+
#
|
340
|
+
# vv.transaction_exclusions << "@io"
|
341
|
+
def transaction_exclusions
|
342
|
+
@transaction_exclusions ||= []
|
343
|
+
end
|
552
344
|
|
553
|
-
|
554
|
-
|
555
|
-
|
345
|
+
class << self
|
346
|
+
def __common_start(name, vars, &block)
|
347
|
+
raise Transaction::TransactionError, Transaction::Messages[:cannot_start_empty_block_transaction] if vars.empty?
|
556
348
|
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
349
|
+
if block
|
350
|
+
begin
|
351
|
+
vlevel = {}
|
352
|
+
|
353
|
+
vars.each do |vv|
|
354
|
+
vv.extend(Transaction::Simple)
|
355
|
+
vv.start_transaction(name)
|
356
|
+
vlevel[vv.__id__] = vv.instance_variable_get(:@__transaction_level__)
|
357
|
+
vv.instance_variable_set(:@__transaction_block__, vlevel[vv.__id__])
|
358
|
+
end
|
563
359
|
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
vv.instance_variable_set(:@__transaction_block__, -1)
|
571
|
-
break if tlevel < vlevel[vv.__id__]
|
572
|
-
vv.abort_transaction if vv.transaction_open?
|
573
|
-
end
|
574
|
-
elsif vv.transaction_open?(name)
|
360
|
+
yield(*vars)
|
361
|
+
rescue Transaction::TransactionAborted
|
362
|
+
vars.each do |vv|
|
363
|
+
if name.nil? and vv.transaction_open?
|
364
|
+
loop do
|
365
|
+
tlevel = vv.instance_variable_get(:@__transaction_level__) || -1
|
575
366
|
vv.instance_variable_set(:@__transaction_block__, -1)
|
576
|
-
vv.
|
367
|
+
break if tlevel < vlevel[vv.__id__]
|
368
|
+
vv.abort_transaction if vv.transaction_open?
|
577
369
|
end
|
370
|
+
elsif vv.transaction_open?(name)
|
371
|
+
vv.instance_variable_set(:@__transaction_block__, -1)
|
372
|
+
vv.abort_transaction(name)
|
578
373
|
end
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
vv.commit_transaction if vv.transaction_open?
|
589
|
-
end
|
590
|
-
elsif vv.transaction_open?(name)
|
374
|
+
end
|
375
|
+
rescue Transaction::TransactionCommitted
|
376
|
+
nil
|
377
|
+
ensure
|
378
|
+
vars.each do |vv|
|
379
|
+
if name.nil? and vv.transaction_open?
|
380
|
+
loop do
|
381
|
+
tlevel = vv.instance_variable_get(:@__transaction_level__) || -1
|
382
|
+
break if tlevel < vlevel[vv.__id__]
|
591
383
|
vv.instance_variable_set(:@__transaction_block__, -1)
|
592
|
-
vv.commit_transaction
|
384
|
+
vv.commit_transaction if vv.transaction_open?
|
593
385
|
end
|
386
|
+
elsif vv.transaction_open?(name)
|
387
|
+
vv.instance_variable_set(:@__transaction_block__, -1)
|
388
|
+
vv.commit_transaction(name)
|
594
389
|
end
|
595
390
|
end
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
391
|
+
end
|
392
|
+
else
|
393
|
+
vars.each do |vv|
|
394
|
+
vv.extend(Transaction::Simple)
|
395
|
+
vv.start_transaction(name)
|
601
396
|
end
|
602
397
|
end
|
603
|
-
|
398
|
+
end
|
399
|
+
private :__common_start
|
604
400
|
|
605
|
-
|
606
|
-
|
607
|
-
|
401
|
+
# Start a named transaction in a block. The transaction will auto-commit
|
402
|
+
# when the block finishes.
|
403
|
+
def start_named(name, *vars, &block)
|
404
|
+
__common_start(name, vars, &block)
|
405
|
+
end
|
608
406
|
|
609
|
-
|
610
|
-
|
611
|
-
|
407
|
+
# Start a named transaction in a block. The transaction will auto-commit
|
408
|
+
# when the block finishes.
|
409
|
+
def start(*vars, &block)
|
410
|
+
__common_start(nil, vars, &block)
|
612
411
|
end
|
412
|
+
end
|
613
413
|
|
614
|
-
|
615
|
-
|
414
|
+
def __abort_transaction(name = nil) #:nodoc:
|
415
|
+
@__transaction_checkpoint__ = __rewind_this_transaction
|
616
416
|
|
417
|
+
if Transaction::Simple.debugging?
|
617
418
|
if name.nil?
|
618
|
-
ss = ""
|
419
|
+
ss = ""
|
619
420
|
else
|
620
|
-
ss = "(#{name.inspect})"
|
421
|
+
ss = "(#{name.inspect})"
|
621
422
|
end
|
622
423
|
|
623
|
-
|
624
|
-
Transaction::Simple.debug_io << "#{'<' * @__transaction_level__} " <<
|
625
|
-
"Abort Transaction#{ss}\n"
|
626
|
-
end
|
627
|
-
@__transaction_level__ -= 1
|
628
|
-
@__transaction_names__.pop
|
629
|
-
if @__transaction_level__ < 1
|
630
|
-
@__transaction_level__ = 0
|
631
|
-
@__transaction_names__ = []
|
632
|
-
end
|
424
|
+
Transaction::Simple.debug_io << "#{'<' * @__transaction_level__} " << "Abort Transaction#{ss}\n"
|
633
425
|
end
|
634
426
|
|
635
|
-
|
636
|
-
|
427
|
+
@__transaction_level__ -= 1
|
428
|
+
@__transaction_names__.pop
|
429
|
+
if @__transaction_level__ < 1
|
430
|
+
@__transaction_level__ = 0
|
431
|
+
@__transaction_names__ = []
|
432
|
+
@__transaction_checkpoint__ = nil
|
433
|
+
end
|
434
|
+
end
|
637
435
|
|
638
|
-
|
639
|
-
rr = Marshal.restore(@__transaction_checkpoint__)
|
436
|
+
SKIP_TRANSACTION_VARS = %w(@__transaction_checkpoint__ @__transaction_level__)
|
640
437
|
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
end
|
438
|
+
def __rewind_this_transaction #:nodoc:
|
439
|
+
defined? @__transaction_checkpoint__ or @__transaction_checkpoint__ = nil
|
440
|
+
raise Transaction::TransactionError, Transaction::Messages[:cannot_rewind_no_transaction] if @__transaction_checkpoint__.nil?
|
441
|
+
rr = Marshal.restore(@__transaction_checkpoint__)
|
646
442
|
|
647
|
-
|
648
|
-
next if SKIP_TRANSACTION_VARS.include?(vv)
|
649
|
-
next if self.transaction_exclusions.include?(vv)
|
650
|
-
if respond_to?(:instance_variable_get)
|
651
|
-
instance_variable_set(vv, rr.instance_variable_get(vv))
|
652
|
-
else
|
653
|
-
instance_eval(%q|#{vv} = rr.instance_eval("#{vv}")|)
|
654
|
-
end
|
655
|
-
end
|
443
|
+
replace(rr) if respond_to?(:replace)
|
656
444
|
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
instance_variable_set(vv, nil)
|
661
|
-
else
|
662
|
-
instance_eval(%q|#{vv} = nil|)
|
663
|
-
end
|
664
|
-
end
|
445
|
+
iv = rr.instance_variables - SKIP_TRANSACTION_VARS - self.transaction_exclusions
|
446
|
+
iv.each do |vv|
|
447
|
+
next if self.transaction_exclusions.include?(vv)
|
665
448
|
|
666
|
-
|
667
|
-
rr.instance_variable_get(TRANSACTION_CHECKPOINT)
|
668
|
-
else
|
669
|
-
rr.instance_eval(TRANSACTION_CHECKPOINT)
|
670
|
-
end
|
449
|
+
instance_variable_set(vv, rr.instance_variable_get(vv))
|
671
450
|
end
|
672
451
|
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
@__transaction_checkpoint__ = Marshal.restore(@__transaction_checkpoint__).instance_eval(TRANSACTION_CHECKPOINT)
|
678
|
-
end
|
452
|
+
rest = instance_variables - rr.instance_variables - SKIP_TRANSACTION_VARS - self.transaction_exclusions
|
453
|
+
rest.each do |vv|
|
454
|
+
remove_instance_variable(vv)
|
455
|
+
end
|
679
456
|
|
680
|
-
|
681
|
-
@__transaction_names__.pop
|
457
|
+
_post_transaction_rewind if respond_to?(:_post_transaction_rewind)
|
682
458
|
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
459
|
+
w, $-w = $-w, false # 20070203 OH is this very UGLY
|
460
|
+
res = rr.instance_variable_get(:@__transaction_checkpoint__)
|
461
|
+
$-w = w # 20070203 OH is this very UGLY
|
462
|
+
res
|
463
|
+
end
|
688
464
|
|
689
|
-
|
690
|
-
|
691
|
-
|
465
|
+
def __commit_transaction #:nodoc:
|
466
|
+
defined? @__transaction_checkpoint__ or @__transaction_checkpoint__ = nil
|
467
|
+
raise Transaction::TransactionError, Transaction::Messages[:cannot_commit_no_transaction] if @__transaction_checkpoint__.nil?
|
468
|
+
old = Marshal.restore(@__transaction_checkpoint__)
|
469
|
+
w, $-w = $-w, false # 20070203 OH is this very UGLY
|
470
|
+
@__transaction_checkpoint__ = old.instance_variable_get(:@__transaction_checkpoint__)
|
471
|
+
$-w = w # 20070203 OH is this very UGLY
|
472
|
+
|
473
|
+
@__transaction_level__ -= 1
|
474
|
+
@__transaction_names__.pop
|
475
|
+
|
476
|
+
if @__transaction_level__ < 1
|
477
|
+
@__transaction_level__ = 0
|
478
|
+
@__transaction_names__ = []
|
479
|
+
@__transaction_checkpoint__ = nil
|
480
|
+
end
|
692
481
|
end
|
482
|
+
|
483
|
+
private :__abort_transaction
|
484
|
+
private :__rewind_this_transaction
|
485
|
+
private :__commit_transaction
|
693
486
|
end
|