lafcadio 0.8.3 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,7 +16,7 @@
16
16
  # http://lafcadio.rubyforge.org/tutorial.html.
17
17
 
18
18
  module Lafcadio
19
- Version = "0.8.3"
19
+ Version = "0.9.0"
20
20
 
21
21
  require 'lafcadio/depend'
22
22
  require 'lafcadio/domain'
@@ -16,7 +16,7 @@
16
16
  # http://lafcadio.rubyforge.org/tutorial.html.
17
17
 
18
18
  module Lafcadio
19
- Version = "0.8.2"
19
+ Version = "0.8.0"
20
20
 
21
21
  require 'lafcadio/depend'
22
22
  require 'lafcadio/domain'
@@ -0,0 +1,93 @@
1
+ module Lafcadio
2
+ # Represents a specific month in time. With the exception of
3
+ # Month.month_names (which returns a zero-based array), every usage of the
4
+ # month value assumes that 1 equals January and 12 equals December.
5
+ class Month
6
+ # Returns an array of the full names of months (in English). Note that
7
+ # "January" is the 0th element, and "December" is the 11th element.
8
+ def Month.month_names
9
+ [ "January", "February", "March", "April", "May", "June", "July",
10
+ "August", "September", "October", "November", "December" ]
11
+ end
12
+
13
+ include Comparable
14
+
15
+ attr_reader :month, :year
16
+
17
+ # A new month can be set to a specific +month+ and +year+, or you can call
18
+ # Month.new with no arguments to receive the current month.
19
+ def initialize( year = nil, month = nil )
20
+ require 'date'
21
+ if month.nil? || year.nil?
22
+ date = Date.today
23
+ month = date.mon unless month
24
+ year = date.year unless year
25
+ end
26
+ fail "invalid month" if month < 1 || month > 12
27
+ @month = month
28
+ @year = year
29
+ end
30
+
31
+ # Returns a new Month that is +amountToAdd+ months later.
32
+ def +( amountToAdd )
33
+ ( fullYears, remainingMonths ) = amountToAdd.divmod( 12 )
34
+ resultYear = @year + fullYears
35
+ resultMonth = @month + remainingMonths
36
+ if resultMonth > 12
37
+ resultMonth -= 12
38
+ resultYear += 1
39
+ end
40
+ Month.new( resultYear, resultMonth )
41
+ end
42
+
43
+ # Returns a new Month that is +amountToSubtract+ months earlier.
44
+ def -(amountToSubtract)
45
+ self + (-amountToSubtract)
46
+ end
47
+
48
+ # Compare this Month to another Month.
49
+ def <=>(anOther)
50
+ if @year == anOther.year
51
+ @month <=> anOther.month
52
+ else
53
+ @year <=> anOther.year
54
+ end
55
+ end
56
+
57
+ # Returns the last Date of the month.
58
+ def end_date
59
+ self.next.start_date - 1
60
+ end
61
+
62
+ # Is this Month equal to +anOther+? +anOther+ must be another Month of the
63
+ # same value.
64
+ def eql?(anOther)
65
+ self == anOther
66
+ end
67
+
68
+ # Calculate a hash value for this Month.
69
+ def hash
70
+ "#{@year}#{@month}".to_i
71
+ end
72
+
73
+ # Returns the next Month.
74
+ def next
75
+ self + 1
76
+ end
77
+
78
+ # Returns the previous Month.
79
+ def prev
80
+ self - 1
81
+ end
82
+
83
+ # Returns the first Date of the month.
84
+ def start_date
85
+ Date.new( @year, @month, 1 )
86
+ end
87
+
88
+ # Returns a string of the format "January 2001".
89
+ def to_s
90
+ Month.month_names[@month-1][0..2] + " " + @year.to_s
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,8 @@
1
+ require 'dbi'
2
+ require 'englishext'
3
+ require 'extensions/all'
4
+ require 'extensions/module'
5
+ require 'log4r'
6
+ require 'month'
7
+ require 'queuehash'
8
+ require 'uscommerce'
@@ -137,9 +137,7 @@ module Lafcadio
137
137
  end
138
138
  end
139
139
 
140
- def eql?(otherObj)
141
- self == otherObj
142
- end
140
+ def eql?( otherObj ); self == otherObj; end
143
141
 
144
142
  def hash; "#{ self.class.name } #{ pk_id }".hash; end
145
143
  end
@@ -242,18 +240,7 @@ module Lafcadio
242
240
  # that each table has a +pk_id+ field that is used to match rows between
243
241
  # different levels.
244
242
  class DomainObject
245
- @@subclassHash = {}
246
- @@class_fields = {}
247
- @@pk_fields =
248
- Hash.new { |hash, key|
249
- pk_field = PrimaryKeyField.new( key )
250
- pk_field.db_field_name = @@sql_primary_keys[key]
251
- hash[key] = pk_field
252
- }
253
- @@sql_primary_keys = Hash.new( 'pk_id' )
254
- @@default_field_setup_hashes = Hash.new { |hash, key|
255
- hash[key] = Hash.new( {} )
256
- }
243
+ @@subclass_records = Hash.new do |h, k| h[k] = SubclassRecord.new( k ); end
257
244
 
258
245
  COMMIT_ADD = 1
259
246
  COMMIT_EDIT = 2
@@ -264,7 +251,6 @@ module Lafcadio
264
251
  def self.[]( pk_id ); get( pk_id ); end
265
252
 
266
253
  def self.abstract_subclasses #:nodoc:
267
- require 'lafcadio/domain'
268
254
  [ MapObject ]
269
255
  end
270
256
 
@@ -273,19 +259,23 @@ module Lafcadio
273
259
  # Returns an array of all fields defined for this class and all concrete
274
260
  # superclasses.
275
261
  def self.all_fields
276
- all_fields = []
277
- self_and_concrete_superclasses.each { |aClass|
278
- aClass.class_fields.each { |field| all_fields << field }
279
- }
280
- all_fields
262
+ self_and_concrete_superclasses.map { |a_class|
263
+ a_class.class_fields
264
+ }.flatten
281
265
  end
282
266
 
267
+ def self.class_field(fieldName) #:nodoc:
268
+ field = nil
269
+ self.class_fields.each { |aField|
270
+ field = aField if aField.name == fieldName
271
+ }
272
+ field
273
+ end
274
+
283
275
  def self.class_fields #:nodoc:
284
- class_fields = @@class_fields[self]
285
- unless class_fields
286
- @@class_fields[self] = self.get_class_fields
287
- class_fields = @@class_fields[self]
288
- class_fields.each do |class_field|
276
+ unless subclass_record.fields
277
+ subclass_record.fields = self.get_class_fields
278
+ subclass_record.fields.each do |class_field|
289
279
  begin
290
280
  undef_method class_field.name.to_sym
291
281
  rescue NameError
@@ -293,52 +283,50 @@ module Lafcadio
293
283
  end
294
284
  end
295
285
  end
296
- class_fields
286
+ subclass_record.fields
297
287
  end
298
288
 
299
289
  def self.create_field( field_class, *args )
300
- class_fields = @@class_fields[self]
301
- if args.last.is_a? Hash
302
- att_hash = args.last
303
- else
304
- att_hash = @@default_field_setup_hashes[self][field_class].clone
290
+ subclass_record.maybe_init_fields
291
+ att_hash = create_field_att_hash( field_class, *args )
292
+ field = field_class.create_with_args( self, att_hash )
293
+ unless class_fields.any? { |cf| cf.name == field.name }
294
+ att_hash.each { |field_name, value|
295
+ setter = field_name + '='
296
+ field.send( setter, value ) if field.respond_to?( setter )
297
+ }
298
+ class_fields << field
305
299
  end
306
- if class_fields.nil?
307
- class_fields = [ @@pk_fields[self] ]
308
- @@class_fields[self] = class_fields
300
+ end
301
+
302
+ def self.create_field_att_hash( field_class, *args ) #:nodoc:
303
+ att_hash = args.last
304
+ unless att_hash.is_a? Hash
305
+ att_hash = subclass_record.default_field_setup_hash[
306
+ field_class
307
+ ].clone
309
308
  end
310
309
  if field_class == DomainObjectField
311
310
  att_hash['linked_type'] = args.first
312
311
  att_hash['name'] = args[1] if args[1] and !args[1].is_a? Hash
313
312
  else
314
313
  name = args.first
315
- att_hash['name'] = name == String ? name : name.to_s
316
- end
317
- field = field_class.instantiate_with_parameters( self, att_hash )
318
- unless class_fields.any? { |cf| cf.name == field.name }
319
- att_hash.each { |field_name, value|
320
- setter = field_name + '='
321
- field.send( setter, value ) if field.respond_to?( setter )
322
- }
323
- class_fields << field
314
+ att_hash['name'] = name.is_a?( String ) ? name : name.to_s
324
315
  end
316
+ att_hash
325
317
  end
326
318
 
327
319
  def self.default_field_setup_hash( field_class, hash )
328
- @@default_field_setup_hashes[self][field_class] = hash
320
+ subclass_record.default_field_setup_hash[field_class] = hash
329
321
  end
330
322
 
331
323
  def self.dependent_classes #:nodoc:
332
324
  dependent_classes = {}
333
325
  DomainObject.subclasses.each { |aClass|
334
- if aClass != DomainObjectProxy &&
335
- (!DomainObject.abstract_subclasses.index(aClass))
336
- aClass.class_fields.each { |field|
337
- if ( field.is_a?( DomainObjectField ) &&
338
- field.linked_type == self.domain_class )
339
- dependent_classes[aClass] = field
340
- end
341
- }
326
+ unless DomainObject.abstract_subclasses.include?( aClass )
327
+ if ( field = aClass.get_link_field( self ) )
328
+ dependent_classes[aClass] = field
329
+ end
342
330
  end
343
331
  }
344
332
  dependent_classes
@@ -352,30 +340,35 @@ module Lafcadio
352
340
  end
353
341
 
354
342
  def self.first; all.first; end
355
-
356
- def self.get_class_field(fieldName) #:nodoc:
357
- field = nil
358
- self.class_fields.each { |aField|
359
- field = aField if aField.name == fieldName
360
- }
361
- field
362
- end
363
-
364
- def DomainObject.get_class_field_by_db_name( fieldName ) #:nodoc:
365
- self.class_fields.find { |field| field.db_field_name == fieldName }
343
+
344
+ def self.get( *args )
345
+ if block_given?
346
+ query = Query.infer( self ) { |dobj| yield( dobj ) }
347
+ ObjectStore.get_object_store.get_subset( query )
348
+ elsif args.size == 1
349
+ arg = args.first
350
+ if arg.is_a? Fixnum
351
+ ObjectStore.get_object_store.get( self, *args )
352
+ else
353
+ qry = Query.new( self, nil, { :group_functions => [ :count ] } )
354
+ ObjectStore.get_object_store.query qry
355
+ end
356
+ else
357
+ ObjectStore.get_object_store.get_filtered( self.name, *args )
358
+ end
366
359
  end
367
360
 
368
361
  # Returns an Array of ObjectField instances for this domain class, parsing
369
362
  # them from XML if necessary.
370
363
  def self.get_class_fields
371
364
  if self.methods( false ).include?( 'get_class_fields' )
372
- [ @@pk_fields[ self ] ]
365
+ [ subclass_record.pk_field ]
373
366
  elsif abstract_subclasses.include?( self )
374
367
  []
375
368
  else
376
369
  xmlParser = try_load_xml_parser
377
370
  if xmlParser
378
- xmlParser.get_class_fields
371
+ xmlParser.get_class_fields
379
372
  else
380
373
  error_msg = "Couldn't find either an XML class description file " +
381
374
  "or get_class_fields method for " + self.name
@@ -396,7 +389,7 @@ module Lafcadio
396
389
  aDomainClass = self
397
390
  field = nil
398
391
  while aDomainClass < DomainObject && !field
399
- field = aDomainClass.get_class_field( fieldName )
392
+ field = aDomainClass.class_field( fieldName )
400
393
  aDomainClass = aDomainClass.superclass
401
394
  end
402
395
  if field
@@ -429,7 +422,7 @@ module Lafcadio
429
422
  end
430
423
 
431
424
  def self.inherited(subclass) #:nodoc:
432
- @@subclassHash[subclass] = true
425
+ @@subclass_records[subclass]
433
426
  end
434
427
 
435
428
  def self.is_based_on? #:nodoc:
@@ -444,44 +437,33 @@ module Lafcadio
444
437
 
445
438
  def self.method_missing( methodId, *args ) #:nodoc:
446
439
  method_name = methodId.id2name
447
- if method_name == 'get'
448
- if block_given?
449
- query = Query.infer( self ) { |dobj| yield( dobj ) }
450
- ObjectStore.get_object_store.get_subset( query )
451
- elsif args.size == 1
452
- ObjectStore.get_object_store.get( self, *args )
453
- else
454
- ObjectStore.get_object_store.get_filtered( self.name, *args )
455
- end
456
- else
457
- maybe_field_class_name = method_name.underscore_to_camel_case + 'Field'
458
- begin
459
- field_class = Lafcadio.const_get( maybe_field_class_name )
460
- create_field( field_class, *args )
461
- rescue NameError
462
- singular = method_name.singular
463
- if singular
464
- maybe_field_class_name = singular.underscore_to_camel_case + 'Field'
465
- begin
466
- field_class = Lafcadio.const_get( maybe_field_class_name )
467
- arg = args.shift
468
- until args.empty?
469
- next_arg = args.shift
470
- if next_arg.is_a? String or next_arg.is_a? Symbol
471
- create_field( field_class, arg )
472
- arg = next_arg
473
- else
474
- create_field( field_class, arg, next_arg )
475
- arg = args.shift
476
- end
440
+ maybe_field_class_name = method_name.underscore_to_camel_case + 'Field'
441
+ begin
442
+ field_class = Lafcadio.const_get( maybe_field_class_name )
443
+ create_field( field_class, *args )
444
+ rescue NameError
445
+ singular = method_name.singular
446
+ if singular
447
+ maybe_field_class_name = singular.underscore_to_camel_case + 'Field'
448
+ begin
449
+ field_class = Lafcadio.const_get( maybe_field_class_name )
450
+ arg = args.shift
451
+ until args.empty?
452
+ next_arg = args.shift
453
+ if next_arg.is_a? String or next_arg.is_a? Symbol
454
+ create_field( field_class, arg )
455
+ arg = next_arg
456
+ else
457
+ create_field( field_class, arg, next_arg )
458
+ arg = args.shift
477
459
  end
478
- create_field( field_class, arg ) unless arg.nil?
479
- rescue NameError
480
- super
481
460
  end
482
- else
461
+ create_field( field_class, arg ) unless arg.nil?
462
+ rescue NameError
483
463
  super
484
464
  end
465
+ else
466
+ super
485
467
  end
486
468
  end
487
469
  end
@@ -522,7 +504,7 @@ module Lafcadio
522
504
  begin
523
505
  get_field( 'pk_id' ).db_field_name = self.send( symbol )
524
506
  rescue NameError
525
- @@sql_primary_keys[self] = self.send( symbol )
507
+ subclass_record.sql_primary_key = self.send( symbol )
526
508
  end
527
509
  end
528
510
  end
@@ -535,9 +517,11 @@ module Lafcadio
535
517
  end
536
518
  get_field( 'pk_id' ).db_field_name
537
519
  end
520
+
521
+ def self.subclass_record; @@subclass_records[self]; end
538
522
 
539
523
  def self.subclasses #:nodoc:
540
- @@subclassHash.keys
524
+ @@subclass_records.keys
541
525
  end
542
526
 
543
527
  # Returns the table name, which is assumed to be the domain class name
@@ -561,16 +545,15 @@ module Lafcadio
561
545
 
562
546
  def self.try_load_xml_parser
563
547
  require 'lafcadio/domain'
564
- if ( dirName = LafcadioConfig.new['classDefinitionDir'] )
565
- xmlFileName = self.basename + '.xml'
566
- xmlPath = File.join( dirName, xmlFileName )
567
- xml = ''
568
- begin
569
- File.open( xmlPath ) { |file| xml = file.readlines.join }
570
- ClassDefinitionXmlParser.new( self, xml )
571
- rescue Errno::ENOENT
572
- # no xml file, so no @xmlParser
573
- end
548
+ dirName = LafcadioConfig.new['classDefinitionDir']
549
+ xmlFileName = self.basename + '.xml'
550
+ xmlPath = File.join( dirName, xmlFileName )
551
+ xml = ''
552
+ begin
553
+ File.open( xmlPath ) { |file| xml = file.readlines.join }
554
+ ClassDefinitionXmlParser.new( self, xml )
555
+ rescue Errno::ENOENT
556
+ # no xml file, so no @xmlParser
574
557
  end
575
558
  end
576
559
 
@@ -595,6 +578,7 @@ module Lafcadio
595
578
  def initialize(fieldHash)
596
579
  if fieldHash.respond_to? :keys
597
580
  fieldHash.keys.each { |key|
581
+ key = key.to_s
598
582
  begin
599
583
  self.class.get_field( key )
600
584
  rescue MissingError
@@ -602,11 +586,16 @@ module Lafcadio
602
586
  end
603
587
  }
604
588
  end
605
- @fieldHash = fieldHash
589
+ if fieldHash.is_a? Hash
590
+ @fieldHash = {}
591
+ fieldHash.each do |k, v| @fieldHash[k.to_s] = v; end
592
+ else
593
+ @fieldHash = fieldHash
594
+ end
606
595
  @error_messages = []
607
596
  @fields = {}
608
597
  @fields_set = []
609
- reset_original_values_hash @fieldHash
598
+ @original_values = OriginalValuesHash.new( @fieldHash )
610
599
  check_fields = LafcadioConfig.new()['checkFields']
611
600
  verify if %w( onInstantiate onAllStates ).include?( check_fields )
612
601
  end
@@ -700,10 +689,6 @@ module Lafcadio
700
689
  def post_commit_trigger
701
690
  nil
702
691
  end
703
-
704
- def reset_original_values_hash( f = @fields ) #:nodoc:
705
- @original_values = OriginalValuesHash.new( f.clone )
706
- end
707
692
 
708
693
  def set_field( field, value ) #:nodoc:
709
694
  if field.class <= DomainObjectField
@@ -735,6 +720,28 @@ module Lafcadio
735
720
  class OriginalValuesHash < DelegateClass( Hash )
736
721
  def []=( key, val ); raise NoMethodError; end
737
722
  end
723
+
724
+ class SubclassRecord
725
+ attr_accessor :default_field_setup_hash, :fields, :sql_primary_key
726
+
727
+ def initialize( subclass )
728
+ @subclass = subclass
729
+ @default_field_setup_hash = Hash.new( {} )
730
+ @sql_primary_key = 'pk_id'
731
+ end
732
+
733
+ def maybe_init_fields
734
+ self.fields = [ pk_field ] if self.fields.nil?
735
+ end
736
+
737
+ def pk_field
738
+ if @pk_field.nil?
739
+ @pk_field = PrimaryKeyField.new @subclass
740
+ @pk_field.db_field_name = sql_primary_key
741
+ end
742
+ @pk_field
743
+ end
744
+ end
738
745
  end
739
746
 
740
747
  # Any domain class that is used mostly to map between two other domain