lafcadio 0.6.6 → 0.7.0

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.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