lafcadio 0.8.0 → 0.8.1

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.8.0"
19
+ Version = "0.8.1"
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.7.5"
19
+ Version = "0.8.0"
20
20
 
21
21
  require 'lafcadio/depend'
22
22
  require 'lafcadio/domain'
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.6
3
3
  specification_version: 1
4
4
  name: lafcadio
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.8.0
7
- date: 2005-09-21
6
+ version: 0.8.1
7
+ date: 2005-10-23
8
8
  summary: Lafcadio is an object-relational mapping layer
9
9
  require_paths:
10
10
  - lib
@@ -34,29 +34,17 @@ files:
34
34
  - lib/lafcadio
35
35
  - lib/lafcadio.rb
36
36
  - lib/lafcadio.rb~
37
- - lib/lafcadio/dateTime.rb~
38
37
  - lib/lafcadio/depend.rb
39
- - lib/lafcadio/depend.rb~
40
38
  - lib/lafcadio/domain.rb
41
- - lib/lafcadio/domain.rb~
42
39
  - lib/lafcadio/mock.rb
43
- - lib/lafcadio/mock.rb~
44
40
  - lib/lafcadio/objectField.rb
45
- - lib/lafcadio/objectField.rb~
46
41
  - lib/lafcadio/objectStore.rb
47
- - lib/lafcadio/objectStore.rb.~1.64.~
48
- - lib/lafcadio/objectStore.rb~
49
42
  - lib/lafcadio/query.rb
50
- - lib/lafcadio/query.rb~
51
43
  - lib/lafcadio/schema.rb
52
- - lib/lafcadio/schema.rb~
53
44
  - lib/lafcadio/test
54
45
  - lib/lafcadio/test.rb
55
- - lib/lafcadio/test.rb~
56
46
  - lib/lafcadio/util.rb
57
- - lib/lafcadio/util.rb~
58
47
  - lib/lafcadio/test/testconfig.dat
59
- - lib/lafcadio/test/testconfig.dat~
60
48
  test_files: []
61
49
  rdoc_options: []
62
50
  extra_rdoc_files: []
@@ -65,6 +53,16 @@ executables:
65
53
  extensions: []
66
54
  requirements: []
67
55
  dependencies:
56
+ - !ruby/object:Gem::Dependency
57
+ name: contxtlservice
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Version::Requirement
60
+ requirements:
61
+ -
62
+ - ">"
63
+ - !ruby/object:Gem::Version
64
+ version: 0.0.0
65
+ version:
68
66
  - !ruby/object:Gem::Dependency
69
67
  name: englishext
70
68
  version_requirement:
@@ -1,93 +0,0 @@
1
- module Lafcadio
2
- # Represents a specific month in time. With the exception of
3
- # Month.month_names (which returns a zero-based array), every usage of the
4
- # month value assumes that 1 equals January and 12 equals December.
5
- class Month
6
- # Returns an array of the full names of months (in English). Note that
7
- # "January" is the 0th element, and "December" is the 11th element.
8
- def Month.month_names
9
- [ "January", "February", "March", "April", "May", "June", "July",
10
- "August", "September", "October", "November", "December" ]
11
- end
12
-
13
- include Comparable
14
-
15
- attr_reader :month, :year
16
-
17
- # A new month can be set to a specific +month+ and +year+, or you can call
18
- # Month.new with no arguments to receive the current month.
19
- def initialize( year = nil, month = nil )
20
- require 'date'
21
- if month.nil? || year.nil?
22
- date = Date.today
23
- month = date.mon unless month
24
- year = date.year unless year
25
- end
26
- fail "invalid month" if month < 1 || month > 12
27
- @month = month
28
- @year = year
29
- end
30
-
31
- # Returns a new Month that is +amountToAdd+ months later.
32
- def +( amountToAdd )
33
- ( fullYears, remainingMonths ) = amountToAdd.divmod( 12 )
34
- resultYear = @year + fullYears
35
- resultMonth = @month + remainingMonths
36
- if resultMonth > 12
37
- resultMonth -= 12
38
- resultYear += 1
39
- end
40
- Month.new( resultYear, resultMonth )
41
- end
42
-
43
- # Returns a new Month that is +amountToSubtract+ months earlier.
44
- def -(amountToSubtract)
45
- self + (-amountToSubtract)
46
- end
47
-
48
- # Compare this Month to another Month.
49
- def <=>(anOther)
50
- if @year == anOther.year
51
- @month <=> anOther.month
52
- else
53
- @year <=> anOther.year
54
- end
55
- end
56
-
57
- # Returns the last Date of the month.
58
- def end_date
59
- self.next.start_date - 1
60
- end
61
-
62
- # Is this Month equal to +anOther+? +anOther+ must be another Month of the
63
- # same value.
64
- def eql?(anOther)
65
- self == anOther
66
- end
67
-
68
- # Calculate a hash value for this Month.
69
- def hash
70
- "#{@year}#{@month}".to_i
71
- end
72
-
73
- # Returns the next Month.
74
- def next
75
- self + 1
76
- end
77
-
78
- # Returns the previous Month.
79
- def prev
80
- self - 1
81
- end
82
-
83
- # Returns the first Date of the month.
84
- def start_date
85
- Date.new( @year, @month, 1 )
86
- end
87
-
88
- # Returns a string of the format "January 2001".
89
- def to_s
90
- Month.month_names[@month-1][0..2] + " " + @year.to_s
91
- end
92
- end
93
- end
@@ -1,8 +0,0 @@
1
- require 'dbi'
2
- require 'englishext'
3
- require 'extensions/all'
4
- require 'extensions/module'
5
- require 'log4r'
6
- require 'month'
7
- require 'queuehash'
8
- require 'uscommerce'
@@ -1,751 +0,0 @@
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( @name.singular ) { |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="StringField"/>
159
- # <field name="email" class="StringField"/>
160
- # <field name="password" class="StringField"/>
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 << StringField.new(self, 'firstName')
170
- # fields << StringField.new(self, 'lastName')
171
- # fields << StringField.new(self, 'email')
172
- # fields << StringField.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 DomainObjectField to express the
192
- # relation.
193
- # <lafcadio_class_definition name="Message">
194
- # <field name="subject" class="StringField" />
195
- # <field name="body" class="StringField" />
196
- # <field name="author" class="DomainObjectField" linked_type="User" />
197
- # <field name="recipient" class="DomainObjectField" 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
- @@default_field_setup_hashes = Hash.new { |hash, key|
255
- hash[key] = Hash.new( {} )
256
- }
257
-
258
- COMMIT_ADD = 1
259
- COMMIT_EDIT = 2
260
- COMMIT_DELETE = 3
261
-
262
- include DomainComparable
263
-
264
- def self.[]( pk_id ); get( pk_id ); end
265
-
266
- def self.abstract_subclasses #:nodoc:
267
- require 'lafcadio/domain'
268
- [ MapObject ]
269
- end
270
-
271
- def self.all; ObjectStore.get_object_store.get_all( self ); end
272
-
273
- # Returns an array of all fields defined for this class and all concrete
274
- # superclasses.
275
- def self.all_fields
276
- all_fields = []
277
- self_and_concrete_superclasses.each { |aClass|
278
- aClass.class_fields.each { |field| all_fields << field }
279
- }
280
- all_fields
281
- end
282
-
283
- def self.class_fields #:nodoc:
284
- class_fields = @@class_fields[self]
285
- unless class_fields
286
- @@class_fields[self] = self.get_class_fields
287
- class_fields = @@class_fields[self]
288
- class_fields.each do |class_field|
289
- begin
290
- undef_method class_field.name.to_sym
291
- rescue NameError
292
- # not defined globally or in an included Module, skip it
293
- end
294
- end
295
- end
296
- class_fields
297
- end
298
-
299
- def self.create_field( field_class, *args )
300
- class_fields = @@class_fields[self]
301
- if args.last.is_a? Hash
302
- att_hash = args.last
303
- else
304
- att_hash = @@default_field_setup_hashes[self][field_class].clone
305
- end
306
- if class_fields.nil?
307
- class_fields = [ @@pk_fields[self] ]
308
- @@class_fields[self] = class_fields
309
- end
310
- if field_class == DomainObjectField
311
- att_hash['linked_type'] = args.first
312
- att_hash['name'] = args[1] if args[1] and !args[1].is_a? Hash
313
- else
314
- name = args.first
315
- att_hash['name'] = name == String ? name : name.to_s
316
- end
317
- field = field_class.instantiate_with_parameters( self, att_hash )
318
- att_hash.each { |field_name, value|
319
- setter = field_name + '='
320
- field.send( setter, value ) if field.respond_to?( setter )
321
- }
322
- class_fields << field
323
- end
324
-
325
- def self.default_field_setup_hash( field_class, hash )
326
- @@default_field_setup_hashes[self][field_class] = hash
327
- end
328
-
329
- def self.dependent_classes #:nodoc:
330
- dependent_classes = {}
331
- DomainObject.subclasses.each { |aClass|
332
- if aClass != DomainObjectProxy &&
333
- (!DomainObject.abstract_subclasses.index(aClass))
334
- aClass.class_fields.each { |field|
335
- if ( field.is_a?( DomainObjectField ) &&
336
- field.linked_type == self.domain_class )
337
- dependent_classes[aClass] = field
338
- end
339
- }
340
- end
341
- }
342
- dependent_classes
343
- end
344
-
345
- def self.exist?( search_term, field_name = :pk_id )
346
- query = Query.infer( self ) { |dobj|
347
- dobj.send( field_name ).equals( search_term )
348
- }
349
- !ObjectStore.get_object_store.get_subset( query ).empty?
350
- end
351
-
352
- def self.first; all.first; end
353
-
354
- def self.get_class_field(fieldName) #:nodoc:
355
- field = nil
356
- self.class_fields.each { |aField|
357
- field = aField if aField.name == fieldName
358
- }
359
- field
360
- end
361
-
362
- def DomainObject.get_class_field_by_db_name( fieldName ) #:nodoc:
363
- self.class_fields.find { |field| field.db_field_name == fieldName }
364
- end
365
-
366
- # Returns an Array of ObjectField instances for this domain class, parsing
367
- # them from XML if necessary.
368
- def self.get_class_fields
369
- if self.methods( false ).include?( 'get_class_fields' )
370
- [ @@pk_fields[ self ] ]
371
- elsif abstract_subclasses.include?( self )
372
- []
373
- else
374
- xmlParser = try_load_xml_parser
375
- if xmlParser
376
- xmlParser.get_class_fields
377
- else
378
- error_msg = "Couldn't find either an XML class description file " +
379
- "or get_class_fields method for " + self.name
380
- raise MissingError, error_msg, caller
381
- end
382
- end
383
- end
384
-
385
- def self.get_domain_dirs #:nodoc:
386
- if ( domainDirStr = LafcadioConfig.new['domainDirs'] )
387
- domainDirStr.split(',')
388
- else
389
- []
390
- end
391
- end
392
-
393
- def self.get_field( fieldName ) #:nodoc:
394
- aDomainClass = self
395
- field = nil
396
- while aDomainClass < DomainObject && !field
397
- field = aDomainClass.get_class_field( fieldName )
398
- aDomainClass = aDomainClass.superclass
399
- end
400
- if field
401
- field
402
- else
403
- errStr = "Couldn't find field \"#{ fieldName }\" in " +
404
- "#{ self } domain class"
405
- raise( MissingError, errStr, caller )
406
- end
407
- end
408
-
409
- def self.get_domain_class_from_string(typeString) #:nodoc:
410
- domain_class = nil
411
- require_domain_file( typeString )
412
- subclasses.each { |subclass|
413
- domain_class = subclass if subclass.to_s == typeString
414
- }
415
- if domain_class
416
- domain_class
417
- else
418
- raise CouldntMatchDomainClassError,
419
- "couldn't match domain_class #{typeString}", caller
420
- end
421
- end
422
-
423
- def self.get_link_field( linked_domain_class ) # :nodoc:
424
- class_fields.find { |field|
425
- field.is_a? DomainObjectField and field.linked_type == linked_domain_class
426
- }
427
- end
428
-
429
- def self.inherited(subclass) #:nodoc:
430
- @@subclassHash[subclass] = true
431
- end
432
-
433
- def self.is_based_on? #:nodoc:
434
- self.superclass.is_concrete?
435
- end
436
-
437
- def self.is_concrete? #:nodoc:
438
- (self != DomainObject && abstract_subclasses.index(self).nil?)
439
- end
440
-
441
- def self.last; all.last; end
442
-
443
- def self.method_missing( methodId, *args ) #:nodoc:
444
- method_name = methodId.id2name
445
- if method_name == 'get'
446
- if block_given?
447
- query = Query.infer( self ) { |dobj| yield( dobj ) }
448
- ObjectStore.get_object_store.get_subset( query )
449
- elsif args.size == 1
450
- ObjectStore.get_object_store.get( self, *args )
451
- else
452
- ObjectStore.get_object_store.get_filtered( self.name, *args )
453
- end
454
- else
455
- maybe_field_class_name = method_name.underscore_to_camel_case + 'Field'
456
- begin
457
- field_class = Lafcadio.const_get( maybe_field_class_name )
458
- create_field( field_class, *args )
459
- rescue NameError
460
- singular = method_name.singular
461
- if singular
462
- maybe_field_class_name = singular.underscore_to_camel_case + 'Field'
463
- begin
464
- field_class = Lafcadio.const_get( maybe_field_class_name )
465
- arg = args.shift
466
- until args.empty?
467
- next_arg = args.shift
468
- if next_arg.is_a? String or next_arg.is_a? Symbol
469
- create_field( field_class, arg )
470
- arg = next_arg
471
- else
472
- create_field( field_class, arg, next_arg )
473
- arg = args.shift
474
- end
475
- end
476
- create_field( field_class, arg ) unless arg.nil?
477
- rescue NameError
478
- super
479
- end
480
- else
481
- super
482
- end
483
- end
484
- end
485
- end
486
-
487
- def self.only; all.only; end
488
-
489
- def self.domain_class #:nodoc:
490
- self
491
- end
492
-
493
- def self.require_domain_file( typeString )
494
- typeString =~ /([^\:]*)$/
495
- fileName = $1
496
- get_domain_dirs.each { |domainDir|
497
- if Dir.entries(domainDir).index("#{fileName}.rb")
498
- require "#{ domainDir }#{ fileName }"
499
- end
500
- }
501
- if (domainFiles = LafcadioConfig.new['domainFiles'])
502
- domainFiles = domainFiles.split( ',' ) if domainFiles.is_a? String
503
- domainFiles.each { |domainFile| require domainFile }
504
- end
505
- end
506
-
507
- def self.self_and_concrete_superclasses # :nodoc:
508
- classes = [ ]
509
- a_domain_class = self
510
- until( a_domain_class == DomainObject ||
511
- abstract_subclasses.index( a_domain_class ) != nil )
512
- classes << a_domain_class
513
- a_domain_class = a_domain_class.superclass
514
- end
515
- classes
516
- end
517
-
518
- def self.singleton_method_added( symbol )
519
- if symbol.id2name == 'sql_primary_key_name' && self < DomainObject
520
- begin
521
- get_field( 'pk_id' ).db_field_name = self.send( symbol )
522
- rescue NameError
523
- @@sql_primary_keys[self] = self.send( symbol )
524
- end
525
- end
526
- end
527
-
528
- # Returns the name of the primary key in the database, retrieving it from
529
- # the class definition XML if necessary.
530
- def self.sql_primary_key_name( set_sql_primary_key_name = nil )
531
- if set_sql_primary_key_name
532
- get_field( 'pk_id' ).db_field_name = set_sql_primary_key_name
533
- end
534
- get_field( 'pk_id' ).db_field_name
535
- end
536
-
537
- def self.subclasses #:nodoc:
538
- @@subclassHash.keys
539
- end
540
-
541
- # Returns the table name, which is assumed to be the domain class name
542
- # pluralized, and with the first letter lowercase. A User class is
543
- # assumed to be stored in a "users" table, while a ProductCategory class is
544
- # assumed to be stored in a "productCategories" table.
545
- def self.table_name( set_table_name = nil )
546
- if set_table_name
547
- @table_name = set_table_name
548
- elsif @table_name
549
- @table_name
550
- else
551
- xmlParser = try_load_xml_parser
552
- if (!xmlParser.nil? && table_name = xmlParser.table_name)
553
- table_name
554
- else
555
- self.basename.camel_case_to_underscore.plural
556
- end
557
- end
558
- end
559
-
560
- def self.try_load_xml_parser
561
- require 'lafcadio/domain'
562
- dirName = LafcadioConfig.new['classDefinitionDir']
563
- xmlFileName = self.basename + '.xml'
564
- xmlPath = File.join( dirName, xmlFileName )
565
- xml = ''
566
- begin
567
- File.open( xmlPath ) { |file| xml = file.readlines.join }
568
- ClassDefinitionXmlParser.new( self, xml )
569
- rescue Errno::ENOENT
570
- # no xml file, so no @xmlParser
571
- end
572
- end
573
-
574
- attr_accessor :error_messages, :last_commit, :fields, :fields_set
575
- attr_reader :delete
576
- protected :fields, :fields_set
577
-
578
- # fieldHash should contain key-value associations for the different
579
- # fields of this domain class. For example, instantiating a User class
580
- # might look like:
581
- #
582
- # User.new( 'firstNames' => 'John', 'lastName' => 'Doe',
583
- # 'email' => 'john.doe@email.com', 'password' => 'l33t' )
584
- #
585
- # In normal usage any code you write that creates a domain object will not
586
- # define the +pk_id+ field. The system assumes that a domain object with an
587
- # undefined +pk_id+ has yet to be inserted into the database, and when you
588
- # commit the domain object a +pk_id+ will automatically be assigned.
589
- #
590
- # If you're creating mock objects for unit tests, you can explicitly set
591
- # the +pk_id+ to represent objects that already exist in the database.
592
- def initialize(fieldHash)
593
- if fieldHash.respond_to? :keys
594
- fieldHash.keys.each { |key|
595
- begin
596
- self.class.get_field( key )
597
- rescue MissingError
598
- raise ArgumentError, "Invalid field name #{ key }"
599
- end
600
- }
601
- end
602
- @fieldHash = fieldHash
603
- @error_messages = []
604
- @fields = {}
605
- @fields_set = []
606
- @original_values = OriginalValuesHash.new( @fieldHash )
607
- check_fields = LafcadioConfig.new()['checkFields']
608
- verify if %w( onInstantiate onAllStates ).include?( check_fields )
609
- end
610
-
611
- # Returns a clone, with all of the fields copied.
612
- def clone
613
- copy = super
614
- copy.fields = @fields.clone
615
- copy.fields_set = @fields_set.clone
616
- copy
617
- end
618
-
619
- # Commits this domain object to the database.
620
- def commit
621
- ObjectStore.get_object_store.commit self
622
- end
623
-
624
- # Set the delete value to true if you want this domain object to be deleted
625
- # from the database during its next commit.
626
- def delete=(value)
627
- if value && !pk_id
628
- raise "No point deleting an object that's not already in the DB"
629
- end
630
- @delete = value
631
- end
632
-
633
- def delete!
634
- self.delete = true
635
- commit
636
- end
637
-
638
- def get_field( field ) #:nodoc:
639
- unless @fields_set.include?( field )
640
- set_field( field, @fieldHash[field.name] )
641
- end
642
- @fields[field.name]
643
- end
644
-
645
- def get_getter_field( methId ) #:nodoc:
646
- begin
647
- self.class.get_field( methId.id2name )
648
- rescue MissingError
649
- nil
650
- end
651
- end
652
-
653
- def get_setter_field( methId ) #:nodoc:
654
- if methId.id2name =~ /(.*)=$/
655
- begin
656
- self.class.get_field( $1 )
657
- rescue MissingError
658
- nil
659
- end
660
- else
661
- nil
662
- end
663
- end
664
-
665
- def method_missing( methId, *args ) #:nodoc:
666
- if ( field = get_setter_field( methId ) )
667
- set_field( field, args.first )
668
- elsif ( field = get_getter_field( methId ) )
669
- get_field( field )
670
- else
671
- new_symbol = ( 'get_' + methId.id2name ).to_sym
672
- object_store = ObjectStore.get_object_store
673
- if object_store.respond_to? new_symbol
674
- args = [ self ].concat args
675
- object_store.send( 'get_' + methId.id2name, *args )
676
- else
677
- super( methId, *args )
678
- end
679
- end
680
- end
681
-
682
- # Returns the subclass of DomainObject that this instance represents.
683
- # Because of the way that proxying works, clients should call this method
684
- # instead of Object.class.
685
- def domain_class
686
- self.class.domain_class
687
- end
688
-
689
- # This template method is called before every commit. Subclasses can
690
- # override it to ensure code is executed before a commit.
691
- def pre_commit_trigger
692
- nil
693
- end
694
-
695
- # This template method is called after every commit. Subclasses can
696
- # override it to ensure code is executed after a commit.
697
- def post_commit_trigger
698
- nil
699
- end
700
-
701
- def set_field( field, value ) #:nodoc:
702
- if field.class <= DomainObjectField
703
- if value.class != DomainObjectProxy && value
704
- value = DomainObjectProxy.new(value)
705
- end
706
- end
707
- if ( LafcadioConfig.new()['checkFields'] == 'onAllStates' &&
708
- !field.instance_of?( PrimaryKeyField ) )
709
- field.verify( value, pk_id )
710
- end
711
- @fields[field.name] = value
712
- @fields_set << field
713
- end
714
-
715
- def update!( changes )
716
- changes.each do |sym, value| self.send( sym.to_s + '=', value ); end
717
- commit
718
- end
719
-
720
- def verify
721
- if ObjectStore.get_object_store.mock?
722
- self.class.get_class_fields.each { |field|
723
- field.verify( self.send( field.name ), self.pk_id )
724
- }
725
- end
726
- end
727
-
728
- class OriginalValuesHash < DelegateClass( Hash )
729
- def []=( key, val ); raise NoMethodError; end
730
- end
731
- end
732
-
733
- # Any domain class that is used mostly to map between two other domain
734
- # classes should be a subclass of MapObject. Subclasses of MapObject should
735
- # override MapObject.mappedTypes, returning a two-element array containing
736
- # the domain classes that the map object maps between.
737
- class MapObject < DomainObject
738
- def self.other_mapped_type(firstType) #:nodoc:
739
- types = mappedTypes
740
- if types.index(firstType) == 0
741
- types[1]
742
- else
743
- types[0]
744
- end
745
- end
746
-
747
- def self.subsidiary_map #:nodoc:
748
- nil
749
- end
750
- end
751
- end