lafcadio 0.8.3 → 0.9.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.
@@ -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