lafcadio 0.4.3 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/bin/lafcadio_schema +28 -0
  2. data/lib/lafcadio.rb +3 -4
  3. data/lib/lafcadio.rb~ +3 -4
  4. data/lib/lafcadio/TestSuite.rb +2 -0
  5. data/lib/lafcadio/TestSuite.rb~ +16 -0
  6. data/lib/lafcadio/dateTime.rb +93 -2
  7. data/lib/lafcadio/{dateTime/Month.rb → dateTime.rb~} +33 -33
  8. data/lib/lafcadio/depend.rb +3 -0
  9. data/lib/lafcadio/domain.rb +574 -70
  10. data/lib/lafcadio/domain.rb~ +570 -70
  11. data/lib/lafcadio/mock.rb +92 -2
  12. data/lib/lafcadio/mock.rb~ +93 -0
  13. data/lib/lafcadio/objectField.rb +614 -3
  14. data/lib/lafcadio/objectField.rb~ +618 -0
  15. data/lib/lafcadio/objectStore.rb +662 -19
  16. data/lib/lafcadio/objectStore.rb~ +746 -0
  17. data/lib/lafcadio/query.rb +415 -31
  18. data/lib/lafcadio/query.rb~ +572 -0
  19. data/lib/lafcadio/schema.rb +57 -2
  20. data/lib/lafcadio/test.rb +17 -2
  21. data/lib/lafcadio/{test/LafcadioTestCase.rb → test.rb~} +5 -5
  22. data/lib/lafcadio/test/testconfig.dat +1 -1
  23. data/lib/lafcadio/util.rb +337 -20
  24. metadata +16 -77
  25. data/lib/lafcadio/domain/DomainObject.rb +0 -375
  26. data/lib/lafcadio/domain/DomainObject.rb~ +0 -371
  27. data/lib/lafcadio/domain/MapObject.rb +0 -22
  28. data/lib/lafcadio/domain/ObjectType.rb +0 -80
  29. data/lib/lafcadio/includer.rb +0 -18
  30. data/lib/lafcadio/mock/MockDbBridge.rb +0 -78
  31. data/lib/lafcadio/mock/MockDbBridge.rb~ +0 -74
  32. data/lib/lafcadio/mock/MockObjectStore.rb +0 -20
  33. data/lib/lafcadio/objectField/AutoIncrementField.rb +0 -25
  34. data/lib/lafcadio/objectField/BooleanField.rb +0 -83
  35. data/lib/lafcadio/objectField/DateField.rb +0 -33
  36. data/lib/lafcadio/objectField/DateTimeField.rb +0 -25
  37. data/lib/lafcadio/objectField/DecimalField.rb +0 -41
  38. data/lib/lafcadio/objectField/EmailField.rb +0 -28
  39. data/lib/lafcadio/objectField/EnumField.rb +0 -62
  40. data/lib/lafcadio/objectField/FieldValueError.rb +0 -4
  41. data/lib/lafcadio/objectField/IntegerField.rb +0 -15
  42. data/lib/lafcadio/objectField/LinkField.rb +0 -92
  43. data/lib/lafcadio/objectField/LinkField.rb~ +0 -86
  44. data/lib/lafcadio/objectField/MoneyField.rb +0 -13
  45. data/lib/lafcadio/objectField/MonthField.rb +0 -16
  46. data/lib/lafcadio/objectField/ObjectField.rb +0 -142
  47. data/lib/lafcadio/objectField/PasswordField.rb +0 -29
  48. data/lib/lafcadio/objectField/StateField.rb +0 -13
  49. data/lib/lafcadio/objectField/SubsetLinkField.rb +0 -25
  50. data/lib/lafcadio/objectField/TextField.rb +0 -23
  51. data/lib/lafcadio/objectField/TextListField.rb +0 -21
  52. data/lib/lafcadio/objectField/TimeStampField.rb +0 -15
  53. data/lib/lafcadio/objectStore/Cache.rb +0 -81
  54. data/lib/lafcadio/objectStore/Committer.rb +0 -65
  55. data/lib/lafcadio/objectStore/CouldntMatchObjectTypeError.rb +0 -4
  56. data/lib/lafcadio/objectStore/DbBridge.rb +0 -140
  57. data/lib/lafcadio/objectStore/DbBridge.rb~ +0 -140
  58. data/lib/lafcadio/objectStore/DomainComparable.rb +0 -25
  59. data/lib/lafcadio/objectStore/DomainObjectInitError.rb +0 -9
  60. data/lib/lafcadio/objectStore/DomainObjectNotFoundError.rb +0 -4
  61. data/lib/lafcadio/objectStore/DomainObjectProxy.rb +0 -62
  62. data/lib/lafcadio/objectStore/DomainObjectSqlMaker.rb +0 -74
  63. data/lib/lafcadio/objectStore/ObjectStore.rb +0 -207
  64. data/lib/lafcadio/objectStore/ObjectStore.rb~ +0 -207
  65. data/lib/lafcadio/objectStore/SqlValueConverter.rb +0 -30
  66. data/lib/lafcadio/objectStore/SqlValueConverter.rb~ +0 -30
  67. data/lib/lafcadio/query/Compare.rb +0 -55
  68. data/lib/lafcadio/query/CompoundCondition.rb +0 -39
  69. data/lib/lafcadio/query/Condition.rb +0 -66
  70. data/lib/lafcadio/query/Condition.rb~ +0 -66
  71. data/lib/lafcadio/query/Equals.rb +0 -45
  72. data/lib/lafcadio/query/In.rb +0 -20
  73. data/lib/lafcadio/query/Like.rb +0 -48
  74. data/lib/lafcadio/query/Link.rb +0 -20
  75. data/lib/lafcadio/query/Max.rb +0 -32
  76. data/lib/lafcadio/query/Max.rb~ +0 -25
  77. data/lib/lafcadio/query/Not.rb +0 -21
  78. data/lib/lafcadio/query/Query.rb +0 -92
  79. data/lib/lafcadio/schema/CreateTableStatement.rb +0 -61
  80. data/lib/lafcadio/schema/CreateTableStatement.rb~ +0 -59
  81. data/lib/lafcadio/util/Context.rb +0 -61
  82. data/lib/lafcadio/util/ContextualService.rb +0 -33
  83. data/lib/lafcadio/util/English.rb +0 -117
  84. data/lib/lafcadio/util/HashOfArrays.rb +0 -48
  85. data/lib/lafcadio/util/LafcadioConfig.rb +0 -25
  86. data/lib/lafcadio/util/QueueHash.rb +0 -67
  87. data/lib/lafcadio/util/UsStates.rb +0 -29
  88. data/lib/lafcadio/xml.rb +0 -2
@@ -1,371 +0,0 @@
1
- require 'lafcadio/objectField/LinkField'
2
- require 'lafcadio/objectStore/DomainComparable'
3
- require 'lafcadio/objectStore/DomainObjectProxy'
4
-
5
- module Lafcadio
6
- # All classes that correspond to a table in the database need to be children
7
- # of DomainObject.
8
- #
9
- # = Defining fields
10
- # There are two ways to define the fields of a DomainObject subclass.
11
- # 1. Defining fields in an XML file. To do this,
12
- # 1. Set one directory to contain all your XML files, by setting
13
- # +classDefinitionDir+ in your LafcadioConfig file.
14
- # 2. Write one XML file per domain class. For example, a User.xml file
15
- # might look like:
16
- # <lafcadio_class_definition name="User">
17
- # <field name="lastName" class="TextField"/>
18
- # <field name="email" class="TextField"/>
19
- # <field name="password" class="TextField"/>
20
- # <field name="birthday" class="DateField"/>
21
- # </lafcadio_class_definition>
22
- # 2. Overriding DomainObject.getClassFields. The method should return an Array
23
- # of instances of ObjectField or its children. The order is unimportant.
24
- # For example:
25
- # class User < DomainObject
26
- # def User.getClassFields
27
- # fields = []
28
- # fields << TextField.new(self, 'firstName')
29
- # fields << TextField.new(self, 'lastName')
30
- # fields << TextField.new(self, 'email')
31
- # fields << TextField.new(self, 'password')
32
- # fields << DateField.new(self, 'birthday')
33
- # fields
34
- # end
35
- # end
36
- #
37
- # = Setting and retrieving fields
38
- # Once your fields are defined, you can create an instance by passing in a
39
- # hash of field names and values.
40
- # john = User.new( 'firstName' => 'John', 'lastName' => 'Doe',
41
- # 'email' => 'john.doe@email.com',
42
- # 'password' => 'my_password',
43
- # 'birthday' => tenYearsAgo )
44
- #
45
- # You can read and write these fields like normal instance attributes.
46
- # john.email => 'john.doe@email.com'
47
- # john.email = 'john.doe@mail.email.com'
48
- #
49
- # If your domain class has fields that refer to other domain classes, or even
50
- # to another row in the same table, you can use a LinkField to express the
51
- # relation.
52
- # <lafcadio_class_definition name="Message">
53
- # <field name="subject" class="TextField" />
54
- # <field name="body" class="TextField" />
55
- # <field name="author" class="LinkField" linkedType="User" />
56
- # <field name="recipient" class="LinkField" linkedType="User" />
57
- # <field name="dateSent" class="DateField" />
58
- # </lafcadio_class_definition>
59
- #
60
- # msg = Message.new( 'subject' => 'hi there',
61
- # 'body' => 'You wanna go to the movies on Saturday?',
62
- # 'author' => john, 'recipient' => jane,
63
- # 'dateSent' => Date.today )
64
- #
65
- # = pkId and committing
66
- # Lafcadio requires that each table has a numeric primary key. It assumes that
67
- # this key is named +pkId+ in the database, though that can be overridden.
68
- #
69
- # When you create a domain object by calling new, you should not assign a
70
- # +pkId+ to the new instance. The pkId will automatically be set when you
71
- # commit the object by calling DomainObject#commit.
72
- #
73
- # However, you may want to manually set +pkId+ when setting up a test case, so
74
- # you can ensure that a domain object has a given primary key.
75
- #
76
- # = Naming assumptions, and how to override them
77
- # By default, Lafcadio assumes that every domain object is indexed by the
78
- # field +pkId+ in the database schema. If you're dealing with a table that
79
- # uses a different field name, override DomainObject.sqlPrimaryKeyName.
80
- # However, you will always use +pkId+ in your Ruby code.
81
- #
82
- # Lafcadio assumes that a domain class corresponds to a table whose name is
83
- # the plural of the class name, and whose first letter is lowercase. A User
84
- # class is assumed to be stored in a "users" table, while a ProductCategory
85
- # class is assumed to be stored in a "productCategories" table. Override
86
- # DomainObject.tableName to override this behavior.
87
- #
88
- # = Inheritance
89
- # Domain classes can inherit from other domain classes; they have all the
90
- # fields of any concrete superclasses plus any new fields defined for
91
- # themselves. You can use normal inheritance to define this:
92
- # class User < DomainObject
93
- # ...
94
- # end
95
- #
96
- # class Administrator < User
97
- # ...
98
- # end
99
- #
100
- # Lafcadio assumes that each concrete class has a corresponding table, and
101
- # that each table has a +pkId+ field that is used to match rows between
102
- # different levels.
103
- class DomainObject
104
- @@subclassHash = {}
105
- @@classFields = {}
106
-
107
- COMMIT_ADD = 1
108
- COMMIT_EDIT = 2
109
- COMMIT_DELETE = 3
110
-
111
- include DomainComparable
112
-
113
- def DomainObject.classFields #:nodoc:
114
- classFields = @@classFields[self]
115
- unless classFields
116
- @@classFields[self] = self.getClassFields
117
- classFields = @@classFields[self]
118
- end
119
- classFields
120
- end
121
-
122
- def DomainObject.abstractSubclasses #:nodoc:
123
- require 'lafcadio/domain'
124
- [ MapObject ]
125
- end
126
-
127
- def DomainObject.selfAndConcreteSuperclasses # :nodoc:
128
- classes = [ ]
129
- anObjectType = self
130
- until(anObjectType == DomainObject ||
131
- abstractSubclasses.index(anObjectType) != nil)
132
- classes << anObjectType
133
- anObjectType = anObjectType.superclass
134
- end
135
- classes
136
- end
137
-
138
- def DomainObject.method_missing(methodId) #:nodoc:
139
- require 'lafcadio/domain'
140
- ObjectType.getObjectType( self ).send( methodId.id2name )
141
- end
142
-
143
- def DomainObject.getClassField(fieldName) #:nodoc:
144
- field = nil
145
- self.classFields.each { |aField|
146
- field = aField if aField.name == fieldName
147
- }
148
- field
149
- end
150
-
151
- def DomainObject.getField( fieldName ) #:nodoc:
152
- aDomainClass = self
153
- field = nil
154
- while aDomainClass < DomainObject && !field
155
- field = aDomainClass.getClassField( fieldName )
156
- aDomainClass = aDomainClass.superclass
157
- end
158
- if field
159
- field
160
- else
161
- errStr = "Couldn't find field \"#{ field }\" in " +
162
- "#{ self } domain class"
163
- raise( MissingError, errStr, caller )
164
- end
165
- end
166
-
167
- def DomainObject.dependentClasses #:nodoc:
168
- dependentClasses = {}
169
- DomainObject.subclasses.each { |aClass|
170
- if aClass != DomainObjectProxy &&
171
- (!DomainObject.abstractSubclasses.index(aClass))
172
- aClass.classFields.each { |field|
173
- if field.class <= LinkField && field.linkedType == self.objectType
174
- dependentClasses[aClass] = field
175
- end
176
- }
177
- end
178
- }
179
- dependentClasses
180
- end
181
-
182
- def DomainObject.objectType #:nodoc:
183
- self
184
- end
185
-
186
- # Returns an array of all fields defined for this class and all concrete
187
- # superclasses.
188
- def DomainObject.allFields
189
- allFields = []
190
- selfAndConcreteSuperclasses.each { |aClass|
191
- aClass.classFields.each { |field| allFields << field }
192
- }
193
- allFields
194
- end
195
-
196
- def DomainObject.inherited(subclass) #:nodoc:
197
- @@subclassHash[subclass] = true
198
- end
199
-
200
- def DomainObject.subclasses #:nodoc:
201
- @@subclassHash.keys
202
- end
203
-
204
- def DomainObject.isConcrete? #:nodoc:
205
- (self != DomainObject && abstractSubclasses.index(self).nil?)
206
- end
207
-
208
- def DomainObject.isBasedOn? #:nodoc:
209
- self.superclass.isConcrete?
210
- end
211
-
212
- def self.getDomainDirs #:nodoc:
213
- config = LafcadioConfig.new
214
- classPath = config['classpath']
215
- domainDirStr = config['domainDirs']
216
- if domainDirStr
217
- domainDirs = domainDirStr.split(',')
218
- else
219
- domainDirs = [ classPath + 'domain/' ]
220
- end
221
- end
222
-
223
- def self.getObjectTypeFromString(typeString) #:nodoc:
224
- require 'lafcadio/objectStore/CouldntMatchObjectTypeError'
225
- objectType = nil
226
- typeString =~ /([^\:]*)$/
227
- fileName = $1
228
- getDomainDirs.each { |domainDir|
229
- if Dir.entries(domainDir).index("#{fileName}.rb")
230
- require "#{ domainDir }#{ fileName }"
231
- end
232
- }
233
- if (domainFilesStr = LafcadioConfig.new['domainFiles'])
234
- domainFilesStr.split(',').each { |domainFile|
235
- require domainFile
236
- }
237
- end
238
- subclasses.each { |subclass|
239
- objectType = subclass if subclass.to_s == typeString
240
- }
241
- if objectType
242
- objectType
243
- else
244
- raise CouldntMatchObjectTypeError,
245
- "couldn't match objectType #{typeString}", caller
246
- end
247
- end
248
-
249
- attr_accessor :errorMessages, :pkId, :lastCommit, :fields, :fields_set
250
- attr_reader :delete
251
- protected :fields, :fields_set
252
-
253
- # fieldHash should contain key-value associations for the different
254
- # fields of this domain class. For example, instantiating a User class
255
- # might look like:
256
- #
257
- # User.new( 'firstNames' => 'John', 'lastName' => 'Doe',
258
- # 'email' => 'john.doe@email.com', 'password' => 'l33t' )
259
- #
260
- # In normal usage any code you write that creates a domain object will not
261
- # define the +pkId+ field. The system assumes that a domain object with an
262
- # undefined +pkId+ has yet to be inserted into the database, and when you
263
- # commit the domain object a +pkId+ will automatically be assigned.
264
- #
265
- # If you're creating mock objects for unit tests, you can explicitly set
266
- # the +pkId+ to represent objects that already exist in the database.
267
- def initialize(fieldHash)
268
- @fieldHash = fieldHash
269
- @pkId = fieldHash['pkId']
270
- @pkId = @pkId.to_i unless @pkId.nil?
271
- @errorMessages = []
272
- @fields = {}
273
- @fields_set = []
274
- end
275
-
276
- def method_missing( methId, *args ) #:nodoc:
277
- if ( field = get_setter_field( methId ) )
278
- set_field( field, args.first )
279
- elsif ( field = get_getter_field( methId ) )
280
- get_field( field )
281
- else
282
- super( methId, *args )
283
- end
284
- end
285
-
286
- def get_getter_field( methId ) #:nodoc:
287
- begin
288
- self.class.getField( methId.id2name )
289
- rescue MissingError
290
- nil
291
- end
292
- end
293
-
294
- def get_setter_field( methId ) #:nodoc:
295
- if methId.id2name =~ /(.*)=$/
296
- begin
297
- self.class.getField( $1 )
298
- rescue MissingError
299
- nil
300
- end
301
- else
302
- nil
303
- end
304
- end
305
-
306
- def get_field( field ) #:nodoc:
307
- unless @fields_set.include?( field )
308
- set_field( field, @fieldHash[field.name] )
309
- end
310
- @fields[field.name]
311
- end
312
-
313
- def set_field( field, value ) #:nodoc:
314
- if field.class <= LinkField
315
- if value.class != DomainObjectProxy && value
316
- value = DomainObjectProxy.new(value)
317
- end
318
- end
319
- @fields[field.name] = value
320
- @fields_set << field
321
- end
322
-
323
- # Returns the subclass of DomainObject that this instance represents.
324
- # Because of the way that proxying works, clients should call this method
325
- # instead of Object.class.
326
- def objectType
327
- self.class.objectType
328
- end
329
-
330
- # This template method is called before every commit. Subclasses can
331
- # override it to ensure code is executed before a commit.
332
- def preCommitTrigger
333
- nil
334
- end
335
-
336
- # This template method is called after every commit. Subclasses can
337
- # override it to ensure code is executed after a commit.
338
- def postCommitTrigger
339
- nil
340
- end
341
-
342
- # Set the delete value to true if you want this domain object to be deleted
343
- # from the database during its next commit.
344
- def delete=(value)
345
- if value && !pkId
346
- raise "No point deleting an object that's not already in the DB"
347
- end
348
- @delete = value
349
- end
350
-
351
- # By default, to_s is considered an invalid operation for domain objects,
352
- # and will raise an error. This behavior can be overridden by subclasses.
353
- def to_s
354
- raise "Don't make me into a string unless the type asks"
355
- end
356
-
357
- # Returns a clone, with all of the fields copied.
358
- def clone
359
- copy = super
360
- copy.fields = @fields.clone
361
- copy.fields_set = @fields_set.clone
362
- copy
363
- end
364
-
365
- # Commits this domain object to the database.
366
- def commit
367
- require 'lafcadio/objectStore/ObjectStore'
368
- ObjectStore.getObjectStore.commit self
369
- end
370
- end
371
- end
@@ -1,22 +0,0 @@
1
- require 'lafcadio/domain/DomainObject'
2
-
3
- module Lafcadio
4
- # Any domain class that is used mostly to map between two other domain
5
- # classes should be a subclass of MapObject. Subclasses of MapObject should
6
- # override MapObject.mappedTypes, returning a two-element array containing
7
- # the domain classes that the map object maps between.
8
- class MapObject < DomainObject
9
- def MapObject.otherMappedType(firstType) #:nodoc:
10
- types = mappedTypes
11
- if types.index(firstType) == 0
12
- types[1]
13
- else
14
- types[0]
15
- end
16
- end
17
-
18
- def MapObject.subsidiaryMap #:nodoc:
19
- nil
20
- end
21
- end
22
- end
@@ -1,80 +0,0 @@
1
- require 'lafcadio/domain'
2
- require 'lafcadio/util'
3
-
4
- module Lafcadio
5
- # A utility class that handles a few details for the DomainObject class. All
6
- # the methods here are usually called as methods of DomainObject, and then
7
- # delegated to this class.
8
- class ObjectType
9
- @@instances = {}
10
-
11
- def self.flush #:nodoc:
12
- @@instances = {}
13
- end
14
-
15
- def self.getObjectType( aClass ) #:nodoc:
16
- instance = @@instances[aClass]
17
- if instance.nil?
18
- @@instances[aClass] = new( aClass )
19
- instance = @@instances[aClass]
20
- end
21
- instance
22
- end
23
-
24
- private_class_method :new
25
-
26
- def initialize(objectType) #:nodoc:
27
- @objectType = objectType
28
- ( @classFields, @xmlParser ) = [ nil, nil ]
29
- dirName = LafcadioConfig.new['classDefinitionDir']
30
- xmlFileName = @objectType.bareName + '.xml'
31
- xmlPath = File.join( dirName, xmlFileName )
32
- xml = ''
33
- begin
34
- File.open( xmlPath ) { |file| xml = file.readlines.join }
35
- @xmlParser = ClassDefinitionXmlParser.new( @objectType, xml )
36
- rescue Errno::ENOENT
37
- # no xml file, so no @xmlParser
38
- end
39
- end
40
-
41
- # Returns an Array of ObjectField instances for this domain class, parsing
42
- # them from XML if necessary.
43
- def getClassFields
44
- unless @classFields
45
- if @xmlParser
46
- @classFields = @xmlParser.getClassFields
47
- else
48
- error_msg = "Couldn't find either an XML class description file " +
49
- "or getClassFields method for " + @objectType.name
50
- raise MissingError, error_msg, caller
51
- end
52
- end
53
- @classFields
54
- end
55
-
56
- # Returns the name of the primary key in the database, retrieving it from
57
- # the class definition XML if necessary.
58
- def sqlPrimaryKeyName
59
- if !@xmlParser.nil? && ( spkn = @xmlParser.sqlPrimaryKeyName )
60
- spkn
61
- else
62
- 'pkId'
63
- end
64
- end
65
-
66
- # Returns the table name, which is assumed to be the domain class name
67
- # pluralized, and with the first letter lowercase. A User class is
68
- # assumed to be stored in a "users" table, while a ProductCategory class is
69
- # assumed to be stored in a "productCategories" table.
70
- def tableName
71
- if (!@xmlParser.nil? && tableName = @xmlParser.tableName)
72
- tableName
73
- else
74
- tableName = @objectType.bareName
75
- tableName[0] = tableName[0..0].downcase
76
- English.plural tableName
77
- end
78
- end
79
- end
80
- end