lafcadio 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/lafcadio.rb CHANGED
@@ -16,7 +16,7 @@
16
16
  # http://lafcadio.rubyforge.org/tutorial.html.
17
17
 
18
18
  module Lafcadio
19
- Version = "0.9.1"
19
+ Version = "0.9.2"
20
20
 
21
21
  require 'lafcadio/depend'
22
22
  require 'lafcadio/domain'
data/lib/lafcadio.rb~ CHANGED
@@ -16,7 +16,7 @@
16
16
  # http://lafcadio.rubyforge.org/tutorial.html.
17
17
 
18
18
  module Lafcadio
19
- Version = "0.9.0"
19
+ Version = "0.9.1"
20
20
 
21
21
  require 'lafcadio/depend'
22
22
  require 'lafcadio/domain'
@@ -652,14 +652,15 @@ module Lafcadio
652
652
 
653
653
  def self.try_load_xml_parser # :nodoc:
654
654
  require 'lafcadio/domain'
655
- dirName = LafcadioConfig.new['classDefinitionDir']
656
- xmlFileName = self.basename + '.xml'
657
- xmlPath = File.join( dirName, xmlFileName )
658
- begin
659
- xml = File.open( xmlPath ) do |f| f.gets( nil ); end
660
- ClassDefinitionXmlParser.new( self, xml )
661
- rescue Errno::ENOENT
662
- # no xml file, so no @xmlParser
655
+ if ( dirName = LafcadioConfig.new['classDefinitionDir'] )
656
+ xmlFileName = self.basename + '.xml'
657
+ xmlPath = File.join( dirName, xmlFileName )
658
+ begin
659
+ xml = File.open( xmlPath ) do |f| f.gets( nil ); end
660
+ ClassDefinitionXmlParser.new( self, xml )
661
+ rescue Errno::ENOENT
662
+ # no xml file, so no @xmlParser
663
+ end
663
664
  end
664
665
  end
665
666
 
@@ -17,7 +17,7 @@ module Lafcadio
17
17
  if className != ''
18
18
  fieldClass = Class.by_name( 'Lafcadio::' + className )
19
19
  register_name( name )
20
- field = fieldClass.instantiate_from_xml( @domain_class, fieldElt )
20
+ field = fieldClass.create_from_xml( @domain_class, fieldElt )
21
21
  set_field_attributes( field, fieldElt )
22
22
  else
23
23
  msg = "Couldn't find field class '#{ className }' for field " +
@@ -44,7 +44,7 @@ module Lafcadio
44
44
  fieldAttr = []
45
45
  fieldAttr << FieldAttribute.new( 'size', FieldAttribute::INTEGER )
46
46
  fieldAttr << FieldAttribute.new( 'unique', FieldAttribute::BOOLEAN )
47
- fieldAttr << FieldAttribute.new( 'not_null', FieldAttribute::BOOLEAN )
47
+ fieldAttr << FieldAttribute.new( 'not_nil', FieldAttribute::BOOLEAN )
48
48
  fieldAttr << FieldAttribute.new( 'enum_type', FieldAttribute::ENUM,
49
49
  BooleanField )
50
50
  fieldAttr << FieldAttribute.new( 'enums', FieldAttribute::HASH )
@@ -120,6 +120,8 @@ module Lafcadio
120
120
  class InvalidDataError < ArgumentError; end
121
121
  end
122
122
 
123
+ # DomainComparable is used by DomainObject and DomainObjectProxy to define
124
+ # comparisons.
123
125
  module DomainComparable
124
126
  include Comparable
125
127
 
@@ -137,6 +139,8 @@ module Lafcadio
137
139
  end
138
140
  end
139
141
 
142
+ # Two DomainObjects or DomainObjectProxies are eql? if they have the same
143
+ # +domain_class+ and the same +pk_id+.
140
144
  def eql?( otherObj ); self == otherObj; end
141
145
 
142
146
  def hash; "#{ self.class.name } #{ pk_id }".hash; end
@@ -146,24 +150,37 @@ module Lafcadio
146
150
  # of DomainObject.
147
151
  #
148
152
  # = Defining fields
149
- # There are two ways to define the fields of a DomainObject subclass.
150
- # 1. Defining fields in an XML file. To do this,
151
- # 1. Set one directory to contain all your XML files, by setting
152
- # +classDefinitionDir+ in your LafcadioConfig file.
153
- # 2. Write one XML file per domain class. For example, a User.xml file
154
- # might look like:
155
- # <lafcadio_class_definition name="User">
156
- # <field name="lastName" class="StringField"/>
157
- # <field name="email" class="StringField"/>
158
- # <field name="password" class="StringField"/>
159
- # <field name="birthday" class="DateField"/>
160
- # </lafcadio_class_definition>
161
- # 2. Overriding DomainObject.get_class_fields. The method should return an Array
162
- # of instances of ObjectField or its children. The order is unimportant.
153
+ # There are three ways to define the fields of a DomainObject subclass.
154
+ # 1. <b>One-line field definitions</b>: When defining the class, add fields
155
+ # with class methods like so:
156
+ # class User < Lafcadio::DomainObject
157
+ # string 'lastName'
158
+ # email 'email'
159
+ # string 'password'
160
+ # date 'birthday'
161
+ # end
162
+ # These can also be pluralized:
163
+ # class User < Lafcadio::DomainObject
164
+ # strings 'lastName', 'password'
165
+ # email 'email'
166
+ # date 'birthday'
167
+ # end
168
+ # The class methods you can use are +blob+, +boolean+, +date+,
169
+ # +date_time+, +domain_object+, +email+, +enum+, +float+, +integer+,
170
+ # +month+, +state+, +string+, +text_list+. These correspond to BlobField,
171
+ # BooleanField, DateField, DateTimeField, DomainObjectField, EmailField,
172
+ # EnumField, FloatField, IntegerField, MonthField, StateField,
173
+ # StringField, and TextListField, respectively. Consult their individual
174
+ # RDoc entries for more on how to parameterize them through the class
175
+ # methods.
176
+ # 2. <b>Overriding DomainObject.get_class_fields</b>: The method should
177
+ # return an Array of instances of ObjectField or its children. If you use
178
+ # this method, make sure to call the superclass (this is needed to define
179
+ # the primary key field). The order of fields in the Array is unimportant.
163
180
  # For example:
164
181
  # class User < DomainObject
165
182
  # def User.get_class_fields
166
- # fields = []
183
+ # fields = super
167
184
  # fields << StringField.new(self, 'firstName')
168
185
  # fields << StringField.new(self, 'lastName')
169
186
  # fields << StringField.new(self, 'email')
@@ -172,63 +189,89 @@ module Lafcadio
172
189
  # fields
173
190
  # end
174
191
  # end
192
+ # This method is probably not worth the trouble unless you end up defining
193
+ # your own field classes for some reason.
194
+ # 3. <b>Defining fields in an XML file</b>: Note that this method may be
195
+ # removed in the future. To do this:
196
+ # 1. Set one directory to contain all your XML files, by setting
197
+ # +classDefinitionDir+ in your LafcadioConfig file.
198
+ # 2. Write one XML file per domain class. For example, a User.xml file
199
+ # might look like:
200
+ # <lafcadio_class_definition name="User">
201
+ # <field name="lastName" class="StringField"/>
202
+ # <field name="email" class="StringField"/>
203
+ # <field name="password" class="StringField"/>
204
+ # <field name="birthday" class="DateField"/>
205
+ # </lafcadio_class_definition>
175
206
  #
176
207
  # = Setting and retrieving fields
177
208
  # Once your fields are defined, you can create an instance by passing in a
178
209
  # hash of field names and values.
179
- # john = User.new( 'firstName' => 'John', 'lastName' => 'Doe',
180
- # 'email' => 'john.doe@email.com',
181
- # 'password' => 'my_password',
182
- # 'birthday' => tenYearsAgo )
210
+ #
211
+ # john = User.new(
212
+ # :firstName => 'John', :lastName => 'Doe',
213
+ # :email => 'john.doe@email.com', :password => 'my_password',
214
+ # :birthday => Date.new( 1979, 1, 15 )
215
+ # )
183
216
  #
184
217
  # You can read and write these fields like normal instance attributes.
185
- # john.email => 'john.doe@email.com'
218
+ # john.email # => 'john.doe@email.com'
186
219
  # john.email = 'john.doe@mail.email.com'
187
220
  #
188
221
  # If your domain class has fields that refer to other domain classes, or even
189
- # to another row in the same table, you can use a DomainObjectField to express the
190
- # relation.
191
- # <lafcadio_class_definition name="Message">
192
- # <field name="subject" class="StringField" />
193
- # <field name="body" class="StringField" />
194
- # <field name="author" class="DomainObjectField" linked_type="User" />
195
- # <field name="recipient" class="DomainObjectField" linked_type="User" />
196
- # <field name="dateSent" class="DateField" />
197
- # </lafcadio_class_definition>
198
- #
199
- # msg = Message.new( 'subject' => 'hi there',
200
- # 'body' => 'You wanna go to the movies on Saturday?',
201
- # 'author' => john, 'recipient' => jane,
202
- # 'dateSent' => Date.today )
222
+ # to another row in the same table, you can use a DomainObjectField to
223
+ # express the relation.
224
+ #
225
+ # class Message < Lafcadio::DomainObject
226
+ # strings 'subject', 'body'
227
+ # domain_object User, 'author'
228
+ # domain_object User, 'recipient'
229
+ # date 'date_sent'
230
+ # end
231
+ #
232
+ # msg = Message.new(
233
+ # :subject => 'hi there',
234
+ # :body => 'You wanna go to the movies on Saturday?',
235
+ # :author => john, :recipient => jane, :dateSent => Date.today
236
+ # )
203
237
  #
204
238
  # = pk_id and committing
205
- # Lafcadio requires that each table has a numeric primary key. It assumes that
206
- # this key is named +pk_id+ in the database, though that can be overridden.
239
+ # Lafcadio requires that each table has a numeric primary key. It assumes
240
+ # that this key is named +pk_id+ in the database, though that can be
241
+ # overridden.
207
242
  #
208
- # When you create a domain object by calling new, you should not assign a
209
- # +pk_id+ to the new instance. The pk_id will automatically be set when you
210
- # commit the object by calling DomainObject#commit.
243
+ # When you create a domain object by calling DomainObject.new, you should not
244
+ # assign a +pk_id+ to the new instance. The pk_id will automatically be set
245
+ # when you commit the object by calling DomainObject#commit.
211
246
  #
212
- # However, you may want to manually set +pk_id+ when setting up a test case, so
213
- # you can ensure that a domain object has a given primary key.
247
+ # However, you may want to manually set +pk_id+ when setting up a test case,
248
+ # so you can ensure that a domain object has a given primary key.
214
249
  #
215
250
  # = Naming assumptions, and how to override them
216
251
  # By default, Lafcadio assumes that every domain object is indexed by the
217
252
  # field +pk_id+ in the database schema. If you're dealing with a table that
218
- # uses a different field name, override DomainObject.sql_primary_key_name.
253
+ # uses a different field name, call DomainObject.sql_primary_key_name.
219
254
  # However, you will always use +pk_id+ in your Ruby code.
220
255
  #
221
- # Lafcadio assumes that a domain class corresponds to a table whose name is
222
- # the plural of the class name, and whose first letter is lowercase. A User
223
- # class is assumed to be stored in a "users" table, while a ProductCategory
224
- # class is assumed to be stored in a "productCategories" table. Override
256
+ # Lafcadio assumes that a domain class corresponds to a table whose name is
257
+ # the pluralized, lower-case, underscored version of the class name. A User
258
+ # class is assumed to be stored in a "users" table, while a ProductCategory
259
+ # class is assumed to be stored in a "product_categories" table. Call
225
260
  # DomainObject.table_name to override this behavior.
226
261
  #
262
+ # class LegacyThing < Lafcadio::DomainObject
263
+ # string 'some_field'
264
+ # sql_primary_key_name 'some_legacy_id'
265
+ # table_name 'some_legacy_table'
266
+ # end
267
+ # thing = LegacyThing[9909]
268
+ # thing.pk_id # => 9909
269
+ #
227
270
  # = Inheritance
228
271
  # Domain classes can inherit from other domain classes; they have all the
229
272
  # fields of any concrete superclasses plus any new fields defined for
230
273
  # themselves. You can use normal inheritance to define this:
231
- # class User < DomainObject
274
+ # class User < Lafcadio::DomainObject
232
275
  # ...
233
276
  # end
234
277
  #
@@ -248,6 +291,9 @@ module Lafcadio
248
291
 
249
292
  include DomainComparable
250
293
 
294
+ # Shortcut method for retrieving one domain object.
295
+ #
296
+ # User[7356] # => user with the pk_id 7536
251
297
  def self.[]( pk_id ); get( pk_id ); end
252
298
 
253
299
  def self.abstract_subclass?( a_class ) #:nodoc:
@@ -258,11 +304,12 @@ module Lafcadio
258
304
  [ MapObject ]
259
305
  end
260
306
 
261
- def self.all; ObjectStore.get_object_store.get_all( self ); end
307
+ # Returns every committed instance of the domain class.
308
+ #
309
+ # User.all # => all users
310
+ def self.all; ObjectStore.get_object_store.all( self ); end
262
311
 
263
- # Returns an array of all fields defined for this class and all concrete
264
- # superclasses.
265
- def self.all_fields
312
+ def self.all_fields # :nodoc:
266
313
  self_and_concrete_superclasses.map { |a_class|
267
314
  a_class.class_fields
268
315
  }.flatten
@@ -286,7 +333,7 @@ module Lafcadio
286
333
  subclass_record.fields
287
334
  end
288
335
 
289
- def self.create_field( field_class, *args )
336
+ def self.create_field( field_class, *args ) #:nodoc:
290
337
  subclass_record.maybe_init_fields
291
338
  att_hash = create_field_att_hash( field_class, *args )
292
339
  field = field_class.create_with_args( self, att_hash )
@@ -328,6 +375,20 @@ module Lafcadio
328
375
  create_field( field_class, arg ) unless arg.nil?
329
376
  end
330
377
 
378
+ # Sets a default setup hash for a field of a certain class. Useful for
379
+ # mapping domain classes with lots of fields and unusual field
380
+ # configurations.
381
+ #
382
+ # class LotsOfBooleans < Lafcadio::DomainObject
383
+ # default_field_setup_hash(
384
+ # Lafcadio::BooleanField,
385
+ # {
386
+ # 'enum_type' => Lafcadio::BooleanField::ENUMS_CAPITAL_YES_NO
387
+ # }
388
+ # )
389
+ # booleans 'this', 'that', 'the_other', 'and_another_one',
390
+ # 'this_one_too'
391
+ # end
331
392
  def self.default_field_setup_hash( field_class, hash )
332
393
  subclass_record.default_field_setup_hash[field_class] = hash
333
394
  end
@@ -357,11 +418,16 @@ module Lafcadio
357
418
  end
358
419
  end
359
420
 
421
+ # Tests whether a given domain object exists.
422
+ #
423
+ # User.exist?( 8280 ) # => returns true iff there's a User 8280
424
+ # User.exist?( 'Hwang', :lastName ) # => returns true iff there's a User
425
+ # # with the last name 'Hwang'
360
426
  def self.exist?( search_term, field_name = :pk_id )
361
427
  query = Query.infer( self ) { |dobj|
362
428
  dobj.send( field_name ).equals( search_term )
363
429
  }
364
- !ObjectStore.get_object_store.get_subset( query ).empty?
430
+ !ObjectStore.get_object_store.query( query ).empty?
365
431
  end
366
432
 
367
433
  def self.field( fieldName ) #:nodoc:
@@ -374,27 +440,53 @@ module Lafcadio
374
440
  field
375
441
  end
376
442
 
443
+ # Returns the first domain object it can find.
444
+ #
445
+ # very_first_user = User.first
377
446
  def self.first; all.first; end
378
-
447
+
448
+ # This class method has a few uses, depending on how you use it.
449
+ # 1. Pass DomainObject.get a block in order to run a complex query:
450
+ # adult_hwangs = User.get { |user|
451
+ # user.lastName.equals( 'Hwang' ) &
452
+ # user.birthday.lte( Date.today - ( 365 * 18 ) )
453
+ # }
454
+ # See query.rb for more information about how to form these
455
+ # queries.
456
+ # 2. Pass it a simple search term and a field name to retrieve every domain
457
+ # object matching the term. The field name will default to +pk_id+.
458
+ # hwangs = User.get( 'Hwang', :lastName )
459
+ # user123 = User.get( 123 ).first
460
+ # 3. Pass it a { :group => :count } hash to retrieve a count result hash.
461
+ # This interface is fairly new and may be refined (that is, changed) in
462
+ # the future.
463
+ # num_users = User.get( :group => :count ).first[:count]
379
464
  def self.get( *args )
380
465
  if block_given?
381
466
  query = Query.infer( self ) { |dobj| yield( dobj ) }
382
- ObjectStore.get_object_store.get_subset( query )
467
+ ObjectStore.get_object_store.query( query )
383
468
  elsif args.size == 1
384
469
  arg = args.first
385
470
  if arg.is_a? Fixnum
386
471
  ObjectStore.get_object_store.get( self, *args )
387
472
  else
388
473
  qry = Query.new( self, nil, { :group_functions => [ :count ] } )
389
- ObjectStore.get_object_store.query qry
474
+ ObjectStore.get_object_store.group_query qry
390
475
  end
391
476
  else
392
- ObjectStore.get_object_store.get_filtered( self.name, *args )
477
+ search_term = args.shift
478
+ field_name = (
479
+ args.shift or link_field( search_term.domain_class ).name
480
+ )
481
+ qry = Query::Equals.new( field_name, search_term, self )
482
+ ObjectStore.get_object_store.query qry
393
483
  end
394
484
  end
395
485
 
396
486
  # Returns an Array of ObjectField instances for this domain class, parsing
397
- # them from XML if necessary.
487
+ # them from XML if necessary. You can override this to define a domain
488
+ # class' fields, though it will probably just be simpler to use one-line
489
+ # class methods instead.
398
490
  def self.get_class_fields
399
491
  if self.methods( false ).include?( 'get_class_fields' )
400
492
  [ subclass_record.pk_field ]
@@ -416,6 +508,9 @@ module Lafcadio
416
508
  superclass != DomainObject and !abstract_subclass?( superclass )
417
509
  end
418
510
 
511
+ # Returns the last domain object.
512
+ #
513
+ # last_msg = Message.last
419
514
  def self.last; all.last; end
420
515
 
421
516
  def self.link_field( linked_domain_class ) # :nodoc:
@@ -457,9 +552,13 @@ module Lafcadio
457
552
  end
458
553
  end
459
554
 
555
+ # Returns the only committed instance of the domain class. Will raise an
556
+ # IndexError if there are 0, or more than 1, domain objects.
557
+ #
558
+ # the_one_user = User.only
460
559
  def self.only; all.only; end
461
560
 
462
- def self.require_domain_file( typeString )
561
+ def self.require_domain_file( typeString ) # :nodoc:
463
562
  typeString =~ /([^\:]*)$/
464
563
  fileName = $1
465
564
  domain_dirs.each { |domainDir|
@@ -485,7 +584,7 @@ module Lafcadio
485
584
  classes
486
585
  end
487
586
 
488
- def self.singleton_method_added( symbol )
587
+ def self.singleton_method_added( symbol ) # :nodoc:
489
588
  if symbol.id2name == 'sql_primary_key_name' && self < DomainObject
490
589
  begin
491
590
  field( 'pk_id' ).db_field_name = self.send( symbol )
@@ -495,23 +594,47 @@ module Lafcadio
495
594
  end
496
595
  end
497
596
 
498
- # Returns the name of the primary key in the database, retrieving it from
499
- # the class definition XML if necessary.
597
+ # If +set_db_field_name+ is nil, this will return the sql name of the
598
+ # primary key. If +set_db_field_name+ isn't nil, it will set the sql name.
599
+ #
600
+ # class User < Lafcadio::DomainObject
601
+ # string 'firstNames'
602
+ # end
603
+ # User.sql_primary_key_name # => 'pk_id'
604
+ # class User < Lafcadio::DomainObject
605
+ # sql_primary_key_name 'some_other_id'
606
+ # end
607
+ # User.sql_primary_key_name # => 'some_other_id'
500
608
  def self.sql_primary_key_name( set_db_field_name = nil )
501
609
  field( 'pk_id' ).db_field_name = set_db_field_name if set_db_field_name
502
610
  field( 'pk_id' ).db_field_name
503
611
  end
504
612
 
505
- def self.subclass_record; @@subclass_records[self]; end
613
+ def self.subclass_record # :nodoc:
614
+ @@subclass_records[self]
615
+ end
506
616
 
507
617
  def self.subclasses #:nodoc:
508
618
  @@subclass_records.keys
509
619
  end
510
620
 
511
- # Returns the table name, which is assumed to be the domain class name
512
- # pluralized, and with the first letter lowercase. A User class is
513
- # assumed to be stored in a "users" table, while a ProductCategory class is
514
- # assumed to be stored in a "productCategories" table.
621
+ # If +set_table_name+ is nil, DomainObject.table_name will return the table
622
+ # name. Lafcadio assumes that a domain class corresponds to a table whose
623
+ # name is the pluralized, lower-case, underscored version of the class
624
+ # name. A User class is assumed to be stored in a "users" table, while a
625
+ # ProductCategory class is assumed to be stored in a "product_categories"
626
+ # table.
627
+ #
628
+ # If +set_table_name+ is not nil, this will set the table name.
629
+ #
630
+ # class User < Lafcadio::DomainObject
631
+ # string 'firstNames'
632
+ # end
633
+ # User.table_name # => 'users'
634
+ # class User < Lafcadio::DomainObject
635
+ # table_name 'some_table'
636
+ # end
637
+ # User.table_name # => 'some_table'
515
638
  def self.table_name( set_table_name = nil )
516
639
  if set_table_name
517
640
  @table_name = set_table_name
@@ -527,7 +650,7 @@ module Lafcadio
527
650
  end
528
651
  end
529
652
 
530
- def self.try_load_xml_parser
653
+ def self.try_load_xml_parser # :nodoc:
531
654
  require 'lafcadio/domain'
532
655
  dirName = LafcadioConfig.new['classDefinitionDir']
533
656
  xmlFileName = self.basename + '.xml'
@@ -544,12 +667,14 @@ module Lafcadio
544
667
  attr_reader :delete
545
668
  protected :fields_set, :field_values
546
669
 
547
- # fieldHash should contain key-value associations for the different
670
+ # +field_hash+ should contain key-value associations for the different
548
671
  # fields of this domain class. For example, instantiating a User class
549
672
  # might look like:
550
673
  #
551
- # User.new( 'firstNames' => 'John', 'lastName' => 'Doe',
552
- # 'email' => 'john.doe@email.com', 'password' => 'l33t' )
674
+ # User.new(
675
+ # 'firstNames' => 'John', 'lastName' => 'Doe',
676
+ # 'email' => 'john.doe@email.com', 'password' => 'l33t'
677
+ # )
553
678
  #
554
679
  # In normal usage any code you write that creates a domain object will not
555
680
  # define the +pk_id+ field. The system assumes that a domain object with an
@@ -558,11 +683,11 @@ module Lafcadio
558
683
  #
559
684
  # If you're creating mock objects for unit tests, you can explicitly set
560
685
  # the +pk_id+ to represent objects that already exist in the database.
561
- def initialize(fieldHash)
562
- fieldHash = preprocess_field_hash fieldHash
686
+ def initialize( field_hash )
687
+ field_hash = preprocess_field_hash field_hash
563
688
  @field_values = {}
564
689
  @fields_set = []
565
- @original_values = ReadOnlyHash.new @fieldHash
690
+ reset_original_values_hash @fieldHash
566
691
  check_fields = LafcadioConfig.new()['checkFields']
567
692
  verify if %w( onInstantiate onAllStates ).include?( check_fields )
568
693
  end
@@ -589,6 +714,8 @@ module Lafcadio
589
714
  @delete = value
590
715
  end
591
716
 
717
+ # Deletes a domain object, committing the delete to the database
718
+ # immediately.
592
719
  def delete!
593
720
  self.delete = true
594
721
  commit
@@ -618,11 +745,10 @@ module Lafcadio
618
745
  elsif ( field = getter_field( methId ) )
619
746
  field_value( field )
620
747
  else
621
- new_symbol = ( 'get_' + methId.id2name ).to_sym
622
748
  object_store = ObjectStore.get_object_store
623
- if object_store.respond_to? new_symbol
749
+ if object_store.respond_to? methId
624
750
  args = [ self ].concat args
625
- object_store.send( 'get_' + methId.id2name, *args )
751
+ object_store.send( methId, *args )
626
752
  else
627
753
  super( methId, *args )
628
754
  end
@@ -635,7 +761,7 @@ module Lafcadio
635
761
  nil
636
762
  end
637
763
 
638
- def preprocess_field_hash( fieldHash )
764
+ def preprocess_field_hash( fieldHash ) # :nodoc:
639
765
  if fieldHash.is_a? Hash
640
766
  fieldHash.keys.each { |key|
641
767
  if self.class.field( key.to_s ).nil?
@@ -655,6 +781,10 @@ module Lafcadio
655
781
  nil
656
782
  end
657
783
 
784
+ def reset_original_values_hash( f = @field_values ) #:nodoc:
785
+ @original_values = ReadOnlyHash.new( f.clone )
786
+ end
787
+
658
788
  def set_field_value( field, value ) #:nodoc:
659
789
  if (
660
790
  field.is_a?( DomainObjectField ) and
@@ -678,11 +808,18 @@ module Lafcadio
678
808
  end
679
809
  end
680
810
 
811
+ # Updates a domain object and commits the changes to the database
812
+ # immediately.
813
+ #
814
+ # user99 = User[99]
815
+ # user99.update!( :firstNames => 'Bill', :password => 'n3wp4ssw0rd' )
681
816
  def update!( changes )
682
817
  changes.each do |sym, value| self.send( sym.to_s + '=', value ); end
683
818
  commit
684
819
  end
685
820
 
821
+ # If you're running against a MockObjectStore, this will verify each field
822
+ # and raise an error if there's any invalid fields.
686
823
  def verify
687
824
  if ObjectStore.mock?
688
825
  self.class.get_class_fields.each { |field|
@@ -691,11 +828,11 @@ module Lafcadio
691
828
  end
692
829
  end
693
830
 
694
- class ReadOnlyHash < DelegateClass( Hash )
831
+ class ReadOnlyHash < DelegateClass( Hash ) # :nodoc:
695
832
  def []=( key, val ); raise NoMethodError; end
696
833
  end
697
834
 
698
- class SubclassRecord
835
+ class SubclassRecord # :nodoc:
699
836
  attr_accessor :default_field_setup_hash, :fields, :sql_primary_key
700
837
 
701
838
  def initialize( subclass )
@@ -720,11 +857,11 @@ module Lafcadio
720
857
 
721
858
  # Any domain class that is used mostly to map between two other domain
722
859
  # classes should be a subclass of MapObject. Subclasses of MapObject should
723
- # override MapObject.mappedTypes, returning a two-element array containing
860
+ # override MapObject.mapped_classes, returning a two-element array containing
724
861
  # the domain classes that the map object maps between.
725
862
  class MapObject < DomainObject
726
863
  def self.other_mapped_type(firstType) #:nodoc:
727
- mt = mappedTypes.clone
864
+ mt = mapped_classes.clone
728
865
  mt.delete firstType
729
866
  mt.only
730
867
  end