lafcadio 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
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