lafcadio 0.4.3

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.
Files changed (81) hide show
  1. data/lib/lafcadio.rb +32 -0
  2. data/lib/lafcadio.rb~ +32 -0
  3. data/lib/lafcadio/TestSuite.rb +16 -0
  4. data/lib/lafcadio/dateTime.rb +2 -0
  5. data/lib/lafcadio/dateTime/Month.rb +93 -0
  6. data/lib/lafcadio/domain.rb +119 -0
  7. data/lib/lafcadio/domain.rb~ +119 -0
  8. data/lib/lafcadio/domain/DomainObject.rb +375 -0
  9. data/lib/lafcadio/domain/DomainObject.rb~ +371 -0
  10. data/lib/lafcadio/domain/MapObject.rb +22 -0
  11. data/lib/lafcadio/domain/ObjectType.rb +80 -0
  12. data/lib/lafcadio/includer.rb +18 -0
  13. data/lib/lafcadio/mock.rb +2 -0
  14. data/lib/lafcadio/mock/MockDbBridge.rb +78 -0
  15. data/lib/lafcadio/mock/MockDbBridge.rb~ +74 -0
  16. data/lib/lafcadio/mock/MockObjectStore.rb +20 -0
  17. data/lib/lafcadio/objectField.rb +14 -0
  18. data/lib/lafcadio/objectField/AutoIncrementField.rb +25 -0
  19. data/lib/lafcadio/objectField/BooleanField.rb +83 -0
  20. data/lib/lafcadio/objectField/DateField.rb +33 -0
  21. data/lib/lafcadio/objectField/DateTimeField.rb +25 -0
  22. data/lib/lafcadio/objectField/DecimalField.rb +41 -0
  23. data/lib/lafcadio/objectField/EmailField.rb +28 -0
  24. data/lib/lafcadio/objectField/EnumField.rb +62 -0
  25. data/lib/lafcadio/objectField/FieldValueError.rb +4 -0
  26. data/lib/lafcadio/objectField/IntegerField.rb +15 -0
  27. data/lib/lafcadio/objectField/LinkField.rb +92 -0
  28. data/lib/lafcadio/objectField/LinkField.rb~ +86 -0
  29. data/lib/lafcadio/objectField/MoneyField.rb +13 -0
  30. data/lib/lafcadio/objectField/MonthField.rb +16 -0
  31. data/lib/lafcadio/objectField/ObjectField.rb +142 -0
  32. data/lib/lafcadio/objectField/PasswordField.rb +29 -0
  33. data/lib/lafcadio/objectField/StateField.rb +13 -0
  34. data/lib/lafcadio/objectField/SubsetLinkField.rb +25 -0
  35. data/lib/lafcadio/objectField/TextField.rb +23 -0
  36. data/lib/lafcadio/objectField/TextListField.rb +21 -0
  37. data/lib/lafcadio/objectField/TimeStampField.rb +15 -0
  38. data/lib/lafcadio/objectStore.rb +100 -0
  39. data/lib/lafcadio/objectStore/Cache.rb +81 -0
  40. data/lib/lafcadio/objectStore/Committer.rb +65 -0
  41. data/lib/lafcadio/objectStore/CouldntMatchObjectTypeError.rb +4 -0
  42. data/lib/lafcadio/objectStore/DbBridge.rb +140 -0
  43. data/lib/lafcadio/objectStore/DbBridge.rb~ +140 -0
  44. data/lib/lafcadio/objectStore/DomainComparable.rb +25 -0
  45. data/lib/lafcadio/objectStore/DomainObjectInitError.rb +9 -0
  46. data/lib/lafcadio/objectStore/DomainObjectNotFoundError.rb +4 -0
  47. data/lib/lafcadio/objectStore/DomainObjectProxy.rb +62 -0
  48. data/lib/lafcadio/objectStore/DomainObjectSqlMaker.rb +74 -0
  49. data/lib/lafcadio/objectStore/ObjectStore.rb +207 -0
  50. data/lib/lafcadio/objectStore/ObjectStore.rb~ +207 -0
  51. data/lib/lafcadio/objectStore/SqlValueConverter.rb +30 -0
  52. data/lib/lafcadio/objectStore/SqlValueConverter.rb~ +30 -0
  53. data/lib/lafcadio/query.rb +203 -0
  54. data/lib/lafcadio/query/Compare.rb +55 -0
  55. data/lib/lafcadio/query/CompoundCondition.rb +39 -0
  56. data/lib/lafcadio/query/Condition.rb +66 -0
  57. data/lib/lafcadio/query/Condition.rb~ +66 -0
  58. data/lib/lafcadio/query/Equals.rb +45 -0
  59. data/lib/lafcadio/query/In.rb +20 -0
  60. data/lib/lafcadio/query/Like.rb +48 -0
  61. data/lib/lafcadio/query/Link.rb +20 -0
  62. data/lib/lafcadio/query/Max.rb +32 -0
  63. data/lib/lafcadio/query/Max.rb~ +25 -0
  64. data/lib/lafcadio/query/Not.rb +21 -0
  65. data/lib/lafcadio/query/Query.rb +92 -0
  66. data/lib/lafcadio/schema.rb +2 -0
  67. data/lib/lafcadio/schema/CreateTableStatement.rb +61 -0
  68. data/lib/lafcadio/schema/CreateTableStatement.rb~ +59 -0
  69. data/lib/lafcadio/test.rb +2 -0
  70. data/lib/lafcadio/test/LafcadioTestCase.rb +17 -0
  71. data/lib/lafcadio/test/testconfig.dat +13 -0
  72. data/lib/lafcadio/util.rb +180 -0
  73. data/lib/lafcadio/util/Context.rb +61 -0
  74. data/lib/lafcadio/util/ContextualService.rb +33 -0
  75. data/lib/lafcadio/util/English.rb +117 -0
  76. data/lib/lafcadio/util/HashOfArrays.rb +48 -0
  77. data/lib/lafcadio/util/LafcadioConfig.rb +25 -0
  78. data/lib/lafcadio/util/QueueHash.rb +67 -0
  79. data/lib/lafcadio/util/UsStates.rb +29 -0
  80. data/lib/lafcadio/xml.rb +2 -0
  81. metadata +135 -0
@@ -0,0 +1,62 @@
1
+ require 'lafcadio/objectField/TextField'
2
+
3
+ module Lafcadio
4
+ # EnumField represents an enumerated field that can only be set to one of a
5
+ # set range of string values. To set the enumeration in the class definition
6
+ # XML, use the following format:
7
+ # <field name="flavor" class="EnumField">
8
+ # <enums>
9
+ # <enum>Vanilla</enum>
10
+ # <enum>Chocolate</enum>
11
+ # <enum>Lychee</enum>
12
+ # </enums>
13
+ # </field>
14
+ # If you're defining the field in Ruby, you can simply pass in an array of
15
+ # enums as the +enums+ argument.
16
+ #
17
+ class EnumField < TextField
18
+ def EnumField.instantiationParameters( fieldElt ) #:nodoc:
19
+ parameters = super( fieldElt )
20
+ if fieldElt.elements['enums'][1].attributes['key']
21
+ enumValues = []
22
+ fieldElt.elements.each( 'enums/enum' ) { |enumElt|
23
+ enumValues << enumElt.attributes['key']
24
+ enumValues << enumElt.text.to_s
25
+ }
26
+ parameters['enums'] = QueueHash.new( *enumValues )
27
+ else
28
+ parameters['enums'] = []
29
+ fieldElt.elements.each( 'enums/enum' ) { |enumElt|
30
+ parameters['enums'] << enumElt.text.to_s
31
+ }
32
+ end
33
+ parameters
34
+ end
35
+
36
+ def EnumField.instantiateWithParameters( domainClass, parameters ) #:nodoc:
37
+ self.new( domainClass, parameters['name'], parameters['enums'],
38
+ parameters['englishName'] )
39
+ end
40
+
41
+ attr_reader :enums
42
+
43
+ # [objectType] The domain class that this field belongs to.
44
+ # [name] The name of this domain class.
45
+ # [enums] An array of Strings representing the possible choices for
46
+ # this field.
47
+ # [englishName] The English name of this field. (Deprecated)
48
+ def initialize(objectType, name, enums, englishName = nil)
49
+ require 'lafcadio/util/QueueHash'
50
+ super objectType, name, englishName
51
+ if enums.class == Array
52
+ @enums = QueueHash.newFromArray enums
53
+ else
54
+ @enums = enums
55
+ end
56
+ end
57
+
58
+ def valueForSQL(value) #:nodoc:
59
+ value != '' ?(super(value)) : 'null'
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,4 @@
1
+ module Lafcadio
2
+ class FieldValueError < RuntimeError #:nodoc:
3
+ end
4
+ end
@@ -0,0 +1,15 @@
1
+ require 'lafcadio/objectField/ObjectField'
2
+
3
+ module Lafcadio
4
+ # IntegerField represents an integer.
5
+ class IntegerField < ObjectField
6
+ def textBoxSize #:nodoc:
7
+ 5
8
+ end
9
+
10
+ def valueFromSQL(string) #:nodoc:
11
+ value = super
12
+ value ? value.to_i : nil
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,92 @@
1
+ require 'lafcadio/util'
2
+ require 'lafcadio/objectField/ObjectField'
3
+
4
+ module Lafcadio
5
+ # A LinkField is used to link from one domain class to another.
6
+ class LinkField < ObjectField
7
+ def LinkField.instantiationParameters( fieldElt ) #:nodoc:
8
+ parameters = super( fieldElt )
9
+ linkedTypeStr = fieldElt.attributes['linkedType']
10
+ linkedType = DomainObject.getObjectTypeFromString( linkedTypeStr )
11
+ parameters['linkedType'] = linkedType
12
+ parameters['deleteCascade'] = fieldElt.attributes['deleteCascade'] == 'y'
13
+ parameters
14
+ end
15
+
16
+ def LinkField.instantiateWithParameters( domainClass, parameters ) #:nodoc:
17
+ instance = self.new(
18
+ domainClass, parameters['linkedType'], parameters['name'],
19
+ parameters['englishName'], parameters['deleteCascade']
20
+ )
21
+ if parameters['dbFieldName']
22
+ instance.dbFieldName = parameters['dbFieldName']
23
+ end
24
+ instance
25
+ end
26
+
27
+ attr_reader :linkedType
28
+ attr_accessor :listener, :objectStore, :newDuringEdit, :sortField,
29
+ :deleteCascade
30
+
31
+ # [objectType] The domain class that this field belongs to.
32
+ # [linkedType] The domain class that this field points to.
33
+ # [name] The name of this field.
34
+ # [englishName] The English name of this field. (Deprecated)
35
+ # [deleteCascade] If this is true, deleting the domain object that is linked
36
+ # to will cause this domain object to be deleted as well.
37
+ def initialize( objectType, linkedType, name = nil, englishName = nil,
38
+ deleteCascade = false )
39
+ unless name
40
+ linkedType.name =~ /::/
41
+ name = $' || linkedType.name
42
+ name = name.decapitalize
43
+ end
44
+ super(objectType, name, englishName)
45
+ ( @linkedType, @deleteCascade ) = linkedType, deleteCascade
46
+ @listener = nil
47
+ @newDuringEdit = true
48
+ end
49
+
50
+ def valueForSQL(value) #:nodoc:
51
+ require 'lafcadio/objectStore/DomainObjectInitError'
52
+ if !value
53
+ "null"
54
+ elsif value.pkId
55
+ value.pkId
56
+ else
57
+ raise( DomainObjectInitError, "Can't commit #{name} without pkId",
58
+ caller )
59
+ end
60
+ end
61
+
62
+ def valueFromSQL(string) #:nodoc:
63
+ require 'lafcadio/objectStore/DomainObjectProxy'
64
+ string != nil ? DomainObjectProxy.new(@linkedType, string.to_i) : nil
65
+ end
66
+
67
+ def verify(value, pkId) #:nodoc:
68
+ super
69
+ if @linkedType != @objectType && pkId
70
+ subsetLinkField = nil
71
+ @linkedType.classFields.each { |field|
72
+ if field.class == SubsetLinkField && field.subsetField == @name
73
+ subsetLinkField = field
74
+ end
75
+ }
76
+ if subsetLinkField
77
+ begin
78
+ prevObj = ObjectStore.getObjectStore.get(objectType, pkId)
79
+ prevObjLinkedTo = prevObj.send(name)
80
+ possiblyMyObj = prevObjLinkedTo.send(subsetLinkField.name)
81
+ if possiblyMyObj && possiblyMyObj.pkId == pkId
82
+ cantChangeMsg = "You can't change that."
83
+ raise FieldValueError, cantChangeMsg, caller
84
+ end
85
+ rescue DomainObjectNotFoundError
86
+ # no previous value, so nothing to check for
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,86 @@
1
+ require 'lafcadio/util'
2
+ require 'lafcadio/objectField/ObjectField'
3
+
4
+ module Lafcadio
5
+ # A LinkField is used to link from one domain class to another.
6
+ class LinkField < ObjectField
7
+ def LinkField.instantiationParameters( fieldElt ) #:nodoc:
8
+ parameters = super( fieldElt )
9
+ linkedTypeStr = fieldElt.attributes['linkedType']
10
+ linkedType = DomainObject.getObjectTypeFromString( linkedTypeStr )
11
+ parameters['linkedType'] = linkedType
12
+ parameters['deleteCascade'] = fieldElt.attributes['deleteCascade'] == 'y'
13
+ parameters
14
+ end
15
+
16
+ def LinkField.instantiateWithParameters( domainClass, parameters ) #:nodoc:
17
+ self.new( domainClass, parameters['linkedType'], parameters['name'],
18
+ parameters['englishName'], parameters['deleteCascade'] )
19
+ end
20
+
21
+ attr_reader :linkedType
22
+ attr_accessor :listener, :objectStore, :newDuringEdit, :sortField,
23
+ :deleteCascade
24
+
25
+ # [objectType] The domain class that this field belongs to.
26
+ # [linkedType] The domain class that this field points to.
27
+ # [name] The name of this field.
28
+ # [englishName] The English name of this field. (Deprecated)
29
+ # [deleteCascade] If this is true, deleting the domain object that is linked
30
+ # to will cause this domain object to be deleted as well.
31
+ def initialize( objectType, linkedType, name = nil, englishName = nil,
32
+ deleteCascade = false )
33
+ unless name
34
+ linkedType.name =~ /::/
35
+ name = $' || linkedType.name
36
+ name = name.decapitalize
37
+ end
38
+ super(objectType, name, englishName)
39
+ ( @linkedType, @deleteCascade ) = linkedType, deleteCascade
40
+ @listener = nil
41
+ @newDuringEdit = true
42
+ end
43
+
44
+ def valueForSQL(value) #:nodoc:
45
+ require 'lafcadio/objectStore/DomainObjectInitError'
46
+ if !value
47
+ "null"
48
+ elsif value.pkId
49
+ value.pkId
50
+ else
51
+ raise( DomainObjectInitError, "Can't commit #{name} without pkId",
52
+ caller )
53
+ end
54
+ end
55
+
56
+ def valueFromSQL(string) #:nodoc:
57
+ require 'lafcadio/objectStore/DomainObjectProxy'
58
+ string != nil ? DomainObjectProxy.new(@linkedType, string.to_i) : nil
59
+ end
60
+
61
+ def verify(value, pkId) #:nodoc:
62
+ super
63
+ if @linkedType != @objectType && pkId
64
+ subsetLinkField = nil
65
+ @linkedType.classFields.each { |field|
66
+ if field.class == SubsetLinkField && field.subsetField == @name
67
+ subsetLinkField = field
68
+ end
69
+ }
70
+ if subsetLinkField
71
+ begin
72
+ prevObj = ObjectStore.getObjectStore.get(objectType, pkId)
73
+ prevObjLinkedTo = prevObj.send(name)
74
+ possiblyMyObj = prevObjLinkedTo.send(subsetLinkField.name)
75
+ if possiblyMyObj && possiblyMyObj.pkId == pkId
76
+ cantChangeMsg = "You can't change that."
77
+ raise FieldValueError, cantChangeMsg, caller
78
+ end
79
+ rescue DomainObjectNotFoundError
80
+ # no previous value, so nothing to check for
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,13 @@
1
+ require 'lafcadio/objectField/DecimalField'
2
+
3
+ module Lafcadio
4
+ class MoneyField < DecimalField #:nodoc:
5
+ def MoneyField.instantiateWithParameters( domainClass, parameters )
6
+ self.new( domainClass, parameters['name'], parameters['englishName'] )
7
+ end
8
+
9
+ def initialize(objectType, name, englishName = nil)
10
+ super(objectType, name, 2, englishName)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ require 'lafcadio/objectField/DateField'
2
+ require 'lafcadio/dateTime/Month'
3
+
4
+ module Lafcadio
5
+ # Accepts a Month as a value. This field automatically saves in MySQL as a
6
+ # date corresponding to the first day of the month.
7
+ class MonthField < DateField
8
+ def MonthField.valueType #:nodoc:
9
+ Month
10
+ end
11
+
12
+ def valueForSQL(value) #:nodoc:
13
+ "'#{value.year}-#{value.month}-01'"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,142 @@
1
+ require 'lafcadio/util/English'
2
+ require 'lafcadio/objectField/FieldValueError'
3
+
4
+ module Lafcadio
5
+ # ObjectField is the abstract base class of any field for domain objects.
6
+ class ObjectField
7
+ include Comparable
8
+
9
+ attr_reader :name, :defaultFieldName, :objectType
10
+ attr_accessor :notNull, :hideLabel, :writeOnce, :unique, :hideDisplay,
11
+ :default, :dbFieldName, :notUniqueMsg
12
+
13
+ def ObjectField.valueType #:nodoc:
14
+ Object
15
+ end
16
+
17
+ def ObjectField.instantiationParameters( fieldElt ) #:nodoc:
18
+ parameters = {}
19
+ parameters['name'] = fieldElt.attributes['name']
20
+ parameters['englishName'] = fieldElt.attributes['englishName']
21
+ parameters['dbFieldName'] = fieldElt.attributes['dbFieldName']
22
+ parameters
23
+ end
24
+
25
+ def ObjectField.instantiateFromXml( domainClass, fieldElt ) #:nodoc:
26
+ parameters = instantiationParameters( fieldElt )
27
+ instantiateWithParameters( domainClass, parameters )
28
+ end
29
+
30
+ def self.instantiateWithParameters( domainClass, parameters ) #:nodoc:
31
+ instance = self.new( domainClass, parameters['name'],
32
+ parameters['englishName'] )
33
+ if ( dbFieldName = parameters['dbFieldName'] )
34
+ instance.dbFieldName = dbFieldName
35
+ end
36
+ instance
37
+ end
38
+
39
+ # [objectType] The domain class that this object field belongs to.
40
+ # [name] The name of this field.
41
+ # [englishName] The descriptive English name of this field. (Deprecated)
42
+ def initialize(objectType, name, englishName = nil )
43
+ @objectType = objectType
44
+ @name = name
45
+ @dbFieldName = name
46
+ @notNull = true
47
+ @unique = false
48
+ ( @default, @notUniqueMsg ) = [ nil, nil ]
49
+ @englishNameOrNil = englishName
50
+ end
51
+
52
+ def bind_write?; false; end #:nodoc:
53
+
54
+ def db_table_and_field_name
55
+ "#{ objectType.tableName }.#{ dbFieldName }"
56
+ end
57
+
58
+ def englishName #:nodoc:
59
+ @englishNameOrNil || English.camelCaseToEnglish(name).capitalize
60
+ end
61
+
62
+ def nullErrorMsg #:nodoc:
63
+ English.sentence "Please enter %a %nam.", englishName.downcase
64
+ end
65
+
66
+ def verify(value, pkId) #:nodoc:
67
+ if value.nil? && notNull
68
+ raise FieldValueError, nullErrorMsg, caller
69
+ end
70
+ if value
71
+ valueType = self.class.valueType
72
+ unless value.class <= valueType
73
+ raise FieldValueError,
74
+ "#{name} needs an object of type #{valueType.name}", caller
75
+ end
76
+ verifyUniqueness(value, pkId) if unique
77
+ end
78
+ end
79
+
80
+ def verifyUniqueness(value, pkId) #:nodoc:
81
+ inferrer = Query::Inferrer.new( @objectType ) { |domain_obj|
82
+ Query.And( domain_obj.send( self.name ).equals( value ),
83
+ domain_obj.pkId.equals( pkId ).not )
84
+ }
85
+ collisions = ObjectStore.getObjectStore.getSubset( inferrer.execute )
86
+ if collisions.size > 0
87
+ if @notUniqueMsg
88
+ notUniqueMsg = @notUniqueMsg
89
+ else
90
+ notUniqueMsg = "That #{englishName.downcase} is already taken. " +
91
+ "Please choose another."
92
+ end
93
+ raise FieldValueError, notUniqueMsg, caller
94
+ end
95
+ end
96
+
97
+ # Returns the name that this field is referenced by in the MySQL table. By
98
+ # default this is the same as the name; to override it, set
99
+ # ObjectField#dbFieldName.
100
+ def nameForSQL
101
+ dbFieldName
102
+ end
103
+
104
+ # Returns a string value suitable for committing this field's value to
105
+ # MySQL.
106
+ def valueForSQL(value)
107
+ value || 'null'
108
+ end
109
+
110
+ def firstTime(fieldManager) #:nodoc:
111
+ pkId = fieldManager.getpkId
112
+ pkId == nil
113
+ end
114
+
115
+ def prevValue(pkId) #:nodoc:
116
+ prevObject = ObjectStore.getObjectStore.get(@objectType, pkId)
117
+ prevObject.send(name)
118
+ end
119
+
120
+ def processBeforeVerify(value) #:nodoc:
121
+ value = @default if value == nil
122
+ value
123
+ end
124
+
125
+ # Given the SQL value string, returns a Ruby-native value.
126
+ def valueFromSQL(string)
127
+ string
128
+ end
129
+
130
+ def <=>(other)
131
+ if @objectType == other.objectType && name == other.name
132
+ 0
133
+ else
134
+ object_id <=> other.object_id
135
+ end
136
+ end
137
+
138
+ def dbWillAutomaticallyWrite #:nodoc:
139
+ false
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,29 @@
1
+ require 'lafcadio/objectField/TextField'
2
+
3
+ module Lafcadio
4
+ # A PasswordField is simply a TextField that is expected to contain a password
5
+ # value. It can be set to auto-generate a password at random.
6
+ class PasswordField < TextField
7
+ # Returns a random 8-letter alphanumeric password.
8
+ def PasswordField.randomPassword
9
+ chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".
10
+ split(//)
11
+ value = ""
12
+ 0.upto(8) { |i| value += chars[rand(chars.size)] }
13
+ value
14
+ end
15
+
16
+ attr_reader :maxLength
17
+ attr_accessor :autoGenerate
18
+
19
+ # [objectType] The domain class that this object field belongs to.
20
+ # [name] The name of this field.
21
+ # [maxLength] The maximum length of the password. (Deprecated)
22
+ # [englishName] The descriptive English name of this field. (Deprecated)
23
+ def initialize(objectType, maxLength, name = "password", englishName = nil)
24
+ super(objectType, name, englishName)
25
+ @maxLength = maxLength
26
+ @autoGenerate = true
27
+ end
28
+ end
29
+ end