lafcadio 0.9.2 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- 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,
|