lafcadio 0.9.2 → 0.9.3
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/bin/lafcadio_schema +28 -26
- data/lib/lafcadio.rb +3 -3
- data/lib/lafcadio.rb~ +1 -1
- data/lib/lafcadio/domain.rb +29 -35
- data/lib/lafcadio/domain.rb~ +35 -42
- data/lib/lafcadio/mock.rb +37 -15
- data/lib/lafcadio/mock.rb~ +59 -36
- data/lib/lafcadio/objectField.rb +31 -20
- data/lib/lafcadio/objectField.rb~ +163 -142
- data/lib/lafcadio/objectStore.rb +125 -58
- data/lib/lafcadio/objectStore.rb~ +242 -177
- data/lib/lafcadio/query.rb +98 -95
- data/lib/lafcadio/query.rb~ +96 -95
- data/lib/lafcadio/schema.rb +4 -4
- data/lib/lafcadio/schema.rb~ +13 -17
- data/lib/lafcadio/test.rb +33 -7
- data/lib/lafcadio/test.rb~ +146 -20
- data/lib/lafcadio/util.rb +27 -11
- data/lib/lafcadio/util.rb~ +27 -43
- metadata +3 -7
- data/lib/lafcadio/dateTime.rb~ +0 -93
- data/lib/lafcadio/depend.rb~ +0 -8
- data/lib/lafcadio/objectStore.rb.~1.64.~ +0 -766
- data/lib/lafcadio/test/testconfig.dat~ +0 -13
data/bin/lafcadio_schema
CHANGED
@@ -1,36 +1,38 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'ubygems'
|
4
|
-
require 'lafcadio/depend'
|
5
|
-
require 'lafcadio/schema'
|
6
|
-
require 'lafcadio/util'
|
7
4
|
require 'getoptlong'
|
5
|
+
require 'lafcadio'
|
8
6
|
include Lafcadio
|
9
7
|
|
8
|
+
$all_domain_classes = []
|
9
|
+
module Lafcadio
|
10
|
+
def DomainObject.inherited( subclass )
|
11
|
+
$all_domain_classes << subclass
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
( config, dclass_name ) = [ nil, nil ]
|
10
16
|
opts = GetoptLong.new(
|
11
|
-
[ '--config', '-c', GetoptLong::
|
17
|
+
[ '--config', '-c', GetoptLong::OPTIONAL_ARGUMENT ],
|
12
18
|
[ '--class', '-C', GetoptLong::OPTIONAL_ARGUMENT ]
|
13
19
|
)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
else
|
31
|
-
puts "No domain class in #{ fileName }"
|
32
|
-
end
|
33
|
-
}
|
20
|
+
opts.each do |opt, arg|
|
21
|
+
config = arg if opt == '--config'
|
22
|
+
dclass_name = arg if opt == '--class'
|
23
|
+
end
|
24
|
+
if ARGV.size >= 1
|
25
|
+
LafcadioConfig.set_filename config if config
|
26
|
+
ARGV.each { |fileName| require fileName }
|
27
|
+
if dclass_name
|
28
|
+
domain_classes = [ Class.by_name( dclass_name ) ]
|
29
|
+
else
|
30
|
+
domain_classes = $all_domain_classes
|
31
|
+
end
|
32
|
+
sql = domain_classes.map { |domain_class|
|
33
|
+
CreateTableStatement.new( domain_class ).to_sql
|
34
|
+
}.join( "\n\n" )
|
35
|
+
puts sql
|
34
36
|
else
|
35
|
-
puts "lafcadio_schema -
|
36
|
-
end
|
37
|
+
puts "lafcadio_schema [-C domain_class] file1.rb [file2.rb file3.rb ...]"
|
38
|
+
end
|
data/lib/lafcadio.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
# Lafcadio is an object-relational mapping library for Ruby
|
2
|
-
# design has a few aspects in mind:
|
1
|
+
# Lafcadio is an object-relational mapping library for Ruby. It currently
|
2
|
+
# supports MySQL and PostgreSQL. Its design has a few aspects in mind:
|
3
3
|
# * The importance of unit-testing. Lafcadio includes a MockObjectStore which
|
4
4
|
# can take the place of the ObjectStore for unit tests, so you can test
|
5
5
|
# complex database-driven logic. Committing domain objects, running queries,
|
@@ -16,7 +16,7 @@
|
|
16
16
|
# http://lafcadio.rubyforge.org/tutorial.html.
|
17
17
|
|
18
18
|
module Lafcadio
|
19
|
-
Version = "0.9.
|
19
|
+
Version = "0.9.3"
|
20
20
|
|
21
21
|
require 'lafcadio/depend'
|
22
22
|
require 'lafcadio/domain'
|
data/lib/lafcadio.rb~
CHANGED
data/lib/lafcadio/domain.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'extensions/module'
|
2
2
|
require 'lafcadio/objectField'
|
3
3
|
require 'lafcadio/util'
|
4
|
+
require 'monitor'
|
4
5
|
require 'rexml/document'
|
5
6
|
|
6
7
|
module Lafcadio
|
@@ -42,15 +43,13 @@ module Lafcadio
|
|
42
43
|
|
43
44
|
def possible_field_attributes
|
44
45
|
fieldAttr = []
|
45
|
-
fieldAttr << FieldAttribute.new( 'size',
|
46
|
-
fieldAttr << FieldAttribute.new( 'unique',
|
47
|
-
fieldAttr << FieldAttribute.new( 'not_nil',
|
48
|
-
fieldAttr << FieldAttribute.new( 'enum_type',
|
49
|
-
|
50
|
-
fieldAttr << FieldAttribute.new( '
|
51
|
-
fieldAttr << FieldAttribute.new( '
|
52
|
-
DateField )
|
53
|
-
fieldAttr << FieldAttribute.new( 'large', FieldAttribute::BOOLEAN )
|
46
|
+
fieldAttr << FieldAttribute.new( 'size', :integer )
|
47
|
+
fieldAttr << FieldAttribute.new( 'unique', :boolean )
|
48
|
+
fieldAttr << FieldAttribute.new( 'not_nil', :boolean )
|
49
|
+
fieldAttr << FieldAttribute.new( 'enum_type', :enum, BooleanField )
|
50
|
+
fieldAttr << FieldAttribute.new( 'enums', :hash )
|
51
|
+
fieldAttr << FieldAttribute.new( 'range', :enum, DateField )
|
52
|
+
fieldAttr << FieldAttribute.new( 'large', :boolean )
|
54
53
|
end
|
55
54
|
|
56
55
|
def register_name( name )
|
@@ -69,11 +68,6 @@ module Lafcadio
|
|
69
68
|
end
|
70
69
|
|
71
70
|
class FieldAttribute
|
72
|
-
INTEGER = 1
|
73
|
-
BOOLEAN = 2
|
74
|
-
ENUM = 3
|
75
|
-
HASH = 4
|
76
|
-
|
77
71
|
attr_reader :name, :value_class
|
78
72
|
|
79
73
|
def initialize( name, value_class, objectFieldClass = nil )
|
@@ -84,7 +78,7 @@ module Lafcadio
|
|
84
78
|
def maybe_set_field_attr( field, fieldElt )
|
85
79
|
setterMethod = "#{ name }="
|
86
80
|
if field.respond_to?( setterMethod )
|
87
|
-
if value_class !=
|
81
|
+
if value_class != :hash
|
88
82
|
if ( attrStr = fieldElt.attributes[name] )
|
89
83
|
field.send( setterMethod, value_from_string( attrStr ) )
|
90
84
|
end
|
@@ -107,12 +101,12 @@ module Lafcadio
|
|
107
101
|
end
|
108
102
|
|
109
103
|
def value_from_string( valueStr )
|
110
|
-
if @value_class ==
|
104
|
+
if @value_class == :integer
|
111
105
|
valueStr.to_i
|
112
|
-
elsif @value_class ==
|
106
|
+
elsif @value_class == :boolean
|
113
107
|
valueStr == 'y'
|
114
|
-
elsif @value_class ==
|
115
|
-
eval "
|
108
|
+
elsif @value_class == :enum
|
109
|
+
eval ":#{ valueStr }"
|
116
110
|
end
|
117
111
|
end
|
118
112
|
end
|
@@ -165,11 +159,11 @@ module Lafcadio
|
|
165
159
|
# email 'email'
|
166
160
|
# date 'birthday'
|
167
161
|
# end
|
168
|
-
# The class methods you can use are +
|
162
|
+
# The class methods you can use are +binary+, +boolean+, +date+,
|
169
163
|
# +date_time+, +domain_object+, +email+, +enum+, +float+, +integer+,
|
170
|
-
# +month+, +state+, +string+, +text_list+. These correspond to
|
171
|
-
# BooleanField, DateField, DateTimeField, DomainObjectField,
|
172
|
-
# EnumField, FloatField, IntegerField, MonthField, StateField,
|
164
|
+
# +month+, +state+, +string+, +text_list+. These correspond to
|
165
|
+
# BinaryField, BooleanField, DateField, DateTimeField, DomainObjectField,
|
166
|
+
# EmailField, EnumField, FloatField, IntegerField, MonthField, StateField,
|
173
167
|
# StringField, and TextListField, respectively. Consult their individual
|
174
168
|
# RDoc entries for more on how to parameterize them through the class
|
175
169
|
# methods.
|
@@ -284,10 +278,7 @@ module Lafcadio
|
|
284
278
|
# different levels.
|
285
279
|
class DomainObject
|
286
280
|
@@subclass_records = Hash.new do |h, k| h[k] = SubclassRecord.new( k ); end
|
287
|
-
|
288
|
-
COMMIT_ADD = 1
|
289
|
-
COMMIT_EDIT = 2
|
290
|
-
COMMIT_DELETE = 3
|
281
|
+
@@subclass_records.extend MonitorMixin
|
291
282
|
|
292
283
|
include DomainComparable
|
293
284
|
|
@@ -307,7 +298,9 @@ module Lafcadio
|
|
307
298
|
# Returns every committed instance of the domain class.
|
308
299
|
#
|
309
300
|
# User.all # => all users
|
310
|
-
def self.all
|
301
|
+
def self.all( opts = {} )
|
302
|
+
ObjectStore.get_object_store.all( self, opts )
|
303
|
+
end
|
311
304
|
|
312
305
|
def self.all_fields # :nodoc:
|
313
306
|
self_and_concrete_superclasses.map { |a_class|
|
@@ -316,7 +309,7 @@ module Lafcadio
|
|
316
309
|
end
|
317
310
|
|
318
311
|
def self.class_field(fieldName) #:nodoc:
|
319
|
-
self.class_fields.find { |field| field.name == fieldName }
|
312
|
+
self.class_fields.find { |field| field.name == fieldName.to_s }
|
320
313
|
end
|
321
314
|
|
322
315
|
def self.class_fields #:nodoc:
|
@@ -381,10 +374,7 @@ module Lafcadio
|
|
381
374
|
#
|
382
375
|
# class LotsOfBooleans < Lafcadio::DomainObject
|
383
376
|
# default_field_setup_hash(
|
384
|
-
# Lafcadio::BooleanField,
|
385
|
-
# {
|
386
|
-
# 'enum_type' => Lafcadio::BooleanField::ENUMS_CAPITAL_YES_NO
|
387
|
-
# }
|
377
|
+
# Lafcadio::BooleanField, { 'enum_type' => :capital_yes_no }
|
388
378
|
# )
|
389
379
|
# booleans 'this', 'that', 'the_other', 'and_another_one',
|
390
380
|
# 'this_one_too'
|
@@ -470,7 +460,7 @@ module Lafcadio
|
|
470
460
|
if arg.is_a? Fixnum
|
471
461
|
ObjectStore.get_object_store.get( self, *args )
|
472
462
|
else
|
473
|
-
qry = Query.new( self,
|
463
|
+
qry = Query.new( self, :group_functions => [ :count ] )
|
474
464
|
ObjectStore.get_object_store.group_query qry
|
475
465
|
end
|
476
466
|
else
|
@@ -557,6 +547,10 @@ module Lafcadio
|
|
557
547
|
#
|
558
548
|
# the_one_user = User.only
|
559
549
|
def self.only; all.only; end
|
550
|
+
|
551
|
+
def self.postgres_pk_id_seq
|
552
|
+
"#{ table_name }_#{ sql_primary_key_name }_seq"
|
553
|
+
end
|
560
554
|
|
561
555
|
def self.require_domain_file( typeString ) # :nodoc:
|
562
556
|
typeString =~ /([^\:]*)$/
|
@@ -611,7 +605,7 @@ module Lafcadio
|
|
611
605
|
end
|
612
606
|
|
613
607
|
def self.subclass_record # :nodoc:
|
614
|
-
@@subclass_records[self]
|
608
|
+
@@subclass_records.synchronize { @@subclass_records[self] }
|
615
609
|
end
|
616
610
|
|
617
611
|
def self.subclasses #:nodoc:
|
data/lib/lafcadio/domain.rb~
CHANGED
@@ -42,15 +42,13 @@ module Lafcadio
|
|
42
42
|
|
43
43
|
def possible_field_attributes
|
44
44
|
fieldAttr = []
|
45
|
-
fieldAttr << FieldAttribute.new( 'size',
|
46
|
-
fieldAttr << FieldAttribute.new( 'unique',
|
47
|
-
fieldAttr << FieldAttribute.new( 'not_nil',
|
48
|
-
fieldAttr << FieldAttribute.new( 'enum_type',
|
49
|
-
|
50
|
-
fieldAttr << FieldAttribute.new( '
|
51
|
-
fieldAttr << FieldAttribute.new( '
|
52
|
-
DateField )
|
53
|
-
fieldAttr << FieldAttribute.new( 'large', FieldAttribute::BOOLEAN )
|
45
|
+
fieldAttr << FieldAttribute.new( 'size', :integer )
|
46
|
+
fieldAttr << FieldAttribute.new( 'unique', :boolean )
|
47
|
+
fieldAttr << FieldAttribute.new( 'not_nil', :boolean )
|
48
|
+
fieldAttr << FieldAttribute.new( 'enum_type', :enum, BooleanField )
|
49
|
+
fieldAttr << FieldAttribute.new( 'enums', :hash )
|
50
|
+
fieldAttr << FieldAttribute.new( 'range', :enum, DateField )
|
51
|
+
fieldAttr << FieldAttribute.new( 'large', :boolean )
|
54
52
|
end
|
55
53
|
|
56
54
|
def register_name( name )
|
@@ -69,11 +67,6 @@ module Lafcadio
|
|
69
67
|
end
|
70
68
|
|
71
69
|
class FieldAttribute
|
72
|
-
INTEGER = 1
|
73
|
-
BOOLEAN = 2
|
74
|
-
ENUM = 3
|
75
|
-
HASH = 4
|
76
|
-
|
77
70
|
attr_reader :name, :value_class
|
78
71
|
|
79
72
|
def initialize( name, value_class, objectFieldClass = nil )
|
@@ -84,7 +77,7 @@ module Lafcadio
|
|
84
77
|
def maybe_set_field_attr( field, fieldElt )
|
85
78
|
setterMethod = "#{ name }="
|
86
79
|
if field.respond_to?( setterMethod )
|
87
|
-
if value_class !=
|
80
|
+
if value_class != :hash
|
88
81
|
if ( attrStr = fieldElt.attributes[name] )
|
89
82
|
field.send( setterMethod, value_from_string( attrStr ) )
|
90
83
|
end
|
@@ -107,12 +100,12 @@ module Lafcadio
|
|
107
100
|
end
|
108
101
|
|
109
102
|
def value_from_string( valueStr )
|
110
|
-
if @value_class ==
|
103
|
+
if @value_class == :integer
|
111
104
|
valueStr.to_i
|
112
|
-
elsif @value_class ==
|
105
|
+
elsif @value_class == :boolean
|
113
106
|
valueStr == 'y'
|
114
|
-
elsif @value_class ==
|
115
|
-
eval "
|
107
|
+
elsif @value_class == :enum
|
108
|
+
eval ":#{ valueStr }"
|
116
109
|
end
|
117
110
|
end
|
118
111
|
end
|
@@ -165,11 +158,11 @@ module Lafcadio
|
|
165
158
|
# email 'email'
|
166
159
|
# date 'birthday'
|
167
160
|
# end
|
168
|
-
# The class methods you can use are +
|
161
|
+
# The class methods you can use are +binary+, +boolean+, +date+,
|
169
162
|
# +date_time+, +domain_object+, +email+, +enum+, +float+, +integer+,
|
170
|
-
# +month+, +state+, +string+, +text_list+. These correspond to
|
171
|
-
# BooleanField, DateField, DateTimeField, DomainObjectField,
|
172
|
-
# EnumField, FloatField, IntegerField, MonthField, StateField,
|
163
|
+
# +month+, +state+, +string+, +text_list+. These correspond to
|
164
|
+
# BinaryField, BooleanField, DateField, DateTimeField, DomainObjectField,
|
165
|
+
# EmailField, EnumField, FloatField, IntegerField, MonthField, StateField,
|
173
166
|
# StringField, and TextListField, respectively. Consult their individual
|
174
167
|
# RDoc entries for more on how to parameterize them through the class
|
175
168
|
# methods.
|
@@ -285,10 +278,6 @@ module Lafcadio
|
|
285
278
|
class DomainObject
|
286
279
|
@@subclass_records = Hash.new do |h, k| h[k] = SubclassRecord.new( k ); end
|
287
280
|
|
288
|
-
COMMIT_ADD = 1
|
289
|
-
COMMIT_EDIT = 2
|
290
|
-
COMMIT_DELETE = 3
|
291
|
-
|
292
281
|
include DomainComparable
|
293
282
|
|
294
283
|
# Shortcut method for retrieving one domain object.
|
@@ -307,7 +296,9 @@ module Lafcadio
|
|
307
296
|
# Returns every committed instance of the domain class.
|
308
297
|
#
|
309
298
|
# User.all # => all users
|
310
|
-
def self.all
|
299
|
+
def self.all( opts = {} )
|
300
|
+
ObjectStore.get_object_store.all( self, opts )
|
301
|
+
end
|
311
302
|
|
312
303
|
def self.all_fields # :nodoc:
|
313
304
|
self_and_concrete_superclasses.map { |a_class|
|
@@ -316,7 +307,7 @@ module Lafcadio
|
|
316
307
|
end
|
317
308
|
|
318
309
|
def self.class_field(fieldName) #:nodoc:
|
319
|
-
self.class_fields.find { |field| field.name == fieldName }
|
310
|
+
self.class_fields.find { |field| field.name == fieldName.to_s }
|
320
311
|
end
|
321
312
|
|
322
313
|
def self.class_fields #:nodoc:
|
@@ -381,10 +372,7 @@ module Lafcadio
|
|
381
372
|
#
|
382
373
|
# class LotsOfBooleans < Lafcadio::DomainObject
|
383
374
|
# default_field_setup_hash(
|
384
|
-
# Lafcadio::BooleanField,
|
385
|
-
# {
|
386
|
-
# 'enum_type' => Lafcadio::BooleanField::ENUMS_CAPITAL_YES_NO
|
387
|
-
# }
|
375
|
+
# Lafcadio::BooleanField, { 'enum_type' => :capital_yes_no }
|
388
376
|
# )
|
389
377
|
# booleans 'this', 'that', 'the_other', 'and_another_one',
|
390
378
|
# 'this_one_too'
|
@@ -470,7 +458,7 @@ module Lafcadio
|
|
470
458
|
if arg.is_a? Fixnum
|
471
459
|
ObjectStore.get_object_store.get( self, *args )
|
472
460
|
else
|
473
|
-
qry = Query.new( self,
|
461
|
+
qry = Query.new( self, :group_functions => [ :count ] )
|
474
462
|
ObjectStore.get_object_store.group_query qry
|
475
463
|
end
|
476
464
|
else
|
@@ -557,6 +545,10 @@ module Lafcadio
|
|
557
545
|
#
|
558
546
|
# the_one_user = User.only
|
559
547
|
def self.only; all.only; end
|
548
|
+
|
549
|
+
def self.postgres_pk_id_seq
|
550
|
+
"#{ table_name }_#{ sql_primary_key_name }_seq"
|
551
|
+
end
|
560
552
|
|
561
553
|
def self.require_domain_file( typeString ) # :nodoc:
|
562
554
|
typeString =~ /([^\:]*)$/
|
@@ -652,14 +644,15 @@ module Lafcadio
|
|
652
644
|
|
653
645
|
def self.try_load_xml_parser # :nodoc:
|
654
646
|
require 'lafcadio/domain'
|
655
|
-
dirName = LafcadioConfig.new['classDefinitionDir']
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
647
|
+
if ( dirName = LafcadioConfig.new['classDefinitionDir'] )
|
648
|
+
xmlFileName = self.basename + '.xml'
|
649
|
+
xmlPath = File.join( dirName, xmlFileName )
|
650
|
+
begin
|
651
|
+
xml = File.open( xmlPath ) do |f| f.gets( nil ); end
|
652
|
+
ClassDefinitionXmlParser.new( self, xml )
|
653
|
+
rescue Errno::ENOENT
|
654
|
+
# no xml file, so no @xmlParser
|
655
|
+
end
|
663
656
|
end
|
664
657
|
end
|
665
658
|
|
data/lib/lafcadio/mock.rb
CHANGED
@@ -9,32 +9,27 @@ module Lafcadio
|
|
9
9
|
@objects = {}
|
10
10
|
@next_pk_ids = {}
|
11
11
|
@queries = []
|
12
|
+
@transaction = nil
|
12
13
|
end
|
13
14
|
|
14
15
|
def all( domain_class )
|
15
16
|
@objects[domain_class] ? @objects[domain_class].values : []
|
16
17
|
end
|
17
18
|
|
18
|
-
def select_dobjs(query)
|
19
|
-
@queries << query
|
20
|
-
domain_class = query.domain_class
|
21
|
-
objects = []
|
22
|
-
all( domain_class ).each { |dbObj|
|
23
|
-
objects << dbObj if query.dobj_satisfies?( dbObj )
|
24
|
-
}
|
25
|
-
query.order_and_limit_collection objects
|
26
|
-
end
|
27
|
-
|
28
19
|
def commit(db_object)
|
29
20
|
if db_object.pk_id and !db_object.pk_id.is_a?( Integer )
|
30
21
|
raise ArgumentError
|
31
22
|
end
|
32
|
-
|
33
|
-
|
34
|
-
objects_by_domain_class.delete( db_object.pk_id )
|
23
|
+
if @transaction
|
24
|
+
@transaction << db_object
|
35
25
|
else
|
36
|
-
|
37
|
-
|
26
|
+
objects_by_domain_class = objects_by_domain_class db_object.domain_class
|
27
|
+
if db_object.delete
|
28
|
+
objects_by_domain_class.delete( db_object.pk_id )
|
29
|
+
else
|
30
|
+
object_pk_id = pre_commit_pk_id( db_object )
|
31
|
+
objects_by_domain_class[object_pk_id] = db_object
|
32
|
+
end
|
38
33
|
end
|
39
34
|
end
|
40
35
|
|
@@ -79,10 +74,37 @@ module Lafcadio
|
|
79
74
|
@queries.select { |qry| qry.to_sql == sql }.size
|
80
75
|
end
|
81
76
|
|
77
|
+
def select_dobjs(query)
|
78
|
+
@queries << query
|
79
|
+
domain_class = query.domain_class
|
80
|
+
objects = []
|
81
|
+
all( domain_class ).each { |dbObj|
|
82
|
+
objects << dbObj if query.dobj_satisfies?( dbObj )
|
83
|
+
}
|
84
|
+
query.order_and_limit_collection objects
|
85
|
+
end
|
86
|
+
|
82
87
|
def set_next_pk_id( domain_class, npi )
|
83
88
|
@next_pk_ids = {} unless @next_pk_ids
|
84
89
|
@next_pk_ids[ domain_class ] = npi
|
85
90
|
end
|
91
|
+
|
92
|
+
def transaction( action )
|
93
|
+
tr = MockDbBridge::Transaction.new
|
94
|
+
@transaction = tr
|
95
|
+
begin
|
96
|
+
action.call tr
|
97
|
+
@transaction = nil
|
98
|
+
tr.each do |dobj_to_commit| commit( dobj_to_commit ); end
|
99
|
+
rescue RollbackError; end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Transaction < Array
|
103
|
+
def rollback; raise RollbackError; end
|
104
|
+
end
|
105
|
+
|
106
|
+
class RollbackError < StandardError #:nodoc:
|
107
|
+
end
|
86
108
|
end
|
87
109
|
|
88
110
|
# Externally, the MockObjectStore looks and acts exactly like the ObjectStore,
|