lafcadio 0.5.2 → 0.6.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.
@@ -1,16 +0,0 @@
1
- dir = Dir.new 'lafcadio/'
2
- dir.each { |entry|
3
- if ![ '.', '..', 'CVS' ].index(entry) && entry !~ /~$/
4
- begin
5
- subDirName = entry
6
- subDir = Dir.new "lafcadio/#{ subDirName }"
7
- subDir.each { |entry|
8
- if entry =~ /.rb$/
9
- require "lafcadio/#{subDirName}/#{entry}"
10
- end
11
- }
12
- rescue StandardError
13
- # not a directory, whatev
14
- end
15
- end
16
- }
@@ -1,93 +0,0 @@
1
- module Lafcadio
2
- # Represents a specific month in time. With the exception of Month.month_names
3
- # (which returns a zero-based array), every usage of the month value assumes
4
- # 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( month = nil, year = 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( resultMonth, resultYear )
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
@@ -1,93 +0,0 @@
1
- require 'lafcadio/objectStore'
2
-
3
- module Lafcadio
4
- class MockDbBridge #:nodoc:
5
- attr_reader :last_pk_id_inserted, :retrievals_by_type, :query_count
6
-
7
- def initialize
8
- @objects = {}
9
- @retrievals_by_type = Hash.new 0
10
- @query_count = Hash.new( 0 )
11
- end
12
-
13
- def commit(db_object)
14
- objectsByObjectType = get_objects_by_domain_class( db_object.object_type )
15
- if db_object.delete
16
- objectsByObjectType.delete db_object.pk_id
17
- else
18
- object_pk_id = get_pk_id_before_committing( db_object )
19
- objectsByObjectType[object_pk_id] = db_object
20
- end
21
- end
22
-
23
- def _get_all(object_type)
24
- @retrievals_by_type[object_type] = @retrievals_by_type[object_type] + 1
25
- @objects[object_type] ? @objects[object_type].values : []
26
- end
27
-
28
- def get_collection_by_query(query)
29
- @query_count[query] += 1
30
- objects = []
31
- _get_all( query.object_type ).each { |dbObj|
32
- if query.condition
33
- objects << dbObj if query.condition.object_meets(dbObj)
34
- else
35
- objects << dbObj
36
- end
37
- }
38
- if (range = query.limit)
39
- objects = objects[0..(range.last - range.first)]
40
- end
41
- if ( order_by = query.order_by )
42
- objects = objects.sort_by { |dobj| dobj.send( order_by ) }
43
- objects.reverse! if query.order_by_order == Query::DESC
44
- end
45
- objects
46
- end
47
-
48
- def get_pk_id_before_committing( db_object )
49
- object_pk_id = db_object.pk_id
50
- unless object_pk_id
51
- maxpk_id = 0
52
- get_objects_by_domain_class( db_object.object_type ).keys.each { |pk_id|
53
- maxpk_id = pk_id if pk_id > maxpk_id
54
- }
55
- @last_pk_id_inserted = maxpk_id + 1
56
- object_pk_id = @last_pk_id_inserted
57
- end
58
- object_pk_id
59
- end
60
-
61
- def get_objects_by_domain_class( domain_class )
62
- objects_by_domain_class = @objects[domain_class]
63
- unless objects_by_domain_class
64
- objects_by_domain_class = {}
65
- @objects[domain_class] = objects_by_domain_class
66
- end
67
- objects_by_domain_class
68
- end
69
-
70
- def group_query( query )
71
- if query.class == Query::Max
72
- if ( query.field_name == query.object_type.sql_primary_key_name ||
73
- query.field_name == 'rate' )
74
- query.collect( @objects[query.object_type].values )
75
- else
76
- raise "Can't handle query with sql '#{ query.to_sql }'"
77
- end
78
- end
79
- end
80
- end
81
-
82
- # Externally, the MockObjectStore looks and acts exactly like the ObjectStore,
83
- # but stores all its data in memory. This makes it very useful for unit
84
- # testing, and in fact LafcadioTestCase#setup creates a new instance of
85
- # MockObjectStore for each test case.
86
- class MockObjectStore < ObjectStore
87
- public_class_method :new
88
-
89
- def initialize # :nodoc:
90
- super( MockDbBridge.new )
91
- end
92
- end
93
- end
@@ -1,618 +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, :object_type
11
- attr_accessor :not_null, :unique, :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
- parameters['english_name'] )
21
- if ( db_field_name = parameters['db_field_name'] )
22
- instance.db_field_name = db_field_name
23
- end
24
- instance
25
- end
26
-
27
- def self.instantiation_parameters( fieldElt ) #:nodoc:
28
- parameters = {}
29
- parameters['name'] = fieldElt.attributes['name']
30
- parameters['english_name'] = fieldElt.attributes['english_name']
31
- parameters['db_field_name'] = fieldElt.attributes['db_field_name']
32
- parameters
33
- end
34
-
35
- def self.value_type #:nodoc:
36
- Object
37
- end
38
-
39
- # [object_type] The domain class that this object field belongs to.
40
- # [name] The name of this field.
41
- # [english_name] The descriptive English name of this field. (Deprecated)
42
- def initialize(object_type, name, english_name = nil )
43
- @object_type = object_type
44
- @name = name
45
- @db_field_name = name
46
- @not_null = true
47
- @unique = false
48
- @english_nameOrNil = english_name
49
- end
50
-
51
- def <=>(other)
52
- if @object_type == other.object_type && name == other.name
53
- 0
54
- else
55
- object_id <=> other.object_id
56
- end
57
- end
58
-
59
- def bind_write?; false; end #:nodoc:
60
-
61
- def db_table_and_field_name
62
- "#{ object_type.table_name }.#{ db_field_name }"
63
- end
64
-
65
- def db_will_automatically_write #:nodoc:
66
- false
67
- end
68
-
69
- def english_name #:nodoc:
70
- @english_nameOrNil || English.camel_case_to_english(name).capitalize
71
- end
72
-
73
- # Returns the name that this field is referenced by in the MySQL table. By
74
- # default this is the same as the name; to override it, set
75
- # ObjectField#db_field_name.
76
- def name_for_sql
77
- db_field_name
78
- end
79
-
80
- def null_error_msg #:nodoc:
81
- "#{ self.object_type.name }##{ name } can not be nil."
82
- end
83
-
84
- def prev_value(pk_id) #:nodoc:
85
- prevObject = ObjectStore.get_object_store.get(@object_type, pk_id)
86
- prevObject.send(name)
87
- end
88
-
89
- def process_before_verify(value) #:nodoc:
90
- value = @default if value == nil
91
- value
92
- end
93
-
94
- # Returns a string value suitable for committing this field's value to
95
- # MySQL.
96
- def value_for_sql(value)
97
- value || 'null'
98
- end
99
-
100
- def verify(value, pk_id) #:nodoc:
101
- if value.nil? && not_null
102
- raise FieldValueError, null_error_msg, caller
103
- end
104
- verify_non_nil( value, pk_id ) if value
105
- end
106
-
107
- def verify_non_nil( value, pk_id )
108
- value_type = self.class.value_type
109
- unless value.class <= value_type
110
- raise( FieldValueError,
111
- "#{ object_type.name }##{ name } needs a " + value_type.name +
112
- " value.",
113
- caller )
114
- end
115
- verify_uniqueness(value, pk_id) if unique
116
- end
117
-
118
- def verify_uniqueness(value, pk_id) #:nodoc:
119
- inferrer = Query::Inferrer.new( @object_type ) { |domain_obj|
120
- Query.And( domain_obj.send( self.name ).equals( value ),
121
- domain_obj.pk_id.equals( pk_id ).not )
122
- }
123
- collisions = ObjectStore.get_object_store.get_subset( inferrer.execute )
124
- if collisions.size > 0
125
- notUniqueMsg = "That #{english_name.downcase} already exists."
126
- raise FieldValueError, notUniqueMsg, caller
127
- end
128
- end
129
-
130
- # Given the SQL value string, returns a Ruby-native value.
131
- def value_from_sql(string)
132
- string
133
- end
134
- end
135
-
136
- # IntegerField represents an integer.
137
- class IntegerField < ObjectField
138
- def value_from_sql(string) #:nodoc:
139
- value = super
140
- value ? value.to_i : nil
141
- end
142
- end
143
-
144
- # A TextField is expected to contain a string value.
145
- class TextField < ObjectField
146
- def value_for_sql(value) #:nodoc:
147
- if value
148
- value = value.gsub(/(\\?')/) { |m| m.length == 1 ? "''" : m }
149
- value = value.gsub(/\\/) { '\\\\' }
150
- "'#{value}'"
151
- else
152
- "null"
153
- end
154
- end
155
- end
156
-
157
- class AutoIncrementField < IntegerField # :nodoc:
158
- attr_reader :object_type
159
-
160
- def initialize(object_type, name, english_name = nil)
161
- super(object_type, name, english_name)
162
- @object_type = object_type
163
- end
164
-
165
- def html_widget_value_str(value)
166
- if value != nil
167
- super value
168
- else
169
- highestValue = 0
170
- ObjectStore.get_object_store.get_all(object_type).each { |obj|
171
- aValue = obj.send(name).to_i
172
- highestValue = aValue if aValue > highestValue
173
- }
174
- (highestValue + 1).to_s
175
- end
176
- end
177
- end
178
-
179
- # BlobField stores a string value and expects to store its value in a BLOB
180
- # field in the database.
181
- class BlobField < ObjectField
182
- attr_accessor :size
183
-
184
- def self.value_type; String; end
185
-
186
- def bind_write?; true; end #:nodoc:
187
-
188
- def value_for_sql(value); "?"; end #:nodoc:
189
- end
190
-
191
- # BooleanField represents a boolean value. By default, it assumes that the
192
- # table field represents True and False with the integers 1 and 0. There are
193
- # two different ways to change this default.
194
- #
195
- # First, BooleanField includes a few enumerated defaults. Currently there are
196
- # only
197
- # * BooleanField::ENUMS_ONE_ZERO (the default, uses integers 1 and 0)
198
- # * BooleanField::ENUMS_CAPITAL_YES_NO (uses characters 'Y' and 'N')
199
- # In the XML class definition, this field would look like
200
- # <field name="field_name" class="BooleanField"
201
- # enum_type="ENUMS_CAPITAL_YES_NO"/>
202
- # If you're defining a field in Ruby, simply set BooleanField#enum_type to one
203
- # of the values.
204
- #
205
- # For more fine-grained specification you can pass specific values in. Use
206
- # this format for the XML class definition:
207
- # <field name="field_name" class="BooleanField">
208
- # <enums>
209
- # <enum key="true">yin</enum>
210
- # <enum key="false">tang</enum>
211
- # </enums>
212
- # </field>
213
- # If you're defining the field in Ruby, set BooleanField#enums to a hash.
214
- # myBooleanField.enums = { true => 'yin', false => 'yang' }
215
- #
216
- # +enums+ takes precedence over +enum_type+.
217
- class BooleanField < ObjectField
218
- ENUMS_ONE_ZERO = 0
219
- ENUMS_CAPITAL_YES_NO = 1
220
-
221
- attr_accessor :enum_type, :enums
222
-
223
- def initialize(object_type, name, english_name = nil)
224
- super(object_type, name, english_name)
225
- @enum_type = ENUMS_ONE_ZERO
226
- @enums = nil
227
- end
228
-
229
- def false_enum # :nodoc:
230
- get_enums[false]
231
- end
232
-
233
- def get_enums( value = nil ) # :nodoc:
234
- if @enums
235
- @enums
236
- elsif @enum_type == ENUMS_ONE_ZERO
237
- if value.class == String
238
- { true => '1', false => '0' }
239
- else
240
- { true => 1, false => 0 }
241
- end
242
- elsif @enum_type == ENUMS_CAPITAL_YES_NO
243
- { true => 'Y', false => 'N' }
244
- else
245
- raise MissingError
246
- end
247
- end
248
-
249
- def text_enum_type # :nodoc:
250
- @enums ? @enums[true].class == String : @enum_type == ENUMS_CAPITAL_YES_NO
251
- end
252
-
253
- def true_enum( value = nil ) # :nodoc:
254
- get_enums( value )[true]
255
- end
256
-
257
- def value_for_sql(value) # :nodoc:
258
- if value
259
- vfs = true_enum
260
- else
261
- vfs = false_enum
262
- end
263
- text_enum_type ? "'#{vfs}'" : vfs
264
- end
265
-
266
- def value_from_sql(value, lookupLink = true) # :nodoc:
267
- value == true_enum( value )
268
- end
269
- end
270
-
271
- # DateField represents a Date.
272
- class DateField < ObjectField
273
- RANGE_NEAR_FUTURE = 0
274
- RANGE_PAST = 1
275
-
276
- def self.value_type # :nodoc:
277
- Date
278
- end
279
-
280
- attr_accessor :range
281
-
282
- def initialize(object_type, name = "date", english_name = nil)
283
- super(object_type, name, english_name)
284
- @range = RANGE_NEAR_FUTURE
285
- end
286
-
287
- def value_for_sql(value) # :nodoc:
288
- value ? "'#{value.to_s}'" : 'null'
289
- end
290
-
291
- def value_from_sql(dbiDate, lookupLink = true) # :nodoc:
292
- begin
293
- dbiDate ? dbiDate.to_date : nil
294
- rescue ArgumentError
295
- nil
296
- end
297
- end
298
- end
299
-
300
- # DateTimeField represents a DateTime.
301
- class DateTimeField < ObjectField
302
- def value_for_sql(value) # :nodoc:
303
- if value
304
- year = value.year
305
- month = value.mon.to_s.pad( 2, "0" )
306
- day = value.day.to_s.pad( 2, "0" )
307
- hour = value.hour.to_s.pad( 2, "0" )
308
- minute = value.min.to_s.pad( 2, "0" )
309
- second = value.sec.to_s.pad( 2, "0" )
310
- "'#{year}-#{month}-#{day} #{hour}:#{minute}:#{second}'"
311
- else
312
- "null"
313
- end
314
- end
315
-
316
- def value_from_sql(dbi_value, lookupLink = true) # :nodoc:
317
- dbi_value ? dbi_value.to_time : nil
318
- end
319
- end
320
-
321
- # DecimalField represents a decimal value.
322
- class DecimalField < ObjectField
323
- def self.instantiate_with_parameters( domain_class, parameters ) #:nodoc:
324
- self.new( domain_class, parameters['name'], parameters['english_name'] )
325
- end
326
-
327
- def self.value_type #:nodoc:
328
- Numeric
329
- end
330
-
331
- def process_before_verify(value) #:nodoc:
332
- value = super value
333
- value != nil && value != '' ? value.to_f : nil
334
- end
335
-
336
- def value_from_sql(string, lookupLink = true) #:nodoc:
337
- string != nil ? string.to_f : nil
338
- end
339
- end
340
-
341
- # EmailField takes a text value that is expected to be formatted as a single
342
- # valid email address.
343
- class EmailField < TextField
344
- # Is +address+ a valid email address?
345
- def self.valid_address(address)
346
- address =~ /^[^ @]+@[^ \.]+\.[^ ,]+$/
347
- end
348
-
349
- def initialize(object_type, name = "email", english_name = nil)
350
- super(object_type, name, english_name)
351
- end
352
-
353
- def null_error_msg #:nodoc:
354
- "Please enter an email address."
355
- end
356
-
357
- def verify_non_nil(value, pk_id) #:nodoc:
358
- super(value, pk_id)
359
- if !EmailField.valid_address(value)
360
- raise( FieldValueError,
361
- "#{ object_type.name }##{ name } needs a valid email address.",
362
- caller )
363
- end
364
- end
365
- end
366
-
367
- # EnumField represents an enumerated field that can only be set to one of a
368
- # set range of string values. To set the enumeration in the class definition
369
- # XML, use the following format:
370
- # <field name="flavor" class="EnumField">
371
- # <enums>
372
- # <enum>Vanilla</enum>
373
- # <enum>Chocolate</enum>
374
- # <enum>Lychee</enum>
375
- # </enums>
376
- # </field>
377
- # If you're defining the field in Ruby, you can simply pass in an array of
378
- # enums as the +enums+ argument.
379
- #
380
- class EnumField < TextField
381
- def self.instantiate_with_parameters( domain_class, parameters ) #:nodoc:
382
- self.new( domain_class, parameters['name'], parameters['enums'],
383
- parameters['english_name'] )
384
- end
385
-
386
- def self.enum_queue_hash( fieldElt )
387
- enumValues = []
388
- fieldElt.elements.each( 'enums/enum' ) { |enumElt|
389
- enumValues << enumElt.attributes['key']
390
- enumValues << enumElt.text.to_s
391
- }
392
- QueueHash.new( *enumValues )
393
- end
394
-
395
- def self.instantiation_parameters( fieldElt ) #:nodoc:
396
- parameters = super( fieldElt )
397
- if fieldElt.elements['enums'][1].attributes['key']
398
- parameters['enums'] = enum_queue_hash( fieldElt )
399
- else
400
- parameters['enums'] = []
401
- fieldElt.elements.each( 'enums/enum' ) { |enumElt|
402
- parameters['enums'] << enumElt.text.to_s
403
- }
404
- end
405
- parameters
406
- end
407
-
408
- attr_reader :enums
409
-
410
- # [object_type] The domain class that this field belongs to.
411
- # [name] The name of this domain class.
412
- # [enums] An array of Strings representing the possible choices for
413
- # this field.
414
- # [english_name] The English name of this field. (Deprecated)
415
- def initialize(object_type, name, enums, english_name = nil)
416
- super object_type, name, english_name
417
- if enums.class == Array
418
- @enums = QueueHash.new_from_array enums
419
- else
420
- @enums = enums
421
- end
422
- end
423
-
424
- def value_for_sql(value) #:nodoc:
425
- value != '' ?(super(value)) : 'null'
426
- end
427
-
428
- def verify_non_nil( value, pk_id ) #:nodoc:
429
- super
430
- if @enums[value].nil?
431
- key_str = '[ ' +
432
- ( @enums.keys.map { |key| "\"#{ key }\"" } ).join(', ') + ' ]'
433
- err_str = "#{ @object_type.name }##{ name } needs a value that is " +
434
- "one of #{ key_str }"
435
- raise( FieldValueError, err_str, caller )
436
- end
437
- end
438
- end
439
-
440
- class FieldValueError < RuntimeError #:nodoc:
441
- end
442
-
443
- # A LinkField is used to link from one domain class to another.
444
- class LinkField < ObjectField
445
- def self.instantiate_with_parameters( domain_class, parameters ) #:nodoc:
446
- instance = self.new(
447
- domain_class, parameters['linked_type'], parameters['name'],
448
- parameters['english_name'], parameters['delete_cascade']
449
- )
450
- if parameters['db_field_name']
451
- instance.db_field_name = parameters['db_field_name']
452
- end
453
- instance
454
- end
455
-
456
- def self.instantiation_parameters( fieldElt ) #:nodoc:
457
- parameters = super( fieldElt )
458
- linked_typeStr = fieldElt.attributes['linked_type']
459
- linked_type = DomainObject.get_object_type_from_string( linked_typeStr )
460
- parameters['linked_type'] = linked_type
461
- parameters['delete_cascade'] = fieldElt.attributes['delete_cascade'] == 'y'
462
- parameters
463
- end
464
-
465
- attr_reader :linked_type
466
- attr_accessor :delete_cascade
467
-
468
- # [object_type] The domain class that this field belongs to.
469
- # [linked_type] The domain class that this field points to.
470
- # [name] The name of this field.
471
- # [english_name] The English name of this field. (Deprecated)
472
- # [delete_cascade] If this is true, deleting the domain object that is linked
473
- # to will cause this domain object to be deleted as well.
474
- def initialize( object_type, linked_type, name = nil, english_name = nil,
475
- delete_cascade = false )
476
- unless name
477
- linked_type.name =~ /::/
478
- name = $' || linked_type.name
479
- name = name.decapitalize
480
- end
481
- super(object_type, name, english_name)
482
- ( @linked_type, @delete_cascade ) = linked_type, delete_cascade
483
- end
484
-
485
- def value_from_sql(string) #:nodoc:
486
- string != nil ? DomainObjectProxy.new(@linked_type, string.to_i) : nil
487
- end
488
-
489
- def value_for_sql(value) #:nodoc:
490
- if !value
491
- "null"
492
- elsif value.pk_id
493
- value.pk_id
494
- else
495
- raise( DomainObjectInitError, "Can't commit #{name} without pk_id",
496
- caller )
497
- end
498
- end
499
-
500
- def verify_non_nil(value, pk_id) #:nodoc:
501
- super
502
- if @linked_type != @object_type && pk_id
503
- subsetLinkField = @linked_type.class_fields.find { |field|
504
- field.class == SubsetLinkField && field.subset_field == @name
505
- }
506
- if subsetLinkField
507
- verify_subset_link_field( subsetLinkField, pk_id )
508
- end
509
- end
510
- end
511
-
512
- def verify_subset_link_field( subsetLinkField, pk_id )
513
- begin
514
- prevObj = ObjectStore.get_object_store.get(object_type, pk_id)
515
- prevObjLinkedTo = prevObj.send(name)
516
- possiblyMyObj = prevObjLinkedTo.send(subsetLinkField.name)
517
- if possiblyMyObj && possiblyMyObj.pk_id == pk_id
518
- cantChangeMsg = "You can't change that."
519
- raise FieldValueError, cantChangeMsg, caller
520
- end
521
- rescue DomainObjectNotFoundError
522
- # no previous value, so nothing to check for
523
- end
524
- end
525
- end
526
-
527
- class MoneyField < DecimalField #:nodoc:
528
- end
529
-
530
- # Accepts a Month as a value. This field automatically saves in MySQL as a
531
- # date corresponding to the first day of the month.
532
- class MonthField < DateField
533
- def self.value_type #:nodoc:
534
- Month
535
- end
536
-
537
- def value_for_sql(value) #:nodoc:
538
- "'#{value.year}-#{value.month}-01'"
539
- end
540
- end
541
-
542
- # A PasswordField is simply a TextField that is expected to contain a password
543
- # value. It can be set to auto-generate a password at random.
544
- class PasswordField < TextField
545
- # Returns a random 8-letter alphanumeric password.
546
- def self.random_password
547
- chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".
548
- split(//)
549
- value = ""
550
- 0.upto(8) { |i| value += chars[rand(chars.size)] }
551
- value
552
- end
553
- end
554
-
555
- # A StateField is a specialized subclass of EnumField; its possible values are
556
- # any of the 50 states of the United States, stored as each state's two-letter
557
- # postal code.
558
- class StateField < EnumField
559
- def initialize(object_type, name = "state", english_name = nil)
560
- super object_type, name, UsStates.states, english_name
561
- end
562
- end
563
-
564
- class SubsetLinkField < LinkField #:nodoc:
565
- def self.instantiate_with_parameters( domain_class, parameters )
566
- self.new( domain_class, parameters['linked_type'],
567
- parameters['subset_field'], parameters['name'],
568
- parameters['english_name'] )
569
- end
570
-
571
- def self.instantiation_parameters( fieldElt )
572
- parameters = super( fieldElt )
573
- parameters['subset_field'] = fieldElt.attributes['subset_field']
574
- parameters
575
- end
576
-
577
- attr_accessor :subset_field
578
-
579
- def initialize(object_type, linked_type, subset_field,
580
- name = linked_type.name.downcase, english_name = nil)
581
- super(object_type, linked_type, name, english_name)
582
- @subset_field = subset_field
583
- end
584
- end
585
-
586
- # TextListField maps to any String SQL field that tries to represent a
587
- # quick-and-dirty list with a comma-separated string. It returns an Array.
588
- # For example, a SQL field with the value "john,bill,dave", then the Ruby
589
- # field will have the value <tt>[ "john", "bill", "dave" ]</tt>.
590
- class TextListField < ObjectField
591
- def self.value_type #:nodoc:
592
- Array
593
- end
594
-
595
- def value_for_sql(objectValue) #:nodoc:
596
- "'" + objectValue.join(',') + "'"
597
- end
598
-
599
- def value_from_sql(sqlString, lookupLink = true) #:nodoc:
600
- if sqlString
601
- sqlString.split ','
602
- else
603
- []
604
- end
605
- end
606
- end
607
-
608
- class TimeStampField < DateTimeField #:nodoc:
609
- def initialize(object_type, name = 'timeStamp', english_name = nil)
610
- super( object_type, name, english_name )
611
- @not_null = false
612
- end
613
-
614
- def db_will_automatically_write
615
- true
616
- end
617
- end
618
- end