lafcadio 0.6.6 → 0.7.0

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.6"
19
+ Version = "0.7.0"
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.5"
19
+ Version = "0.6.0"
20
20
 
21
21
  require 'lafcadio/dateTime'
22
22
  require 'lafcadio/depend'
@@ -1,4 +1,3 @@
1
- require 'extensions/module'
2
1
  require 'lafcadio/objectField'
3
2
  require 'lafcadio/util'
4
3
  require 'rexml/document'
@@ -278,13 +277,6 @@ module Lafcadio
278
277
  unless class_fields
279
278
  @@class_fields[self] = self.get_class_fields
280
279
  class_fields = @@class_fields[self]
281
- class_fields.each do |class_field|
282
- begin
283
- undef_method class_field.name.to_sym
284
- rescue NameError
285
- # not defined globally or in an included Module, skip it
286
- end
287
- end
288
280
  end
289
281
  class_fields
290
282
  end
@@ -295,15 +287,13 @@ module Lafcadio
295
287
  class_fields = [ @@pk_fields[self] ]
296
288
  @@class_fields[self] = class_fields
297
289
  end
298
- unless class_fields.any? { |cf| cf.name == name }
299
- att_hash['name'] = name
300
- field = field_class.instantiate_with_parameters( self, att_hash )
301
- att_hash.each { |field_name, value|
302
- setter = field_name + '='
303
- field.send( setter, value ) if field.respond_to?( setter )
304
- }
305
- class_fields << field
306
- end
290
+ att_hash['name'] = name
291
+ field = field_class.instantiate_with_parameters( self, att_hash )
292
+ att_hash.each { |field_name, value|
293
+ setter = field_name + '='
294
+ field.send( setter, value ) if field.respond_to?( setter )
295
+ }
296
+ class_fields << field
307
297
  end
308
298
 
309
299
  def self.dependent_classes #:nodoc:
@@ -339,8 +329,6 @@ module Lafcadio
339
329
  def self.get_class_fields
340
330
  if self.methods( false ).include?( 'get_class_fields' )
341
331
  [ @@pk_fields[ self ] ]
342
- elsif abstract_subclasses.include?( self )
343
- []
344
332
  else
345
333
  xmlParser = try_load_xml_parser
346
334
  if xmlParser
@@ -360,7 +348,7 @@ module Lafcadio
360
348
  []
361
349
  end
362
350
  end
363
-
351
+
364
352
  def self.get_field( fieldName ) #:nodoc:
365
353
  aDomainClass = self
366
354
  field = nil
@@ -371,7 +359,7 @@ module Lafcadio
371
359
  if field
372
360
  field
373
361
  else
374
- errStr = "Couldn't find field \"#{ fieldName }\" in " +
362
+ errStr = "Couldn't find field \"#{ field }\" in " +
375
363
  "#{ self } domain class"
376
364
  raise( MissingError, errStr, caller )
377
365
  end
@@ -405,7 +393,8 @@ module Lafcadio
405
393
 
406
394
  def self.method_missing( methodId, *args ) #:nodoc:
407
395
  method_name = methodId.id2name
408
- maybe_field_class_name = method_name.underscore_to_camel_case + 'Field'
396
+ maybe_field_class_name = ( method_name.gsub( /^(.)/ ) { $&.upcase } ) +
397
+ 'Field'
409
398
  field_class = Lafcadio.const_get( maybe_field_class_name )
410
399
  create_field( field_class, args[0], args[1] || {} )
411
400
  end
@@ -1,4 +1,3 @@
1
- require 'extensions/module'
2
1
  require 'lafcadio/objectField'
3
2
  require 'lafcadio/util'
4
3
  require 'rexml/document'
@@ -278,13 +277,6 @@ module Lafcadio
278
277
  unless class_fields
279
278
  @@class_fields[self] = self.get_class_fields
280
279
  class_fields = @@class_fields[self]
281
- class_fields.each do |class_field|
282
- begin
283
- undef_method class_field.name.to_sym
284
- rescue NameError
285
- # not defined globally or in an included Module, skip it
286
- end
287
- end
288
280
  end
289
281
  class_fields
290
282
  end
@@ -337,8 +329,6 @@ module Lafcadio
337
329
  def self.get_class_fields
338
330
  if self.methods( false ).include?( 'get_class_fields' )
339
331
  [ @@pk_fields[ self ] ]
340
- elsif abstract_subclasses.include?( self )
341
- []
342
332
  else
343
333
  xmlParser = try_load_xml_parser
344
334
  if xmlParser
@@ -352,13 +342,16 @@ module Lafcadio
352
342
  end
353
343
 
354
344
  def self.get_domain_dirs #:nodoc:
355
- if ( domainDirStr = LafcadioConfig.new['domainDirs'] )
356
- domainDirStr.split(',')
345
+ config = LafcadioConfig.new
346
+ classPath = config['classpath']
347
+ domainDirStr = config['domainDirs']
348
+ if domainDirStr
349
+ domainDirs = domainDirStr.split(',')
357
350
  else
358
- []
351
+ domainDirs = [ classPath + 'domain/' ]
359
352
  end
360
353
  end
361
-
354
+
362
355
  def self.get_field( fieldName ) #:nodoc:
363
356
  aDomainClass = self
364
357
  field = nil
@@ -369,7 +362,7 @@ module Lafcadio
369
362
  if field
370
363
  field
371
364
  else
372
- errStr = "Couldn't find field \"#{ fieldName }\" in " +
365
+ errStr = "Couldn't find field \"#{ field }\" in " +
373
366
  "#{ self } domain class"
374
367
  raise( MissingError, errStr, caller )
375
368
  end
@@ -403,7 +396,8 @@ module Lafcadio
403
396
 
404
397
  def self.method_missing( methodId, *args ) #:nodoc:
405
398
  method_name = methodId.id2name
406
- maybe_field_class_name = method_name.underscore_to_camel_case + 'Field'
399
+ maybe_field_class_name = ( method_name.gsub( /^(.)/ ) { $&.upcase } ) +
400
+ 'Field'
407
401
  field_class = Lafcadio.const_get( maybe_field_class_name )
408
402
  create_field( field_class, args[0], args[1] || {} )
409
403
  end
data/lib/lafcadio/mock.rb CHANGED
@@ -11,6 +11,9 @@ module Lafcadio
11
11
  end
12
12
 
13
13
  def commit(db_object)
14
+ if db_object.pk_id and !db_object.pk_id.is_a?( Integer )
15
+ raise ArgumentError
16
+ end
14
17
  objects_by_domain_class = get_objects_by_domain_class(
15
18
  db_object.domain_class
16
19
  )
@@ -28,7 +31,7 @@ module Lafcadio
28
31
  end
29
32
 
30
33
  def get_collection_by_query(query)
31
- @query_count[query] += 1
34
+ @query_count[query.to_sql] += 1
32
35
  objects = []
33
36
  _get_all( query.domain_class ).each { |dbObj|
34
37
  if query.condition
@@ -37,14 +40,12 @@ module Lafcadio
37
40
  objects << dbObj
38
41
  end
39
42
  }
43
+ if (range = query.limit)
44
+ objects = objects[0..(range.last - range.first)]
45
+ end
40
46
  if ( order_by = query.order_by )
41
47
  objects = objects.sort_by { |dobj| dobj.send( order_by ) }
42
48
  objects.reverse! if query.order_by_order == Query::DESC
43
- else
44
- objects = objects.sort_by { |dobj| dobj.pk_id }
45
- end
46
- if (range = query.limit)
47
- objects = objects[range]
48
49
  end
49
50
  objects
50
51
  end
@@ -74,14 +75,10 @@ module Lafcadio
74
75
 
75
76
  def group_query( query )
76
77
  if query.class == Query::Max
77
- dobjs_by_pk_id = @objects[query.domain_class]
78
- if dobjs_by_pk_id
79
- dobjs = dobjs_by_pk_id.values.sort_by { |dobj|
80
- dobj.send( query.field_name )
81
- }
82
- [ dobjs.last.send( query.field_name ) ]
78
+ if ( query.field_name == 'pk_id' || query.field_name == 'rate' )
79
+ query.collect( @objects[query.domain_class].values )
83
80
  else
84
- [ nil ]
81
+ raise "Can't handle query with sql '#{ query.to_sql }'"
85
82
  end
86
83
  end
87
84
  end
@@ -11,6 +11,9 @@ module Lafcadio
11
11
  end
12
12
 
13
13
  def commit(db_object)
14
+ if db_object.pk_id and !db_object.pk_id.is_a?( Integer )
15
+ raise ArgumentError
16
+ end
14
17
  objects_by_domain_class = get_objects_by_domain_class(
15
18
  db_object.domain_class
16
19
  )
@@ -28,7 +31,7 @@ module Lafcadio
28
31
  end
29
32
 
30
33
  def get_collection_by_query(query)
31
- @query_count[query] += 1
34
+ @query_count[query.to_sql] += 1
32
35
  objects = []
33
36
  _get_all( query.domain_class ).each { |dbObj|
34
37
  if query.condition
@@ -37,14 +40,12 @@ module Lafcadio
37
40
  objects << dbObj
38
41
  end
39
42
  }
43
+ if (range = query.limit)
44
+ objects = objects[0..(range.last - range.first)]
45
+ end
40
46
  if ( order_by = query.order_by )
41
47
  objects = objects.sort_by { |dobj| dobj.send( order_by ) }
42
48
  objects.reverse! if query.order_by_order == Query::DESC
43
- else
44
- objects = objects.sort_by { |dobj| dobj.pk_id }
45
- end
46
- if (range = query.limit)
47
- objects = objects[range]
48
49
  end
49
50
  objects
50
51
  end
@@ -424,7 +424,7 @@ module Lafcadio
424
424
  unless name
425
425
  linked_type.name =~ /::/
426
426
  name = $' || linked_type.name
427
- name = name.camel_case_to_underscore
427
+ name = name.decapitalize
428
428
  end
429
429
  super( domain_class, name )
430
430
  ( @linked_type, @delete_cascade ) = linked_type, delete_cascade
@@ -11,10 +11,9 @@ module Lafcadio
11
11
 
12
12
  attr_reader :commit_type, :db_object
13
13
 
14
- def initialize(db_object, dbBridge, cache)
14
+ def initialize(db_object, dbBridge)
15
15
  @db_object = db_object
16
16
  @dbBridge = dbBridge
17
- @cache = cache
18
17
  @objectStore = ObjectStore.get_object_store
19
18
  @commit_type = nil
20
19
  end
@@ -29,7 +28,6 @@ module Lafcadio
29
28
  unless @db_object.pk_id
30
29
  @db_object.pk_id = @dbBridge.last_pk_id_inserted
31
30
  end
32
- @cache.update_after_commit self
33
31
  @db_object.post_commit_trigger
34
32
  end
35
33
 
@@ -131,8 +129,12 @@ module Lafcadio
131
129
 
132
130
  def group_query( query )
133
131
  execute_select( query.to_sql )[0].collect { |val|
134
- a_field = query.domain_class.get_field( query.field_name )
135
- a_field.value_from_sql( val )
132
+ if query.field_name != query.domain_class.sql_primary_key_name
133
+ a_field = query.domain_class.get_field( query.field_name )
134
+ a_field.value_from_sql( val )
135
+ else
136
+ val.to_i
137
+ end
136
138
  }
137
139
  end
138
140
 
@@ -441,7 +443,7 @@ module Lafcadio
441
443
  def get_db_bridge; @dbBridge; end
442
444
 
443
445
  def get_field_name( domain_object )
444
- domain_object.domain_class.basename.camel_case_to_underscore
446
+ domain_object.domain_class.basename.decapitalize
445
447
  end
446
448
 
447
449
  def get_filtered(domain_class_name, searchTerm, fieldName = nil) #:nodoc:
@@ -538,8 +540,9 @@ module Lafcadio
538
540
  end
539
541
 
540
542
  def commit( db_object )
541
- committer = Committer.new db_object, @dbBridge, self
543
+ committer = Committer.new db_object, @dbBridge
542
544
  committer.execute
545
+ update_after_commit( committer )
543
546
  end
544
547
 
545
548
  # Flushes a domain object.
@@ -570,11 +573,23 @@ module Lafcadio
570
573
 
571
574
  def get_by_query( query )
572
575
  unless @collections_by_query[query]
573
- newObjects = @dbBridge.get_collection_by_query(query)
574
- newObjects.each { |dbObj| save dbObj }
575
- @collections_by_query[query] = newObjects.collect { |dobj|
576
- dobj.pk_id
577
- }
576
+ superset_query, pk_ids =
577
+ @collections_by_query.find { |other_query, pk_ids|
578
+ query.implies?( other_query )
579
+ }
580
+ if pk_ids
581
+ @collections_by_query[query] = ( pk_ids.collect { |pk_id|
582
+ get( query.domain_class, pk_id )
583
+ } ).select { |dobj| query.object_meets( dobj ) }.collect { |dobj|
584
+ dobj.pk_id
585
+ }
586
+ elsif @collections_by_query.values
587
+ newObjects = @dbBridge.get_collection_by_query(query)
588
+ newObjects.each { |dbObj| save dbObj }
589
+ @collections_by_query[query] = newObjects.collect { |dobj|
590
+ dobj.pk_id
591
+ }
592
+ end
578
593
  end
579
594
  collection = []
580
595
  @collections_by_query[query].each { |pk_id|
@@ -129,8 +129,12 @@ module Lafcadio
129
129
 
130
130
  def group_query( query )
131
131
  execute_select( query.to_sql )[0].collect { |val|
132
- a_field = query.domain_class.get_field( query.field_name )
133
- a_field.value_from_sql( val )
132
+ if query.field_name != query.domain_class.sql_primary_key_name
133
+ a_field = query.domain_class.get_field( query.field_name )
134
+ a_field.value_from_sql( val )
135
+ else
136
+ val.to_i
137
+ end
134
138
  }
135
139
  end
136
140
 
@@ -439,7 +443,7 @@ module Lafcadio
439
443
  def get_db_bridge; @dbBridge; end
440
444
 
441
445
  def get_field_name( domain_object )
442
- domain_object.domain_class.basename.camel_case_to_underscore
446
+ domain_object.domain_class.basename.decapitalize
443
447
  end
444
448
 
445
449
  def get_filtered(domain_class_name, searchTerm, fieldName = nil) #:nodoc:
@@ -140,17 +140,30 @@ module Lafcadio
140
140
  def limit_clause
141
141
  "limit #{ @limit.begin }, #{ @limit.end - @limit.begin + 1 }" if @limit
142
142
  end
143
+
144
+ def object_meets( dobj ); @condition.object_meets( dobj ); end
143
145
 
144
146
  def or( &action ); compound( CompoundCondition::OR, action ); end
145
147
 
146
148
  def order_clause
147
149
  if @order_by
148
- order_by_field = @domain_class.get_field( @order_by )
149
- clause = "order by #{ order_by_field.db_field_name } "
150
+ clause = "order by #{ @order_by } "
150
151
  clause += @order_by_order == ASC ? 'asc' : 'desc'
151
152
  clause
152
153
  end
153
154
  end
155
+
156
+ def implies?( other_query )
157
+ if other_query == self
158
+ true
159
+ elsif @domain_class == other_query.domain_class
160
+ if other_query.condition.nil? and !self.condition.nil?
161
+ true
162
+ else
163
+ self.condition and self.condition.implies?( other_query.condition )
164
+ end
165
+ end
166
+ end
154
167
 
155
168
  def sql_primary_key_field(domain_class)
156
169
  "#{ domain_class.table_name }.#{ domain_class.sql_primary_key_name }"
@@ -208,9 +221,34 @@ module Lafcadio
208
221
  end
209
222
  end
210
223
 
224
+ def implies?( other_condition )
225
+ self.eql?( other_condition ) or (
226
+ other_condition.respond_to?( :implied_by? ) and
227
+ other_condition.implied_by?( self )
228
+ )
229
+ end
230
+
211
231
  def db_field_name; get_field.db_table_and_field_name; end
212
232
 
213
- def get_field; @domain_class.get_field( @fieldName ); end
233
+ def eql?( other_cond )
234
+ other_cond.is_a?( Condition ) and other_cond.to_sql == to_sql
235
+ end
236
+
237
+ def get_field
238
+ a_domain_class = @domain_class
239
+ field = nil
240
+ while ( a_domain_class < DomainObject ) && !field
241
+ field = a_domain_class.get_class_field( @fieldName )
242
+ a_domain_class = a_domain_class.superclass
243
+ end
244
+ if field
245
+ field
246
+ else
247
+ errStr = "Couldn't find field \"#{ @fieldName }\" in " +
248
+ "#{ @domain_class } domain class"
249
+ raise( MissingError, errStr, caller )
250
+ end
251
+ end
214
252
 
215
253
  def query; Query.new( @domain_class, self ); end
216
254
 
@@ -272,22 +310,38 @@ module Lafcadio
272
310
  class CompoundCondition < Condition #:nodoc:
273
311
  AND = 1
274
312
  OR = 2
275
-
276
- def initialize( *args )
277
- if( [ AND, OR ].index( args.last) )
278
- @compoundType = args.last
279
- args.pop
313
+
314
+ def initialize(*conditions)
315
+ if( [ AND, OR ].index(conditions.last) )
316
+ @compound_type = conditions.last
317
+ conditions.pop
280
318
  else
281
- @compoundType = AND
319
+ @compound_type = AND
282
320
  end
283
- @conditions = args.map { |arg|
284
- arg.respond_to?( :to_condition ) ? arg.to_condition : arg
321
+ @conditions = conditions
322
+ @domain_class = conditions[0].domain_class
323
+ end
324
+
325
+ def implied_by?( other_condition )
326
+ @compound_type == OR && @conditions.any? { |cond|
327
+ cond.implies?( other_condition )
285
328
  }
286
- @domain_class = @conditions[0].domain_class
329
+ end
330
+
331
+ def implies?( other_condition )
332
+ super( other_condition ) or (
333
+ @compound_type == AND and @conditions.any? { |cond|
334
+ cond.implies?( other_condition )
335
+ }
336
+ ) or (
337
+ @compound_type == OR and @conditions.all? { |cond|
338
+ cond.implies?( other_condition )
339
+ }
340
+ )
287
341
  end
288
342
 
289
343
  def object_meets(anObj)
290
- if @compoundType == AND
344
+ if @compound_type == AND
291
345
  @conditions.inject( true ) { |result, cond|
292
346
  result && cond.object_meets( anObj )
293
347
  }
@@ -299,7 +353,7 @@ module Lafcadio
299
353
  end
300
354
 
301
355
  def to_sql
302
- booleanString = @compoundType == AND ? 'and' : 'or'
356
+ booleanString = @compound_type == AND ? 'and' : 'or'
303
357
  subSqlStrings = @conditions.collect { |cond| cond.to_sql }
304
358
  "(#{ subSqlStrings.join(" #{ booleanString } ") })"
305
359
  end
@@ -415,11 +469,11 @@ module Lafcadio
415
469
 
416
470
  def get_regexp
417
471
  if @matchType == PRE_AND_POST
418
- Regexp.new( @searchTerm, Regexp::IGNORECASE )
472
+ Regexp.new(@searchTerm)
419
473
  elsif @matchType == PRE_ONLY
420
- Regexp.new( @searchTerm.to_s + "$", Regexp::IGNORECASE )
474
+ Regexp.new(@searchTerm.to_s + "$")
421
475
  elsif @matchType == POST_ONLY
422
- Regexp.new( "^" + @searchTerm, Regexp::IGNORECASE )
476
+ Regexp.new("^" + @searchTerm)
423
477
  end
424
478
  end
425
479
 
@@ -145,8 +145,7 @@ module Lafcadio
145
145
 
146
146
  def order_clause
147
147
  if @order_by
148
- order_by_field = @domain_class.get_field( @order_by )
149
- clause = "order by #{ order_by_field.db_field_name } "
148
+ clause = "order by #{ @order_by } "
150
149
  clause += @order_by_order == ASC ? 'asc' : 'desc'
151
150
  clause
152
151
  end
@@ -210,7 +209,21 @@ module Lafcadio
210
209
 
211
210
  def db_field_name; get_field.db_table_and_field_name; end
212
211
 
213
- def get_field; @domain_class.get_field( @fieldName ); end
212
+ def get_field
213
+ a_domain_class = @domain_class
214
+ field = nil
215
+ while ( a_domain_class < DomainObject ) && !field
216
+ field = a_domain_class.get_class_field( @fieldName )
217
+ a_domain_class = a_domain_class.superclass
218
+ end
219
+ if field
220
+ field
221
+ else
222
+ errStr = "Couldn't find field \"#{ @fieldName }\" in " +
223
+ "#{ @domain_class } domain class"
224
+ raise( MissingError, errStr, caller )
225
+ end
226
+ end
214
227
 
215
228
  def query; Query.new( @domain_class, self ); end
216
229
 
@@ -273,17 +286,15 @@ module Lafcadio
273
286
  AND = 1
274
287
  OR = 2
275
288
 
276
- def initialize( *args )
277
- if( [ AND, OR ].index( args.last) )
278
- @compoundType = args.last
279
- args.pop
289
+ def initialize(*conditions)
290
+ if( [ AND, OR ].index(conditions.last) )
291
+ @compoundType = conditions.last
292
+ conditions.pop
280
293
  else
281
294
  @compoundType = AND
282
295
  end
283
- @conditions = args.map { |arg|
284
- arg.respond_to?( :to_condition ) ? arg.to_condition : arg
285
- }
286
- @domain_class = @conditions[0].domain_class
296
+ @conditions = conditions
297
+ @domain_class = conditions[0].domain_class
287
298
  end
288
299
 
289
300
  def object_meets(anObj)
@@ -0,0 +1,13 @@
1
+ dbuser:test
2
+ dbpassword:password
3
+ dbname:test
4
+ dbhost:localhost
5
+ adminEmail:john.doe@email.com
6
+ siteName:Site Name
7
+ url:http://test.url
8
+ classpath:lafcadio/
9
+ logdir:../test/testOutput/
10
+ domainDirs:../test/mock/domain/
11
+ domainFiles:../test/mock/domain.rb
12
+ logSql:n
13
+ classDefinitionDir:../test/testData
data/lib/lafcadio/util.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'delegate'
2
- require 'lafcadio/depend'
3
2
  require 'singleton'
4
3
 
5
4
  module Lafcadio
@@ -67,16 +66,14 @@ module Lafcadio
67
66
  class ContextualService
68
67
  def self.flush; Context.instance.set_resource( self, nil ); end
69
68
 
70
- def self.method_missing( symbol, *args )
71
- method_name = symbol.id2name
72
- target = nil
73
- if method_name =~ /^get_(.*)/
74
- target = :get_resource if $1.underscore_to_camel_case == basename
75
- elsif method_name =~ /^set_(.*)/
76
- target = :set_resource if $1.underscore_to_camel_case == basename
77
- end
78
- if target
79
- Context.instance.send( target, self, *args )
69
+ def self.method_missing( methodId, *args )
70
+ methodName = methodId.id2name
71
+ if methodName =~ /^get_(.*)/ || methodName =~ /^set_(.*)/
72
+ if methodName =~ /^get_(.*)/
73
+ Context.instance.get_resource( self )
74
+ else
75
+ Context.instance.set_resource( self, *args )
76
+ end
80
77
  else
81
78
  super
82
79
  end
@@ -133,12 +130,8 @@ module Lafcadio
133
130
  consonantYPattern = Regexp.new("([^aeiou])y$", Regexp::IGNORECASE)
134
131
  if singular =~ consonantYPattern
135
132
  singular.gsub consonantYPattern, '\1ies'
136
- elsif singular =~ /^(.*)xis$/
137
- $1 + 'xes'
138
133
  elsif singular =~ /[xs]$/
139
134
  singular + "es"
140
- elsif singular =~ /(.*)tum$/
141
- $1 + 'ta'
142
135
  else
143
136
  singular + "s"
144
137
  end
@@ -1,5 +1,4 @@
1
1
  require 'delegate'
2
- require 'lafcadio/depend'
3
2
  require 'singleton'
4
3
 
5
4
  module Lafcadio
@@ -67,16 +66,14 @@ module Lafcadio
67
66
  class ContextualService
68
67
  def self.flush; Context.instance.set_resource( self, nil ); end
69
68
 
70
- def self.method_missing( symbol, *args )
71
- method_name = symbol.id2name
72
- target = nil
73
- if method_name =~ /^get_(.*)/
74
- target = :get_resource if $1.underscore_to_camel_case == basename
75
- elsif method_name =~ /^set_(.*)/
76
- target = :set_resource if $1.underscore_to_camel_case == basename
77
- end
78
- if target
79
- Context.instance.send( target, self, *args )
69
+ def self.method_missing( methodId, *args )
70
+ methodName = methodId.id2name
71
+ if methodName =~ /^get_(.*)/ || methodName =~ /^set_(.*)/
72
+ if methodName =~ /^get_(.*)/
73
+ Context.instance.get_resource( self )
74
+ else
75
+ Context.instance.set_resource( self, *args )
76
+ end
80
77
  else
81
78
  super
82
79
  end
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.8.6
2
+ rubygems_version: 0.8.1
3
3
  specification_version: 1
4
4
  name: lafcadio
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.6.6
7
- date: 2005-08-14
6
+ version: 0.7.0
7
+ date: 2005-01-20
8
8
  summary: Lafcadio is an object-relational mapping layer
9
9
  require_paths:
10
10
  - lib
11
+ author: Francis Hwang
11
12
  email: sera@fhwang.net
12
13
  homepage: http://lafcadio.rubyforge.org/
13
14
  rubyforge_project:
@@ -28,8 +29,6 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
28
29
  version: 0.0.0
29
30
  version:
30
31
  platform: ruby
31
- authors:
32
- - Francis Hwang
33
32
  files:
34
33
  - lib/lafcadio
35
34
  - lib/lafcadio.rb
@@ -41,7 +40,6 @@ files:
41
40
  - lib/lafcadio/mock.rb
42
41
  - lib/lafcadio/mock.rb~
43
42
  - lib/lafcadio/objectField.rb
44
- - lib/lafcadio/objectField.rb~
45
43
  - lib/lafcadio/objectStore.rb
46
44
  - lib/lafcadio/objectStore.rb~
47
45
  - lib/lafcadio/query.rb
@@ -52,6 +50,7 @@ files:
52
50
  - lib/lafcadio/util.rb
53
51
  - lib/lafcadio/util.rb~
54
52
  - lib/lafcadio/test/testconfig.dat
53
+ - lib/lafcadio/test/testconfig.dat~
55
54
  test_files: []
56
55
  rdoc_options: []
57
56
  extra_rdoc_files: []
@@ -1,561 +0,0 @@
1
- require 'date'
2
- require 'lafcadio/dateTime'
3
- require 'lafcadio/util'
4
-
5
- module Lafcadio
6
- # ObjectField is the abstract base class of any field for domain objects.
7
- class ObjectField
8
- include Comparable
9
-
10
- attr_reader :name, :domain_class
11
- attr_accessor :not_null, :db_field_name
12
-
13
- def self.instantiate_from_xml( domain_class, fieldElt ) #:nodoc:
14
- parameters = instantiation_parameters( fieldElt )
15
- instantiate_with_parameters( domain_class, parameters )
16
- end
17
-
18
- def self.instantiate_with_parameters( domain_class, parameters ) #:nodoc:
19
- instance = self.new( domain_class, parameters['name'] )
20
- if ( db_field_name = parameters['db_field_name'] )
21
- instance.db_field_name = db_field_name
22
- end
23
- instance
24
- end
25
-
26
- def self.instantiation_parameters( fieldElt ) #:nodoc:
27
- parameters = {}
28
- parameters['name'] = fieldElt.attributes['name']
29
- parameters['db_field_name'] = fieldElt.attributes['db_field_name']
30
- parameters
31
- end
32
-
33
- def self.value_type #:nodoc:
34
- Object
35
- end
36
-
37
- # [domain_class] The domain class that this object field belongs to.
38
- # [name] The name of this field.
39
- def initialize( domain_class, name )
40
- @domain_class = domain_class
41
- @name = name
42
- @db_field_name = name
43
- @not_null = true
44
- end
45
-
46
- def <=>(other)
47
- if @domain_class == other.domain_class && name == other.name
48
- 0
49
- else
50
- object_id <=> other.object_id
51
- end
52
- end
53
-
54
- def bind_write?; false; end #:nodoc:
55
-
56
- def db_table_and_field_name
57
- "#{ domain_class.table_name }.#{ db_field_name }"
58
- end
59
-
60
- def db_will_automatically_write #:nodoc:
61
- false
62
- end
63
-
64
- # Returns the name that this field is referenced by in the MySQL table. By
65
- # default this is the same as the name; to override it, set
66
- # ObjectField#db_field_name.
67
- def name_for_sql
68
- db_field_name
69
- end
70
-
71
- def prev_value(pk_id) #:nodoc:
72
- prevObject = ObjectStore.get_object_store.get( @domain_class, pk_id )
73
- prevObject.send(name)
74
- end
75
-
76
- def process_before_verify(value) #:nodoc:
77
- value = @default if value == nil
78
- value
79
- end
80
-
81
- # Returns a string value suitable for committing this field's value to
82
- # MySQL.
83
- def value_for_sql(value)
84
- value || 'null'
85
- end
86
-
87
- def verify(value, pk_id) #:nodoc:
88
- if value.nil? && not_null
89
- raise(
90
- FieldValueError,
91
- "#{ self.domain_class.name }##{ name } can not be nil.",
92
- caller
93
- )
94
- end
95
- verify_non_nil( value, pk_id ) if value
96
- end
97
-
98
- def verify_non_nil( value, pk_id )
99
- value_type = self.class.value_type
100
- unless value.class <= value_type
101
- raise(
102
- FieldValueError,
103
- "#{ domain_class.name }##{ name } needs a " + value_type.name +
104
- " value.",
105
- caller
106
- )
107
- end
108
- end
109
-
110
- # Given the SQL value string, returns a Ruby-native value.
111
- def value_from_sql(string)
112
- string
113
- end
114
- end
115
-
116
- # IntegerField represents an integer.
117
- class IntegerField < ObjectField
118
- def value_from_sql(string) #:nodoc:
119
- value = super
120
- value ? value.to_i : nil
121
- end
122
- end
123
-
124
- # A TextField is expected to contain a string value.
125
- class TextField < ObjectField
126
- def value_for_sql(value) #:nodoc:
127
- if value
128
- value = value.gsub(/(\\?')/) { |m| m.length == 1 ? "''" : m }
129
- value = value.gsub(/\\/) { '\\\\' }
130
- "'#{value}'"
131
- else
132
- "null"
133
- end
134
- end
135
- end
136
-
137
- # BlobField stores a string value and expects to store its value in a BLOB
138
- # field in the database.
139
- class BlobField < ObjectField
140
- attr_accessor :size
141
-
142
- def self.value_type; String; end
143
-
144
- def bind_write?; true; end #:nodoc:
145
-
146
- def value_for_sql(value); "?"; end #:nodoc:
147
- end
148
-
149
- # BooleanField represents a boolean value. By default, it assumes that the
150
- # table field represents True and False with the integers 1 and 0. There are
151
- # two different ways to change this default.
152
- #
153
- # First, BooleanField includes a few enumerated defaults. Currently there are
154
- # only
155
- # * BooleanField::ENUMS_ONE_ZERO (the default, uses integers 1 and 0)
156
- # * BooleanField::ENUMS_CAPITAL_YES_NO (uses characters 'Y' and 'N')
157
- # In the XML class definition, this field would look like
158
- # <field name="field_name" class="BooleanField"
159
- # enum_type="ENUMS_CAPITAL_YES_NO"/>
160
- # If you're defining a field in Ruby, simply set BooleanField#enum_type to one
161
- # of the values.
162
- #
163
- # For more fine-grained specification you can pass specific values in. Use
164
- # this format for the XML class definition:
165
- # <field name="field_name" class="BooleanField">
166
- # <enums>
167
- # <enum key="true">yin</enum>
168
- # <enum key="false">tang</enum>
169
- # </enums>
170
- # </field>
171
- # If you're defining the field in Ruby, set BooleanField#enums to a hash.
172
- # myBooleanField.enums = { true => 'yin', false => 'yang' }
173
- #
174
- # +enums+ takes precedence over +enum_type+.
175
- class BooleanField < ObjectField
176
- ENUMS_ONE_ZERO = 0
177
- ENUMS_CAPITAL_YES_NO = 1
178
-
179
- attr_accessor :enum_type, :enums
180
-
181
- def initialize( domain_class, name )
182
- super( domain_class, name )
183
- @enum_type = ENUMS_ONE_ZERO
184
- @enums = nil
185
- end
186
-
187
- def false_enum # :nodoc:
188
- get_enums[false]
189
- end
190
-
191
- def get_enums( value = nil ) # :nodoc:
192
- if @enums
193
- @enums
194
- elsif @enum_type == ENUMS_ONE_ZERO
195
- if value.class == String
196
- { true => '1', false => '0' }
197
- else
198
- { true => 1, false => 0 }
199
- end
200
- elsif @enum_type == ENUMS_CAPITAL_YES_NO
201
- { true => 'Y', false => 'N' }
202
- else
203
- raise MissingError
204
- end
205
- end
206
-
207
- def text_enum_type # :nodoc:
208
- @enums ? @enums[true].class == String : @enum_type == ENUMS_CAPITAL_YES_NO
209
- end
210
-
211
- def true_enum( value = nil ) # :nodoc:
212
- get_enums( value )[true]
213
- end
214
-
215
- def value_for_sql(value) # :nodoc:
216
- if value
217
- vfs = true_enum
218
- else
219
- vfs = false_enum
220
- end
221
- text_enum_type ? "'#{vfs}'" : vfs
222
- end
223
-
224
- def value_from_sql(value, lookupLink = true) # :nodoc:
225
- value == true_enum( value )
226
- end
227
- end
228
-
229
- # DateField represents a Date.
230
- class DateField < ObjectField
231
- def self.value_type # :nodoc:
232
- Date
233
- end
234
-
235
- def initialize( domain_class, name = "date" )
236
- super( domain_class, name )
237
- end
238
-
239
- def value_for_sql(value) # :nodoc:
240
- value ? "'#{value.to_s}'" : 'null'
241
- end
242
-
243
- def value_from_sql(dbiDate, lookupLink = true) # :nodoc:
244
- begin
245
- dbiDate ? dbiDate.to_date : nil
246
- rescue ArgumentError
247
- nil
248
- end
249
- end
250
- end
251
-
252
- # DateTimeField represents a DateTime.
253
- class DateTimeField < ObjectField
254
- def value_for_sql(value) # :nodoc:
255
- if value
256
- year = value.year
257
- month = value.mon.to_s.pad( 2, "0" )
258
- day = value.day.to_s.pad( 2, "0" )
259
- hour = value.hour.to_s.pad( 2, "0" )
260
- minute = value.min.to_s.pad( 2, "0" )
261
- second = value.sec.to_s.pad( 2, "0" )
262
- "'#{year}-#{month}-#{day} #{hour}:#{minute}:#{second}'"
263
- else
264
- "null"
265
- end
266
- end
267
-
268
- def value_from_sql(dbi_value, lookupLink = true) # :nodoc:
269
- dbi_value ? dbi_value.to_time : nil
270
- end
271
- end
272
-
273
- # DecimalField represents a decimal value.
274
- class DecimalField < ObjectField
275
- def self.instantiate_with_parameters( domain_class, parameters ) #:nodoc:
276
- self.new( domain_class, parameters['name'] )
277
- end
278
-
279
- def self.value_type #:nodoc:
280
- Numeric
281
- end
282
-
283
- def process_before_verify(value) #:nodoc:
284
- value = super value
285
- value != nil && value != '' ? value.to_f : nil
286
- end
287
-
288
- def value_from_sql(string, lookupLink = true) #:nodoc:
289
- string != nil ? string.to_f : nil
290
- end
291
- end
292
-
293
- # EmailField takes a text value that is expected to be formatted as a single
294
- # valid email address.
295
- class EmailField < TextField
296
- # Is +address+ a valid email address?
297
- def self.valid_address(address)
298
- address =~ /^[^ @]+@[^ \.]+\.[^ ,]+$/
299
- end
300
-
301
- def initialize( domain_class, name = "email" )
302
- super( domain_class, name )
303
- end
304
-
305
- def verify_non_nil(value, pk_id) #:nodoc:
306
- super(value, pk_id)
307
- if !EmailField.valid_address(value)
308
- raise(
309
- FieldValueError,
310
- "#{ domain_class.name }##{ name } needs a valid email address.",
311
- caller
312
- )
313
- end
314
- end
315
- end
316
-
317
- # EnumField represents an enumerated field that can only be set to one of a
318
- # set range of string values. To set the enumeration in the class definition
319
- # XML, use the following format:
320
- # <field name="flavor" class="EnumField">
321
- # <enums>
322
- # <enum>Vanilla</enum>
323
- # <enum>Chocolate</enum>
324
- # <enum>Lychee</enum>
325
- # </enums>
326
- # </field>
327
- # If you're defining the field in Ruby, you can simply pass in an array of
328
- # enums as the +enums+ argument.
329
- #
330
- class EnumField < TextField
331
- def self.instantiate_with_parameters( domain_class, parameters ) #:nodoc:
332
- self.new( domain_class, parameters['name'], parameters['enums'] )
333
- end
334
-
335
- def self.enum_queue_hash( fieldElt )
336
- enumValues = []
337
- fieldElt.elements.each( 'enums/enum' ) { |enumElt|
338
- enumValues << enumElt.attributes['key']
339
- enumValues << enumElt.text.to_s
340
- }
341
- QueueHash.new( *enumValues )
342
- end
343
-
344
- def self.instantiation_parameters( fieldElt ) #:nodoc:
345
- parameters = super( fieldElt )
346
- if fieldElt.elements['enums'][1].attributes['key']
347
- parameters['enums'] = enum_queue_hash( fieldElt )
348
- else
349
- parameters['enums'] = []
350
- fieldElt.elements.each( 'enums/enum' ) { |enumElt|
351
- parameters['enums'] << enumElt.text.to_s
352
- }
353
- end
354
- parameters
355
- end
356
-
357
- attr_reader :enums
358
-
359
- # [domain_class] The domain class that this field belongs to.
360
- # [name] The name of this domain class.
361
- # [enums] An array of Strings representing the possible choices for
362
- # this field.
363
- def initialize( domain_class, name, enums )
364
- super( domain_class, name )
365
- if enums.class == Array
366
- @enums = QueueHash.new_from_array enums
367
- else
368
- @enums = enums
369
- end
370
- end
371
-
372
- def value_for_sql(value) #:nodoc:
373
- value != '' ?(super(value)) : 'null'
374
- end
375
-
376
- def verify_non_nil( value, pk_id ) #:nodoc:
377
- super
378
- if @enums[value].nil?
379
- key_str = '[ ' +
380
- ( @enums.keys.map { |key| "\"#{ key }\"" } ).join(', ') + ' ]'
381
- err_str = "#{ @domain_class.name }##{ name } needs a value that is " +
382
- "one of #{ key_str }"
383
- raise( FieldValueError, err_str, caller )
384
- end
385
- end
386
- end
387
-
388
- class FieldValueError < RuntimeError #:nodoc:
389
- end
390
-
391
- # A LinkField is used to link from one domain class to another.
392
- class LinkField < ObjectField
393
- def self.instantiate_with_parameters( domain_class, parameters ) #:nodoc:
394
- instance = self.new(
395
- domain_class, parameters['linked_type'], parameters['name'],
396
- parameters['delete_cascade']
397
- )
398
- if parameters['db_field_name']
399
- instance.db_field_name = parameters['db_field_name']
400
- end
401
- instance
402
- end
403
-
404
- def self.instantiation_parameters( fieldElt ) #:nodoc:
405
- parameters = super( fieldElt )
406
- linked_typeStr = fieldElt.attributes['linked_type']
407
- linked_type = DomainObject.get_domain_class_from_string( linked_typeStr )
408
- parameters['linked_type'] = linked_type
409
- parameters['delete_cascade'] = fieldElt.attributes['delete_cascade'] == 'y'
410
- parameters
411
- end
412
-
413
- attr_reader :linked_type
414
- attr_accessor :delete_cascade
415
-
416
- # [domain_class] The domain class that this field belongs to.
417
- # [linked_type] The domain class that this field points to.
418
- # [name] The name of this field.
419
- # [delete_cascade] If this is true, deleting the domain object that is
420
- # linked to will cause this domain object to be deleted
421
- # as well.
422
- def initialize( domain_class, linked_type, name = nil,
423
- delete_cascade = false )
424
- unless name
425
- linked_type.name =~ /::/
426
- name = $' || linked_type.name
427
- name = name.decapitalize
428
- end
429
- super( domain_class, name )
430
- ( @linked_type, @delete_cascade ) = linked_type, delete_cascade
431
- end
432
-
433
- def value_from_sql(string) #:nodoc:
434
- string != nil ? DomainObjectProxy.new(@linked_type, string.to_i) : nil
435
- end
436
-
437
- def value_for_sql(value) #:nodoc:
438
- if !value
439
- "null"
440
- elsif value.pk_id
441
- value.pk_id
442
- else
443
- raise( DomainObjectInitError, "Can't commit #{name} without pk_id",
444
- caller )
445
- end
446
- end
447
-
448
- def verify_non_nil(value, pk_id) #:nodoc:
449
- super
450
- if @linked_type != @domain_class && pk_id
451
- subsetLinkField = @linked_type.class_fields.find { |field|
452
- field.class == SubsetLinkField && field.subset_field == @name
453
- }
454
- if subsetLinkField
455
- verify_subset_link_field( subsetLinkField, pk_id )
456
- end
457
- end
458
- end
459
-
460
- def verify_subset_link_field( subsetLinkField, pk_id )
461
- begin
462
- prevObj = ObjectStore.get_object_store.get( domain_class, pk_id )
463
- prevObjLinkedTo = prevObj.send(name)
464
- possiblyMyObj = prevObjLinkedTo.send(subsetLinkField.name)
465
- if possiblyMyObj && possiblyMyObj.pk_id == pk_id
466
- cantChangeMsg = "You can't change that."
467
- raise FieldValueError, cantChangeMsg, caller
468
- end
469
- rescue DomainObjectNotFoundError
470
- # no previous value, so nothing to check for
471
- end
472
- end
473
- end
474
-
475
- # Accepts a Month as a value. This field automatically saves in MySQL as a
476
- # date corresponding to the first day of the month.
477
- class MonthField < DateField
478
- def self.value_type #:nodoc:
479
- Month
480
- end
481
-
482
- def value_for_sql(value) #:nodoc:
483
- "'#{value.year}-#{value.month}-01'"
484
- end
485
- end
486
-
487
- class PrimaryKeyField < IntegerField
488
- def initialize( domain_class )
489
- super( domain_class, 'pk_id' )
490
- @not_null = false
491
- end
492
- end
493
-
494
- # A StateField is a specialized subclass of EnumField; its possible values are
495
- # any of the 50 states of the United States, stored as each state's two-letter
496
- # postal code.
497
- class StateField < EnumField
498
- def initialize( domain_class, name = "state" )
499
- super( domain_class, name, UsStates.states )
500
- end
501
- end
502
-
503
- class SubsetLinkField < LinkField #:nodoc:
504
- def self.instantiate_with_parameters( domain_class, parameters )
505
- self.new( domain_class, parameters['linked_type'],
506
- parameters['subset_field'], parameters['name'] )
507
- end
508
-
509
- def self.instantiation_parameters( fieldElt )
510
- parameters = super( fieldElt )
511
- parameters['subset_field'] = fieldElt.attributes['subset_field']
512
- parameters
513
- end
514
-
515
- attr_accessor :subset_field
516
-
517
- def initialize( domain_class, linked_type, subset_field,
518
- name = linked_type.name.downcase )
519
- super( domain_class, linked_type, name )
520
- @subset_field = subset_field
521
- end
522
- end
523
-
524
- # TextListField maps to any String SQL field that tries to represent a
525
- # quick-and-dirty list with a comma-separated string. It returns an Array.
526
- # For example, a SQL field with the value "john,bill,dave", then the Ruby
527
- # field will have the value <tt>[ "john", "bill", "dave" ]</tt>.
528
- class TextListField < ObjectField
529
- def self.value_type #:nodoc:
530
- Array
531
- end
532
-
533
- def value_for_sql(objectValue) #:nodoc:
534
- if objectValue.is_a?( Array )
535
- str = objectValue.join(',')
536
- else
537
- str = objectValue
538
- end
539
- "'" + str + "'"
540
- end
541
-
542
- def value_from_sql(sqlString, lookupLink = true) #:nodoc:
543
- if sqlString
544
- sqlString.split ','
545
- else
546
- []
547
- end
548
- end
549
- end
550
-
551
- class TimeStampField < DateTimeField #:nodoc:
552
- def initialize( domain_class, name = 'timeStamp' )
553
- super( domain_class, name )
554
- @not_null = false
555
- end
556
-
557
- def db_will_automatically_write
558
- true
559
- end
560
- end
561
- end