lafcadio 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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