lafcadio 0.6.1 → 0.6.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.6.1"
19
+ Version = "0.6.2"
20
20
 
21
21
  require 'lafcadio/dateTime'
22
22
  require 'lafcadio/depend'
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.6.0"
19
+ Version = "0.6.1"
20
20
 
21
21
  require 'lafcadio/dateTime'
22
22
  require 'lafcadio/depend'
@@ -1,3 +1,4 @@
1
+ require 'extensions/module'
1
2
  require 'lafcadio/objectField'
2
3
  require 'lafcadio/util'
3
4
  require 'rexml/document'
@@ -348,7 +349,7 @@ module Lafcadio
348
349
  []
349
350
  end
350
351
  end
351
-
352
+
352
353
  def self.get_field( fieldName ) #:nodoc:
353
354
  aDomainClass = self
354
355
  field = nil
@@ -359,7 +360,7 @@ module Lafcadio
359
360
  if field
360
361
  field
361
362
  else
362
- errStr = "Couldn't find field \"#{ field }\" in " +
363
+ errStr = "Couldn't find field \"#{ fieldName }\" in " +
363
364
  "#{ self } domain class"
364
365
  raise( MissingError, errStr, caller )
365
366
  end
@@ -393,8 +394,7 @@ module Lafcadio
393
394
 
394
395
  def self.method_missing( methodId, *args ) #:nodoc:
395
396
  method_name = methodId.id2name
396
- maybe_field_class_name = ( method_name.gsub( /^(.)/ ) { $&.upcase } ) +
397
- 'Field'
397
+ maybe_field_class_name = method_name.underscore_to_camel_case + 'Field'
398
398
  field_class = Lafcadio.const_get( maybe_field_class_name )
399
399
  create_field( field_class, args[0], args[1] || {} )
400
400
  end
@@ -0,0 +1,639 @@
1
+ require 'extensions/module'
2
+ require 'lafcadio/objectField'
3
+ require 'lafcadio/util'
4
+ require 'rexml/document'
5
+
6
+ module Lafcadio
7
+ class ClassDefinitionXmlParser # :nodoc: all
8
+ def initialize( domain_class, xml )
9
+ @domain_class = domain_class
10
+ @xmlDocRoot = REXML::Document.new( xml ).root
11
+ @namesProcessed = {}
12
+ end
13
+
14
+ def get_class_field( fieldElt )
15
+ className = fieldElt.attributes['class'].to_s
16
+ name = fieldElt.attributes['name']
17
+ if className != ''
18
+ fieldClass = Class.by_name( 'Lafcadio::' + className )
19
+ register_name( name )
20
+ field = fieldClass.instantiate_from_xml( @domain_class, fieldElt )
21
+ set_field_attributes( field, fieldElt )
22
+ else
23
+ msg = "Couldn't find field class '#{ className }' for field " +
24
+ "'#{ name }'"
25
+ raise( MissingError, msg, caller )
26
+ end
27
+ field
28
+ end
29
+
30
+ def get_class_fields
31
+ namesProcessed = {}
32
+ pk_field = PrimaryKeyField.new( @domain_class )
33
+ if ( spkn = @xmlDocRoot.attributes['sql_primary_key_name'] )
34
+ pk_field.db_field_name = spkn
35
+ end
36
+ fields = [ pk_field ]
37
+ @xmlDocRoot.elements.each('field') { |fieldElt|
38
+ fields << get_class_field( fieldElt )
39
+ }
40
+ fields
41
+ end
42
+
43
+ def possible_field_attributes
44
+ fieldAttr = []
45
+ fieldAttr << FieldAttribute.new( 'size', FieldAttribute::INTEGER )
46
+ fieldAttr << FieldAttribute.new( 'unique', FieldAttribute::BOOLEAN )
47
+ fieldAttr << FieldAttribute.new( 'not_null', FieldAttribute::BOOLEAN )
48
+ fieldAttr << FieldAttribute.new( 'enum_type', FieldAttribute::ENUM,
49
+ BooleanField )
50
+ fieldAttr << FieldAttribute.new( 'enums', FieldAttribute::HASH )
51
+ fieldAttr << FieldAttribute.new( 'range', FieldAttribute::ENUM,
52
+ DateField )
53
+ fieldAttr << FieldAttribute.new( 'large', FieldAttribute::BOOLEAN )
54
+ end
55
+
56
+ def register_name( name )
57
+ raise InvalidDataError if @namesProcessed[name]
58
+ @namesProcessed[name] = true
59
+ end
60
+
61
+ def set_field_attributes( field, fieldElt )
62
+ possible_field_attributes.each { |fieldAttr|
63
+ fieldAttr.maybe_set_field_attr( field, fieldElt )
64
+ }
65
+ end
66
+
67
+ def table_name
68
+ @xmlDocRoot.attributes['table_name']
69
+ end
70
+
71
+ class FieldAttribute
72
+ INTEGER = 1
73
+ BOOLEAN = 2
74
+ ENUM = 3
75
+ HASH = 4
76
+
77
+ attr_reader :name, :value_class
78
+
79
+ def initialize( name, value_class, objectFieldClass = nil )
80
+ @name = name; @value_class = value_class
81
+ @objectFieldClass = objectFieldClass
82
+ end
83
+
84
+ def maybe_set_field_attr( field, fieldElt )
85
+ setterMethod = "#{ name }="
86
+ if field.respond_to?( setterMethod )
87
+ if value_class != FieldAttribute::HASH
88
+ if ( attrStr = fieldElt.attributes[name] )
89
+ field.send( setterMethod, value_from_string( attrStr ) )
90
+ end
91
+ else
92
+ if ( attrElt = fieldElt.elements[name] )
93
+ field.send( setterMethod, value_from_elt( attrElt ) )
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ def value_from_elt( elt )
100
+ hash = {}
101
+ elt.elements.each( English.singular( @name ) ) { |subElt|
102
+ key = subElt.attributes['key'] == 'true'
103
+ value = subElt.text.to_s
104
+ hash[key] = value
105
+ }
106
+ hash
107
+ end
108
+
109
+ def value_from_string( valueStr )
110
+ if @value_class == INTEGER
111
+ valueStr.to_i
112
+ elsif @value_class == BOOLEAN
113
+ valueStr == 'y'
114
+ elsif @value_class == ENUM
115
+ eval "#{ @objectFieldClass.name }::#{ valueStr }"
116
+ end
117
+ end
118
+ end
119
+
120
+ class InvalidDataError < ArgumentError; end
121
+ end
122
+
123
+ module DomainComparable
124
+ include Comparable
125
+
126
+ # A DomainObject or DomainObjectProxy is compared by +domain_class+ and by
127
+ # +pk_id+.
128
+ def <=>(anOther)
129
+ if anOther.respond_to?( 'domain_class' )
130
+ if self.domain_class == anOther.domain_class
131
+ self.pk_id <=> anOther.pk_id
132
+ else
133
+ self.domain_class.name <=> anOther.domain_class.name
134
+ end
135
+ else
136
+ nil
137
+ end
138
+ end
139
+
140
+ def eql?(otherObj)
141
+ self == otherObj
142
+ end
143
+
144
+ def hash; "#{ self.class.name } #{ pk_id }".hash; end
145
+ end
146
+
147
+ # All classes that correspond to a table in the database need to be children
148
+ # of DomainObject.
149
+ #
150
+ # = Defining fields
151
+ # There are two ways to define the fields of a DomainObject subclass.
152
+ # 1. Defining fields in an XML file. To do this,
153
+ # 1. Set one directory to contain all your XML files, by setting
154
+ # +classDefinitionDir+ in your LafcadioConfig file.
155
+ # 2. Write one XML file per domain class. For example, a User.xml file
156
+ # might look like:
157
+ # <lafcadio_class_definition name="User">
158
+ # <field name="lastName" class="TextField"/>
159
+ # <field name="email" class="TextField"/>
160
+ # <field name="password" class="TextField"/>
161
+ # <field name="birthday" class="DateField"/>
162
+ # </lafcadio_class_definition>
163
+ # 2. Overriding DomainObject.get_class_fields. The method should return an Array
164
+ # of instances of ObjectField or its children. The order is unimportant.
165
+ # For example:
166
+ # class User < DomainObject
167
+ # def User.get_class_fields
168
+ # fields = []
169
+ # fields << TextField.new(self, 'firstName')
170
+ # fields << TextField.new(self, 'lastName')
171
+ # fields << TextField.new(self, 'email')
172
+ # fields << TextField.new(self, 'password')
173
+ # fields << DateField.new(self, 'birthday')
174
+ # fields
175
+ # end
176
+ # end
177
+ #
178
+ # = Setting and retrieving fields
179
+ # Once your fields are defined, you can create an instance by passing in a
180
+ # hash of field names and values.
181
+ # john = User.new( 'firstName' => 'John', 'lastName' => 'Doe',
182
+ # 'email' => 'john.doe@email.com',
183
+ # 'password' => 'my_password',
184
+ # 'birthday' => tenYearsAgo )
185
+ #
186
+ # You can read and write these fields like normal instance attributes.
187
+ # john.email => 'john.doe@email.com'
188
+ # john.email = 'john.doe@mail.email.com'
189
+ #
190
+ # If your domain class has fields that refer to other domain classes, or even
191
+ # to another row in the same table, you can use a LinkField to express the
192
+ # relation.
193
+ # <lafcadio_class_definition name="Message">
194
+ # <field name="subject" class="TextField" />
195
+ # <field name="body" class="TextField" />
196
+ # <field name="author" class="LinkField" linked_type="User" />
197
+ # <field name="recipient" class="LinkField" linked_type="User" />
198
+ # <field name="dateSent" class="DateField" />
199
+ # </lafcadio_class_definition>
200
+ #
201
+ # msg = Message.new( 'subject' => 'hi there',
202
+ # 'body' => 'You wanna go to the movies on Saturday?',
203
+ # 'author' => john, 'recipient' => jane,
204
+ # 'dateSent' => Date.today )
205
+ #
206
+ # = pk_id and committing
207
+ # Lafcadio requires that each table has a numeric primary key. It assumes that
208
+ # this key is named +pk_id+ in the database, though that can be overridden.
209
+ #
210
+ # When you create a domain object by calling new, you should not assign a
211
+ # +pk_id+ to the new instance. The pk_id will automatically be set when you
212
+ # commit the object by calling DomainObject#commit.
213
+ #
214
+ # However, you may want to manually set +pk_id+ when setting up a test case, so
215
+ # you can ensure that a domain object has a given primary key.
216
+ #
217
+ # = Naming assumptions, and how to override them
218
+ # By default, Lafcadio assumes that every domain object is indexed by the
219
+ # field +pk_id+ in the database schema. If you're dealing with a table that
220
+ # uses a different field name, override DomainObject.sql_primary_key_name.
221
+ # However, you will always use +pk_id+ in your Ruby code.
222
+ #
223
+ # Lafcadio assumes that a domain class corresponds to a table whose name is
224
+ # the plural of the class name, and whose first letter is lowercase. A User
225
+ # class is assumed to be stored in a "users" table, while a ProductCategory
226
+ # class is assumed to be stored in a "productCategories" table. Override
227
+ # DomainObject.table_name to override this behavior.
228
+ #
229
+ # = Inheritance
230
+ # Domain classes can inherit from other domain classes; they have all the
231
+ # fields of any concrete superclasses plus any new fields defined for
232
+ # themselves. You can use normal inheritance to define this:
233
+ # class User < DomainObject
234
+ # ...
235
+ # end
236
+ #
237
+ # class Administrator < User
238
+ # ...
239
+ # end
240
+ #
241
+ # Lafcadio assumes that each concrete class has a corresponding table, and
242
+ # that each table has a +pk_id+ field that is used to match rows between
243
+ # different levels.
244
+ class DomainObject
245
+ @@subclassHash = {}
246
+ @@class_fields = {}
247
+ @@pk_fields =
248
+ Hash.new { |hash, key|
249
+ pk_field = PrimaryKeyField.new( key )
250
+ pk_field.db_field_name = @@sql_primary_keys[key]
251
+ hash[key] = pk_field
252
+ }
253
+ @@sql_primary_keys = Hash.new( 'pk_id' )
254
+
255
+ COMMIT_ADD = 1
256
+ COMMIT_EDIT = 2
257
+ COMMIT_DELETE = 3
258
+
259
+ include DomainComparable
260
+
261
+ def self.abstract_subclasses #:nodoc:
262
+ require 'lafcadio/domain'
263
+ [ MapObject ]
264
+ end
265
+
266
+ # Returns an array of all fields defined for this class and all concrete
267
+ # superclasses.
268
+ def self.all_fields
269
+ all_fields = []
270
+ self_and_concrete_superclasses.each { |aClass|
271
+ aClass.class_fields.each { |field| all_fields << field }
272
+ }
273
+ all_fields
274
+ end
275
+
276
+ def self.class_fields #:nodoc:
277
+ class_fields = @@class_fields[self]
278
+ unless class_fields
279
+ @@class_fields[self] = self.get_class_fields
280
+ class_fields = @@class_fields[self]
281
+ end
282
+ class_fields
283
+ end
284
+
285
+ def self.create_field( field_class, name, att_hash )
286
+ class_fields = @@class_fields[self]
287
+ if class_fields.nil?
288
+ class_fields = [ @@pk_fields[self] ]
289
+ @@class_fields[self] = class_fields
290
+ end
291
+ att_hash['name'] = name
292
+ field = field_class.instantiate_with_parameters( self, att_hash )
293
+ att_hash.each { |field_name, value|
294
+ setter = field_name + '='
295
+ field.send( setter, value ) if field.respond_to?( setter )
296
+ }
297
+ class_fields << field
298
+ end
299
+
300
+ def self.dependent_classes #:nodoc:
301
+ dependent_classes = {}
302
+ DomainObject.subclasses.each { |aClass|
303
+ if aClass != DomainObjectProxy &&
304
+ (!DomainObject.abstract_subclasses.index(aClass))
305
+ aClass.class_fields.each { |field|
306
+ if ( field.is_a?( LinkField ) &&
307
+ field.linked_type == self.domain_class )
308
+ dependent_classes[aClass] = field
309
+ end
310
+ }
311
+ end
312
+ }
313
+ dependent_classes
314
+ end
315
+
316
+ def self.get_class_field(fieldName) #:nodoc:
317
+ field = nil
318
+ self.class_fields.each { |aField|
319
+ field = aField if aField.name == fieldName
320
+ }
321
+ field
322
+ end
323
+
324
+ def DomainObject.get_class_field_by_db_name( fieldName ) #:nodoc:
325
+ self.class_fields.find { |field| field.db_field_name == fieldName }
326
+ end
327
+
328
+ # Returns an Array of ObjectField instances for this domain class, parsing
329
+ # them from XML if necessary.
330
+ def self.get_class_fields
331
+ if self.methods( false ).include?( 'get_class_fields' )
332
+ [ @@pk_fields[ self ] ]
333
+ else
334
+ xmlParser = try_load_xml_parser
335
+ if xmlParser
336
+ xmlParser.get_class_fields
337
+ else
338
+ error_msg = "Couldn't find either an XML class description file " +
339
+ "or get_class_fields method for " + self.name
340
+ raise MissingError, error_msg, caller
341
+ end
342
+ end
343
+ end
344
+
345
+ def self.get_domain_dirs #:nodoc:
346
+ if ( domainDirStr = LafcadioConfig.new['domainDirs'] )
347
+ domainDirStr.split(',')
348
+ else
349
+ []
350
+ end
351
+ end
352
+
353
+ def self.get_field( fieldName ) #:nodoc:
354
+ aDomainClass = self
355
+ field = nil
356
+ while aDomainClass < DomainObject && !field
357
+ field = aDomainClass.get_class_field( fieldName )
358
+ aDomainClass = aDomainClass.superclass
359
+ end
360
+ if field
361
+ field
362
+ else
363
+ errStr = "Couldn't find field \"#{ fieldName }\" in " +
364
+ "#{ self } domain class"
365
+ raise( MissingError, errStr, caller )
366
+ end
367
+ end
368
+
369
+ def self.get_domain_class_from_string(typeString) #:nodoc:
370
+ domain_class = nil
371
+ require_domain_file( typeString )
372
+ subclasses.each { |subclass|
373
+ domain_class = subclass if subclass.to_s == typeString
374
+ }
375
+ if domain_class
376
+ domain_class
377
+ else
378
+ raise CouldntMatchDomainClassError,
379
+ "couldn't match domain_class #{typeString}", caller
380
+ end
381
+ end
382
+
383
+ def self.inherited(subclass) #:nodoc:
384
+ @@subclassHash[subclass] = true
385
+ end
386
+
387
+ def self.is_based_on? #:nodoc:
388
+ self.superclass.is_concrete?
389
+ end
390
+
391
+ def self.is_concrete? #:nodoc:
392
+ (self != DomainObject && abstract_subclasses.index(self).nil?)
393
+ end
394
+
395
+ def self.method_missing( methodId, *args ) #:nodoc:
396
+ method_name = methodId.id2name
397
+ maybe_field_class_name = ( method_name.gsub( /^(.)/ ) { $&.upcase } ) +
398
+ 'Field'
399
+ field_class = Lafcadio.const_get( maybe_field_class_name )
400
+ create_field( field_class, args[0], args[1] || {} )
401
+ end
402
+
403
+ def self.domain_class #:nodoc:
404
+ self
405
+ end
406
+
407
+ def self.require_domain_file( typeString )
408
+ typeString =~ /([^\:]*)$/
409
+ fileName = $1
410
+ get_domain_dirs.each { |domainDir|
411
+ if Dir.entries(domainDir).index("#{fileName}.rb")
412
+ require "#{ domainDir }#{ fileName }"
413
+ end
414
+ }
415
+ if (domainFilesStr = LafcadioConfig.new['domainFiles'])
416
+ domainFilesStr.split(',').each { |domainFile|
417
+ require domainFile
418
+ }
419
+ end
420
+ end
421
+
422
+ def self.self_and_concrete_superclasses # :nodoc:
423
+ classes = [ ]
424
+ a_domain_class = self
425
+ until( a_domain_class == DomainObject ||
426
+ abstract_subclasses.index( a_domain_class ) != nil )
427
+ classes << a_domain_class
428
+ a_domain_class = a_domain_class.superclass
429
+ end
430
+ classes
431
+ end
432
+
433
+ def self.singleton_method_added( symbol )
434
+ if symbol.id2name == 'sql_primary_key_name' && self < DomainObject
435
+ begin
436
+ get_field( 'pk_id' ).db_field_name = self.send( symbol )
437
+ rescue NameError
438
+ @@sql_primary_keys[self] = self.send( symbol )
439
+ end
440
+ end
441
+ end
442
+
443
+ # Returns the name of the primary key in the database, retrieving it from
444
+ # the class definition XML if necessary.
445
+ def self.sql_primary_key_name( set_sql_primary_key_name = nil )
446
+ if set_sql_primary_key_name
447
+ get_field( 'pk_id' ).db_field_name = set_sql_primary_key_name
448
+ end
449
+ get_field( 'pk_id' ).db_field_name
450
+ end
451
+
452
+ def self.subclasses #:nodoc:
453
+ @@subclassHash.keys
454
+ end
455
+
456
+ # Returns the table name, which is assumed to be the domain class name
457
+ # pluralized, and with the first letter lowercase. A User class is
458
+ # assumed to be stored in a "users" table, while a ProductCategory class is
459
+ # assumed to be stored in a "productCategories" table.
460
+ def self.table_name( set_table_name = nil )
461
+ if set_table_name
462
+ @table_name = set_table_name
463
+ elsif @table_name
464
+ @table_name
465
+ else
466
+ xmlParser = try_load_xml_parser
467
+ if (!xmlParser.nil? && table_name = xmlParser.table_name)
468
+ table_name
469
+ else
470
+ table_name = self.basename
471
+ table_name[0] = table_name[0..0].downcase
472
+ English.plural table_name
473
+ end
474
+ end
475
+ end
476
+
477
+ def self.try_load_xml_parser
478
+ require 'lafcadio/domain'
479
+ dirName = LafcadioConfig.new['classDefinitionDir']
480
+ xmlFileName = self.basename + '.xml'
481
+ xmlPath = File.join( dirName, xmlFileName )
482
+ xml = ''
483
+ begin
484
+ File.open( xmlPath ) { |file| xml = file.readlines.join }
485
+ ClassDefinitionXmlParser.new( self, xml )
486
+ rescue Errno::ENOENT
487
+ # no xml file, so no @xmlParser
488
+ end
489
+ end
490
+
491
+ attr_accessor :error_messages, :last_commit, :fields, :fields_set
492
+ attr_reader :delete
493
+ protected :fields, :fields_set
494
+
495
+ # fieldHash should contain key-value associations for the different
496
+ # fields of this domain class. For example, instantiating a User class
497
+ # might look like:
498
+ #
499
+ # User.new( 'firstNames' => 'John', 'lastName' => 'Doe',
500
+ # 'email' => 'john.doe@email.com', 'password' => 'l33t' )
501
+ #
502
+ # In normal usage any code you write that creates a domain object will not
503
+ # define the +pk_id+ field. The system assumes that a domain object with an
504
+ # undefined +pk_id+ has yet to be inserted into the database, and when you
505
+ # commit the domain object a +pk_id+ will automatically be assigned.
506
+ #
507
+ # If you're creating mock objects for unit tests, you can explicitly set
508
+ # the +pk_id+ to represent objects that already exist in the database.
509
+ def initialize(fieldHash)
510
+ @fieldHash = fieldHash
511
+ @error_messages = []
512
+ @fields = {}
513
+ @fields_set = []
514
+ check_fields = LafcadioConfig.new()['checkFields']
515
+ verify if %w( onInstantiate onAllStates ).include?( check_fields )
516
+ end
517
+
518
+ # Returns a clone, with all of the fields copied.
519
+ def clone
520
+ copy = super
521
+ copy.fields = @fields.clone
522
+ copy.fields_set = @fields_set.clone
523
+ copy
524
+ end
525
+
526
+ # Commits this domain object to the database.
527
+ def commit
528
+ ObjectStore.get_object_store.commit self
529
+ end
530
+
531
+ # Set the delete value to true if you want this domain object to be deleted
532
+ # from the database during its next commit.
533
+ def delete=(value)
534
+ if value && !pk_id
535
+ raise "No point deleting an object that's not already in the DB"
536
+ end
537
+ @delete = value
538
+ end
539
+
540
+ def get_field( field ) #:nodoc:
541
+ unless @fields_set.include?( field )
542
+ set_field( field, @fieldHash[field.name] )
543
+ end
544
+ @fields[field.name]
545
+ end
546
+
547
+ def get_getter_field( methId ) #:nodoc:
548
+ begin
549
+ self.class.get_field( methId.id2name )
550
+ rescue MissingError
551
+ nil
552
+ end
553
+ end
554
+
555
+ def get_setter_field( methId ) #:nodoc:
556
+ if methId.id2name =~ /(.*)=$/
557
+ begin
558
+ self.class.get_field( $1 )
559
+ rescue MissingError
560
+ nil
561
+ end
562
+ else
563
+ nil
564
+ end
565
+ end
566
+
567
+ def method_missing( methId, *args ) #:nodoc:
568
+ if ( field = get_setter_field( methId ) )
569
+ set_field( field, args.first )
570
+ elsif ( field = get_getter_field( methId ) )
571
+ get_field( field )
572
+ elsif ( methId.to_s =~ /^get_/ and
573
+ ObjectStore.get_object_store.respond_to?( methId ) )
574
+ args = [ self ].concat( args )
575
+ ObjectStore.get_object_store.send( methId, *args )
576
+ else
577
+ super( methId, *args )
578
+ end
579
+ end
580
+
581
+ # Returns the subclass of DomainObject that this instance represents.
582
+ # Because of the way that proxying works, clients should call this method
583
+ # instead of Object.class.
584
+ def domain_class
585
+ self.class.domain_class
586
+ end
587
+
588
+ # This template method is called before every commit. Subclasses can
589
+ # override it to ensure code is executed before a commit.
590
+ def pre_commit_trigger
591
+ nil
592
+ end
593
+
594
+ # This template method is called after every commit. Subclasses can
595
+ # override it to ensure code is executed after a commit.
596
+ def post_commit_trigger
597
+ nil
598
+ end
599
+
600
+ def set_field( field, value ) #:nodoc:
601
+ if field.class <= LinkField
602
+ if value.class != DomainObjectProxy && value
603
+ value = DomainObjectProxy.new(value)
604
+ end
605
+ end
606
+ if ( LafcadioConfig.new()['checkFields'] == 'onAllStates' &&
607
+ !field.instance_of?( PrimaryKeyField ) )
608
+ field.verify( value, pk_id )
609
+ end
610
+ @fields[field.name] = value
611
+ @fields_set << field
612
+ end
613
+
614
+ def verify
615
+ self.class.get_class_fields.each { |field|
616
+ field.verify( self.send( field.name ), self.pk_id )
617
+ }
618
+ end
619
+ end
620
+
621
+ # Any domain class that is used mostly to map between two other domain
622
+ # classes should be a subclass of MapObject. Subclasses of MapObject should
623
+ # override MapObject.mappedTypes, returning a two-element array containing
624
+ # the domain classes that the map object maps between.
625
+ class MapObject < DomainObject
626
+ def self.other_mapped_type(firstType) #:nodoc:
627
+ types = mappedTypes
628
+ if types.index(firstType) == 0
629
+ types[1]
630
+ else
631
+ types[0]
632
+ end
633
+ end
634
+
635
+ def self.subsidiary_map #:nodoc:
636
+ nil
637
+ end
638
+ end
639
+ end