lafcadio 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,6 +9,7 @@ module Lafcadio
9
9
  @objects = {}
10
10
  @next_pk_ids = {}
11
11
  @queries = []
12
+ @transaction = nil
12
13
  end
13
14
 
14
15
  def all( domain_class )
@@ -22,21 +23,23 @@ module Lafcadio
22
23
  all( domain_class ).each { |dbObj|
23
24
  objects << dbObj if query.dobj_satisfies?( dbObj )
24
25
  }
25
- objects = order_collection( objects, query )
26
- if (range = query.limit); objects = objects[range]; end
27
- objects
26
+ query.order_and_limit_collection objects
28
27
  end
29
28
 
30
29
  def commit(db_object)
31
30
  if db_object.pk_id and !db_object.pk_id.is_a?( Integer )
32
31
  raise ArgumentError
33
32
  end
34
- objects_by_domain_class = objects_by_domain_class db_object.domain_class
35
- if db_object.delete
36
- objects_by_domain_class.delete( db_object.pk_id )
33
+ if @transaction
34
+ @transaction << db_object
37
35
  else
38
- object_pk_id = pre_commit_pk_id( db_object )
39
- objects_by_domain_class[object_pk_id] = db_object
36
+ objects_by_domain_class = objects_by_domain_class db_object.domain_class
37
+ if db_object.delete
38
+ objects_by_domain_class.delete( db_object.pk_id )
39
+ else
40
+ object_pk_id = pre_commit_pk_id( db_object )
41
+ objects_by_domain_class[object_pk_id] = db_object
42
+ end
40
43
  end
41
44
  end
42
45
 
@@ -44,40 +47,33 @@ module Lafcadio
44
47
  query.collect objects_by_domain_class( query.domain_class ).values
45
48
  end
46
49
 
50
+ def next_pk_id( domain_class )
51
+ dobjs = objects_by_domain_class( domain_class ).values
52
+ dobjs.inject( 0 ) { |memo, obj| memo > obj.pk_id ? memo : obj.pk_id } + 1
53
+ end
54
+
47
55
  def objects_by_domain_class( domain_class )
48
56
  @objects[domain_class] = {} unless @objects[domain_class]
49
57
  @objects[domain_class]
50
58
  end
51
59
 
52
- def order_collection( objects, query )
53
- objects = objects.sort_by { |dobj|
54
- if ( order_by = query.order_by ).nil?
55
- dobj.pk_id
56
- elsif order_by.is_a?( Array )
57
- order_by.map { |field_name| dobj.send( field_name ) }
58
- else
59
- dobj.send order_by
60
- end
61
- }
62
- objects.reverse! if query.order_by_order == Query::DESC
63
- objects
64
- end
65
-
66
- def pre_commit_pk_id( db_object )
67
- if db_object.pk_id
68
- db_object.pk_id
60
+ def pre_commit_pk_id( domain_object )
61
+ @next_pk_ids = {} unless @next_pk_ids
62
+ if (next_pk_id = @next_pk_ids[domain_object.domain_class])
63
+ @next_pk_ids[domain_object.domain_class] = nil
64
+ @last_pk_id_inserted = next_pk_id
65
+ elsif domain_object.pk_id
66
+ domain_object.pk_id
67
+ elsif ( next_pk_id = @next_pk_ids[domain_object.domain_class] )
68
+ @last_pk_id_inserted = next_pk_id
69
+ @next_pk_ids[domain_object.domain_class] = nil
70
+ next_pk_id
69
71
  else
70
- if ( next_pk_id = @next_pk_ids[db_object.domain_class] )
71
- @last_pk_id_inserted = next_pk_id
72
- @next_pk_ids[db_object.domain_class] = nil
73
- next_pk_id
74
- else
75
- pk_ids = objects_by_domain_class( db_object.domain_class ).keys
76
- @last_pk_id_inserted = pk_ids.max ? pk_ids.max + 1 : 1
77
- end
72
+ pk_ids = objects_by_domain_class( domain_object.domain_class ).keys
73
+ @last_pk_id_inserted = pk_ids.max ? pk_ids.max + 1 : 1
78
74
  end
79
75
  end
80
-
76
+
81
77
  def queries( domain_class = nil )
82
78
  @queries.select { |qry|
83
79
  domain_class ? qry.domain_class == domain_class : true
@@ -89,16 +85,43 @@ module Lafcadio
89
85
  end
90
86
 
91
87
  def set_next_pk_id( domain_class, npi )
88
+ @next_pk_ids = {} unless @next_pk_ids
92
89
  @next_pk_ids[ domain_class ] = npi
93
90
  end
91
+
92
+ def transaction( action )
93
+ tr = MockDbBridge::Transaction.new
94
+ @transaction = tr
95
+ begin
96
+ action.call tr
97
+ @transaction = nil
98
+ tr.each do |dobj_to_commit| commit( dobj_to_commit ); end
99
+ rescue RollbackError; end
100
+ end
101
+
102
+ class Transaction < Array
103
+ def rollback; raise RollbackError; end
104
+ end
105
+
106
+ class RollbackError < StandardError #:nodoc:
107
+ end
94
108
  end
95
109
 
96
110
  # Externally, the MockObjectStore looks and acts exactly like the ObjectStore,
97
111
  # but stores all its data in memory. This makes it very useful for unit
98
112
  # testing, and in fact LafcadioTestCase#setup creates a new instance of
99
- # MockObjectStore for each test case.
113
+ # MockObjectStore for each test case. For example:
114
+ #
115
+ # class SomeTestCase < Test::Unit::TestCase
116
+ # def setup
117
+ # @mock_object_store = Lafcadio::MockObjectStore.new
118
+ # Lafcadio::ObjectStore.set_object_store @mock_object_store
119
+ # end
120
+ # end
100
121
  class MockObjectStore < ObjectStore
101
- def self.db_bridge; MockDbBridge.new; end
122
+ def self.db_bridge #:nodoc:
123
+ MockDbBridge.new
124
+ end
102
125
 
103
126
  public_class_method :new
104
127
 
@@ -148,9 +148,9 @@ module Lafcadio
148
148
  end
149
149
  end
150
150
 
151
- # BlobField stores a string value and expects to store its value in a BLOB
152
- # field in the database.
153
- class BlobField < ObjectField
151
+ # BinaryField stores a string value and expects to store its value in a
152
+ # binary field in the database.
153
+ class BinaryField < ObjectField
154
154
  def self.value_type #:nodoc:
155
155
  String
156
156
  end
@@ -166,12 +166,12 @@ module Lafcadio
166
166
  #
167
167
  # First, BooleanField includes a few enumerated defaults. Currently there are
168
168
  # only
169
- # * BooleanField::ENUMS_ONE_ZERO (the default, uses integers 1 and 0)
170
- # * BooleanField::ENUMS_CAPITAL_YES_NO (uses characters 'Y' and 'N')
169
+ # * :one_zero (the default, uses integers 1 and 0)
170
+ # * :capital_yes_no (uses characters 'Y' and 'N')
171
+ # * :raw_true_false (uses unquoted values 'true' and 'false')
171
172
  # In a class definition, this would look like
172
173
  # class User < Lafcadio::DomainObject
173
- # boolean 'administrator',
174
- # { 'enum_type' => Lafcadio::BooleanField::ENUMS_CAPITAL_YES_NO }
174
+ # boolean 'administrator', { 'enum_type' => :capital_yes_no }
175
175
  # end
176
176
  #
177
177
  # For more fine-grained specification you can pass a hash with the keys
@@ -182,31 +182,42 @@ module Lafcadio
182
182
  # end
183
183
  # +enums+ takes precedence over +enum_type+.
184
184
  class BooleanField < ObjectField
185
- ENUMS_ONE_ZERO = 0
186
- ENUMS_CAPITAL_YES_NO = 1
187
-
188
185
  attr_accessor :enum_type
189
186
  attr_writer :enums
190
187
 
191
188
  def initialize( domain_class, name )
192
189
  super( domain_class, name )
193
- @enum_type = ENUMS_ONE_ZERO
194
190
  @enums = nil
195
191
  end
192
+
193
+ def default_enum_type
194
+ case ObjectStore.db_type
195
+ when 'Mysql'
196
+ :one_zero
197
+ when 'Pg'
198
+ :raw_true_false
199
+ end
200
+ end
196
201
 
197
202
  def enums( value = nil ) # :nodoc:
198
203
  if @enums
199
204
  @enums
200
- elsif @enum_type == ENUMS_ONE_ZERO
201
- if value.is_a?( String )
202
- { true => '1', false => '0' }
205
+ else
206
+ enum_type = ( @enum_type or default_enum_type )
207
+ case enum_type
208
+ when :one_zero
209
+ if value.is_a?( String )
210
+ { true => '1', false => '0' }
211
+ else
212
+ { true => 1, false => 0 }
213
+ end
214
+ when :capital_yes_no
215
+ { true => 'Y', false => 'N' }
216
+ when :raw_true_false
217
+ { true => true, false => false }
203
218
  else
204
- { true => 1, false => 0 }
219
+ raise MissingError
205
220
  end
206
- elsif @enum_type == ENUMS_CAPITAL_YES_NO
207
- { true => 'Y', false => 'N' }
208
- else
209
- raise MissingError
210
221
  end
211
222
  end
212
223
 
@@ -215,7 +226,7 @@ module Lafcadio
215
226
  end
216
227
 
217
228
  def text_enum_type? # :nodoc:
218
- @enums ? @enums[true].class == String : @enum_type == ENUMS_CAPITAL_YES_NO
229
+ @enums ? @enums[true].class == String : @enum_type == :capital_yes_no
219
230
  end
220
231
 
221
232
  def true_enum( value = nil ) # :nodoc:
@@ -4,14 +4,28 @@ require 'lafcadio/util'
4
4
 
5
5
  module Lafcadio
6
6
  # ObjectField is the abstract base class of any field for domain objects.
7
+ # Fields can be added to a domain class using DomainObject.string,
8
+ # DomainObject.integer, etc.
9
+ #
10
+ # class User < Lafcadio::DomainObject
11
+ # string 'fname'
12
+ # date 'birthday'
13
+ # end
14
+ #
15
+ # All fields accept the following arguments in hashes:
16
+ # [not_nil] This is +true+ by default. Set it to +false+ to avoid
17
+ # checking for nil values in tests.
18
+ # [db_field_name] By default, fields are assumed to have the same name in
19
+ # the database, but you can override this assumption using
20
+ # +db_field_name+.
21
+ #
22
+ # class User < Lafcadio::DomainObject
23
+ # string 'fname', { 'not_nil' => false }
24
+ # date 'birthday', { 'db_field_name' => 'bday' }
25
+ # end
7
26
  class ObjectField
8
- include Comparable
9
-
10
- attr_reader :name, :domain_class
11
- attr_accessor :not_null, :db_field_name
12
-
13
- def self.instantiate_from_xml( domain_class, fieldElt ) #:nodoc:
14
- parameters = instantiation_parameters( fieldElt )
27
+ def self.create_from_xml( domain_class, fieldElt ) #:nodoc:
28
+ parameters = creation_parameters( fieldElt )
15
29
  create_with_args( domain_class, parameters )
16
30
  end
17
31
 
@@ -23,7 +37,7 @@ module Lafcadio
23
37
  instance
24
38
  end
25
39
 
26
- def self.instantiation_parameters( fieldElt ) #:nodoc:
40
+ def self.creation_parameters( fieldElt ) #:nodoc:
27
41
  parameters = {}
28
42
  parameters['name'] = fieldElt.attributes['name']
29
43
  parameters['db_field_name'] = fieldElt.attributes['db_field_name']
@@ -34,13 +48,18 @@ module Lafcadio
34
48
  Object
35
49
  end
36
50
 
37
- # [domain_class] The domain class that this object field belongs to.
51
+ include Comparable
52
+
53
+ attr_reader :domain_class, :name
54
+ attr_accessor :db_field_name, :not_nil
55
+
56
+ # [domain_class] The domain class that this field belongs to.
38
57
  # [name] The name of this field.
39
58
  def initialize( domain_class, name )
40
59
  @domain_class = domain_class
41
60
  @name = name
42
61
  @db_field_name = name
43
- @not_null = true
62
+ @not_nil = true
44
63
  end
45
64
 
46
65
  def <=>(other)
@@ -51,23 +70,18 @@ module Lafcadio
51
70
  end
52
71
  end
53
72
 
54
- def bind_write?; false; end #:nodoc:
73
+ def bind_write? #:nodoc:
74
+ false
75
+ end
55
76
 
56
- def db_table_and_field_name
77
+ def db_column #:nodoc:
57
78
  "#{ domain_class.table_name }.#{ db_field_name }"
58
79
  end
59
80
 
60
- def db_will_automatically_write #:nodoc:
81
+ def db_will_automatically_write? #:nodoc:
61
82
  false
62
83
  end
63
84
 
64
- # Returns the name that this field is referenced by in the MySQL table. By
65
- # default this is the same as the name; to override it, set
66
- # ObjectField#db_field_name.
67
- def name_for_sql
68
- db_field_name
69
- end
70
-
71
85
  def prev_value(pk_id) #:nodoc:
72
86
  prevObject = ObjectStore.get_object_store.get( @domain_class, pk_id )
73
87
  prevObject.send(name)
@@ -85,17 +99,17 @@ module Lafcadio
85
99
  end
86
100
 
87
101
  def verify(value, pk_id) #:nodoc:
88
- if value.nil? && not_null
102
+ if value.nil? && not_nil
89
103
  raise(
90
104
  FieldValueError,
91
105
  "#{ self.domain_class.name }##{ name } can not be nil.",
92
106
  caller
93
107
  )
94
108
  end
95
- verify_non_nil( value, pk_id ) if value
109
+ verify_non_nil_value( value, pk_id ) if value
96
110
  end
97
111
 
98
- def verify_non_nil( value, pk_id )
112
+ def verify_non_nil_value( value, pk_id ) #:nodoc:
99
113
  value_type = self.class.value_type
100
114
  unless value.class <= value_type
101
115
  raise(
@@ -115,7 +129,7 @@ module Lafcadio
115
129
 
116
130
  # A StringField is expected to contain a string value.
117
131
  class StringField < ObjectField
118
- def value_for_sql(value) #:nodoc:
132
+ def value_for_sql(value)
119
133
  if value
120
134
  value = value.gsub(/(\\?')/) { |m| m.length == 1 ? "''" : m }
121
135
  value = value.gsub(/\\/) { '\\\\' }
@@ -128,100 +142,103 @@ module Lafcadio
128
142
 
129
143
  # IntegerField represents an integer.
130
144
  class IntegerField < ObjectField
131
- def value_from_sql(string) #:nodoc:
145
+ def value_from_sql(string)
132
146
  value = super
133
147
  value ? value.to_i : nil
134
148
  end
135
149
  end
136
150
 
137
- # BlobField stores a string value and expects to store its value in a BLOB
151
+ # BinaryField stores a string value and expects to store its value in a BLOB
138
152
  # field in the database.
139
- class BlobField < ObjectField
140
- attr_accessor :size
141
-
142
- def self.value_type; String; end
153
+ class BinaryField < ObjectField
154
+ def self.value_type #:nodoc:
155
+ String
156
+ end
143
157
 
144
158
  def bind_write?; true; end #:nodoc:
145
159
 
146
- def value_for_sql(value); "?"; end #:nodoc:
160
+ def value_for_sql(value); "?"; end
147
161
  end
148
162
 
149
163
  # BooleanField represents a boolean value. By default, it assumes that the
150
- # table field represents True and False with the integers 1 and 0. There are
151
- # two different ways to change this default.
164
+ # table field represents +true+ and +false+ with the integers 1 and 0. There
165
+ # are two different ways to change this default.
152
166
  #
153
167
  # First, BooleanField includes a few enumerated defaults. Currently there are
154
168
  # only
155
- # * BooleanField::ENUMS_ONE_ZERO (the default, uses integers 1 and 0)
156
- # * BooleanField::ENUMS_CAPITAL_YES_NO (uses characters 'Y' and 'N')
157
- # In the XML class definition, this field would look like
158
- # <field name="field_name" class="BooleanField"
159
- # enum_type="ENUMS_CAPITAL_YES_NO"/>
160
- # If you're defining a field in Ruby, simply set BooleanField#enum_type to one
161
- # of the values.
162
- #
163
- # For more fine-grained specification you can pass specific values in. Use
164
- # this format for the XML class definition:
165
- # <field name="field_name" class="BooleanField">
166
- # <enums>
167
- # <enum key="true">yin</enum>
168
- # <enum key="false">tang</enum>
169
- # </enums>
170
- # </field>
171
- # If you're defining the field in Ruby, set BooleanField#enums to a hash.
172
- # myBooleanField.enums = { true => 'yin', false => 'yang' }
169
+ # * :one_zero (the default, uses integers 1 and 0)
170
+ # * :capital_yes_no (uses characters 'Y' and 'N')
171
+ # * :raw_true_false (uses unquoted values 'true' and 'false')
172
+ # In a class definition, this would look like
173
+ # class User < Lafcadio::DomainObject
174
+ # boolean 'administrator', { 'enum_type' => :capital_yes_no }
175
+ # end
173
176
  #
177
+ # For more fine-grained specification you can pass a hash with the keys
178
+ # +true+ and +false+ using the argument +enums+.
179
+ # class User < Lafcadio::DomainObject
180
+ # boolean 'administrator',
181
+ # { 'enums' => { true => 'yin', false => 'yang' } }
182
+ # end
174
183
  # +enums+ takes precedence over +enum_type+.
175
184
  class BooleanField < ObjectField
176
- ENUMS_ONE_ZERO = 0
177
- ENUMS_CAPITAL_YES_NO = 1
178
-
179
- attr_accessor :enum_type, :enums
185
+ attr_accessor :enum_type
186
+ attr_writer :enums
180
187
 
181
188
  def initialize( domain_class, name )
182
189
  super( domain_class, name )
183
- @enum_type = ENUMS_ONE_ZERO
184
190
  @enums = nil
185
191
  end
186
-
187
- def false_enum # :nodoc:
188
- get_enums[false]
192
+
193
+ def default_enum_type
194
+ case ObjectStore.db_type
195
+ when 'Mysql'
196
+ :one_zero
197
+ when 'Pg'
198
+ :raw_true_false
199
+ end
189
200
  end
190
201
 
191
- def get_enums( value = nil ) # :nodoc:
202
+ def enums( value = nil ) # :nodoc:
192
203
  if @enums
193
204
  @enums
194
- elsif @enum_type == ENUMS_ONE_ZERO
195
- if value.class == String
196
- { true => '1', false => '0' }
205
+ else
206
+ enum_type = ( @enum_type or default_enum_type )
207
+ case enum_type
208
+ when :one_zero
209
+ if value.is_a?( String )
210
+ { true => '1', false => '0' }
211
+ else
212
+ { true => 1, false => 0 }
213
+ end
214
+ when :capital_yes_no
215
+ { true => 'Y', false => 'N' }
216
+ when :raw_true_false
217
+ { true => true, false => false }
197
218
  else
198
- { true => 1, false => 0 }
219
+ raise MissingError
199
220
  end
200
- elsif @enum_type == ENUMS_CAPITAL_YES_NO
201
- { true => 'Y', false => 'N' }
202
- else
203
- raise MissingError
204
221
  end
205
222
  end
206
223
 
207
- def text_enum_type # :nodoc:
208
- @enums ? @enums[true].class == String : @enum_type == ENUMS_CAPITAL_YES_NO
224
+ def false_enum # :nodoc:
225
+ enums[false]
226
+ end
227
+
228
+ def text_enum_type? # :nodoc:
229
+ @enums ? @enums[true].class == String : @enum_type == :capital_yes_no
209
230
  end
210
231
 
211
232
  def true_enum( value = nil ) # :nodoc:
212
- get_enums( value )[true]
233
+ enums( value )[true]
213
234
  end
214
235
 
215
236
  def value_for_sql(value) # :nodoc:
216
- if value
217
- vfs = true_enum
218
- else
219
- vfs = false_enum
220
- end
221
- text_enum_type ? "'#{vfs}'" : vfs
237
+ vfs = value ? true_enum : false_enum
238
+ text_enum_type? ? "'#{ vfs }'" : vfs
222
239
  end
223
240
 
224
- def value_from_sql(value, lookupLink = true) # :nodoc:
241
+ def value_from_sql( value ) # :nodoc:
225
242
  value == true_enum( value )
226
243
  end
227
244
  end
@@ -240,7 +257,7 @@ module Lafcadio
240
257
  value ? "'#{value.to_s}'" : 'null'
241
258
  end
242
259
 
243
- def value_from_sql(dbiDate, lookupLink = true) # :nodoc:
260
+ def value_from_sql( dbiDate ) # :nodoc:
244
261
  begin
245
262
  dbiDate ? dbiDate.to_date : nil
246
263
  rescue ArgumentError
@@ -265,16 +282,41 @@ module Lafcadio
265
282
  end
266
283
  end
267
284
 
268
- def value_from_sql(dbi_value, lookupLink = true) # :nodoc:
285
+ def value_from_sql( dbi_value ) # :nodoc:
269
286
  dbi_value ? dbi_value.to_time : nil
270
287
  end
271
288
  end
272
289
 
273
- # A DomainObjectField is used to link from one domain class to another.
290
+ # A DomainObjectField is used to link from one domain class to another. To
291
+ # add such an association in a class definition, call
292
+ # DomainObject.domain_object:
293
+ # class Invoice < Lafcadio::DomainObject
294
+ # domain_object Client
295
+ # end
296
+ # By default, the field name is assumed to be the same as the class name,
297
+ # only lower-cased and camel-case.
298
+ # class LineItem < Lafcadio::DomainObject
299
+ # domain_object Product # field name 'product'
300
+ # domain_object CatalogOrder # field name 'catalog_order'
301
+ # end
302
+ # The field name can be explicitly set as the 2nd argument of
303
+ # DomainObject.domain_object.
304
+ # class Message < Lafcadio::DomainObject
305
+ # domain_object User, 'sender'
306
+ # domain_object User, 'recipient'
307
+ # end
308
+ # Setting +delete_cascade+ to true means that if the domain object being
309
+ # associated to is deleted, this domain object will also be deleted.
310
+ # class Invoice < Lafcadio::DomainObject
311
+ # domain_object Client, 'client', { 'delete_cascade' => true }
312
+ # end
313
+ # cli = Client.new( 'name' => 'big company' ).commit
314
+ # inv = Invoice.new( 'client' => cli ).commit
315
+ # cli.delete!
316
+ # inv_prime = Invoice[inv.pk_id] # => will raise DomainObjectNotFoundError
274
317
  class DomainObjectField < ObjectField
275
- def self.auto_name( linked_type )
276
- linked_type.name =~ /::/
277
- ( $' || linked_type.name ).camel_case_to_underscore
318
+ def self.auto_name( linked_type ) #:nodoc:
319
+ linked_type.basename.camel_case_to_underscore
278
320
  end
279
321
 
280
322
  def self.create_with_args( domain_class, parameters ) #:nodoc:
@@ -290,51 +332,46 @@ module Lafcadio
290
332
  instance
291
333
  end
292
334
 
293
- def self.instantiation_parameters( fieldElt ) #:nodoc:
335
+ def self.creation_parameters( fieldElt ) #:nodoc:
294
336
  parameters = super( fieldElt )
295
337
  linked_typeStr = fieldElt.attributes['linked_type']
296
- linked_type = Class.by_name linked_typeStr
297
- parameters['linked_type'] = linked_type
298
- parameters['delete_cascade'] = fieldElt.attributes['delete_cascade'] == 'y'
338
+ parameters['linked_type'] = Class.by_name linked_typeStr
339
+ parameters['delete_cascade'] =
340
+ ( fieldElt.attributes['delete_cascade'] == 'y' )
299
341
  parameters
300
342
  end
301
343
 
302
344
  attr_reader :linked_type
303
345
  attr_accessor :delete_cascade
304
346
 
305
- # [domain_class] The domain class that this field belongs to.
306
- # [linked_type] The domain class that this field points to.
307
- # [name] The name of this field.
308
- # [delete_cascade] If this is true, deleting the domain object that is
309
- # linked to will cause this domain object to be deleted
310
- # as well.
311
347
  def initialize( domain_class, linked_type, name = nil,
312
- delete_cascade = false )
348
+ delete_cascade = false ) #:nodoc:
313
349
  name = self.class.auto_name( linked_type ) unless name
314
350
  super( domain_class, name )
315
351
  ( @linked_type, @delete_cascade ) = linked_type, delete_cascade
316
352
  end
317
353
 
318
- def value_from_sql(string) #:nodoc:
319
- string != nil ? DomainObjectProxy.new(@linked_type, string.to_i) : nil
320
- end
321
-
322
354
  def value_for_sql(value) #:nodoc:
323
- if !value
355
+ if value.nil?
324
356
  "null"
325
357
  elsif value.pk_id
326
358
  value.pk_id
327
359
  else
328
- raise( DomainObjectInitError, "Can't commit #{name} without pk_id",
329
- caller )
360
+ raise(
361
+ DomainObjectInitError, "Can't commit #{name} without pk_id", caller
362
+ )
330
363
  end
331
364
  end
332
365
 
333
- def verify_non_nil(value, pk_id) #:nodoc:
366
+ def value_from_sql(string) #:nodoc:
367
+ string ? DomainObjectProxy.new(@linked_type, string.to_i) : nil
368
+ end
369
+
370
+ def verify_non_nil_value(value, pk_id) #:nodoc:
334
371
  super
335
372
  if @linked_type != @domain_class && pk_id
336
373
  subsetDomainObjectField = @linked_type.class_fields.find { |field|
337
- field.class == SubsetDomainObjectField && field.subset_field == @name
374
+ field.is_a?( SubsetDomainObjectField ) && field.subset_field == @name
338
375
  }
339
376
  if subsetDomainObjectField
340
377
  verify_subset_link_field( subsetDomainObjectField, pk_id )
@@ -342,11 +379,10 @@ module Lafcadio
342
379
  end
343
380
  end
344
381
 
345
- def verify_subset_link_field( subsetDomainObjectField, pk_id )
382
+ def verify_subset_link_field( subsetDomainObjectField, pk_id ) #:nodoc:
346
383
  begin
347
- prevObj = ObjectStore.get_object_store.get( domain_class, pk_id )
348
- prevObjLinkedTo = prevObj.send(name)
349
- possiblyMyObj = prevObjLinkedTo.send(subsetDomainObjectField.name)
384
+ prevObjLinkedTo = domain_class[pk_id].send(name)
385
+ possiblyMyObj = prevObjLinkedTo.send subsetDomainObjectField.name
350
386
  if possiblyMyObj && possiblyMyObj.pk_id == pk_id
351
387
  cantChangeMsg = "You can't change that."
352
388
  raise FieldValueError, cantChangeMsg, caller
@@ -369,7 +405,7 @@ module Lafcadio
369
405
  super( domain_class, name )
370
406
  end
371
407
 
372
- def verify_non_nil(value, pk_id) #:nodoc:
408
+ def verify_non_nil_value(value, pk_id) #:nodoc:
373
409
  super(value, pk_id)
374
410
  if !EmailField.valid_address(value)
375
411
  raise(
@@ -382,24 +418,17 @@ module Lafcadio
382
418
  end
383
419
 
384
420
  # EnumField represents an enumerated field that can only be set to one of a
385
- # set range of string values. To set the enumeration in the class definition
386
- # XML, use the following format:
387
- # <field name="flavor" class="EnumField">
388
- # <enums>
389
- # <enum>Vanilla</enum>
390
- # <enum>Chocolate</enum>
391
- # <enum>Lychee</enum>
392
- # </enums>
393
- # </field>
394
- # If you're defining the field in Ruby, you can simply pass in an array of
395
- # enums as the +enums+ argument.
396
- #
421
+ # set range of string values. To set the enumeration in the class definition,
422
+ # pass in an Array of values as +enums+.
423
+ # class IceCream < Lafcadio::DomainObject
424
+ # enum 'flavor', { 'enums' => %w( Vanilla Chocolate Lychee ) }
425
+ # end
397
426
  class EnumField < StringField
398
427
  def self.create_with_args( domain_class, parameters ) #:nodoc:
399
428
  self.new( domain_class, parameters['name'], parameters['enums'] )
400
429
  end
401
430
 
402
- def self.enum_queue_hash( fieldElt )
431
+ def self.enum_queue_hash( fieldElt ) #:nodoc:
403
432
  enumValues = []
404
433
  fieldElt.elements.each( 'enums/enum' ) { |enumElt|
405
434
  enumValues << enumElt.attributes['key']
@@ -408,7 +437,7 @@ module Lafcadio
408
437
  QueueHash.new( *enumValues )
409
438
  end
410
439
 
411
- def self.instantiation_parameters( fieldElt ) #:nodoc:
440
+ def self.creation_parameters( fieldElt ) #:nodoc:
412
441
  parameters = super( fieldElt )
413
442
  if fieldElt.elements['enums'][1].attributes['key']
414
443
  parameters['enums'] = enum_queue_hash( fieldElt )
@@ -423,11 +452,7 @@ module Lafcadio
423
452
 
424
453
  attr_reader :enums
425
454
 
426
- # [domain_class] The domain class that this field belongs to.
427
- # [name] The name of this domain class.
428
- # [enums] An array of Strings representing the possible choices for
429
- # this field.
430
- def initialize( domain_class, name, enums )
455
+ def initialize( domain_class, name, enums ) #:nodoc:
431
456
  super( domain_class, name )
432
457
  if enums.class == Array
433
458
  @enums = QueueHash.new_from_array enums
@@ -437,10 +462,10 @@ module Lafcadio
437
462
  end
438
463
 
439
464
  def value_for_sql(value) #:nodoc:
440
- value != '' ?(super(value)) : 'null'
465
+ value != '' ? (super(value)) : 'null'
441
466
  end
442
467
 
443
- def verify_non_nil( value, pk_id ) #:nodoc:
468
+ def verify_non_nil_value( value, pk_id ) #:nodoc:
444
469
  super
445
470
  if @enums[value].nil?
446
471
  key_str = '[ ' +
@@ -457,10 +482,6 @@ module Lafcadio
457
482
 
458
483
  # FloatField represents a decimal value.
459
484
  class FloatField < ObjectField
460
- def self.create_with_args( domain_class, parameters ) #:nodoc:
461
- self.new( domain_class, parameters['name'] )
462
- end
463
-
464
485
  def self.value_type #:nodoc:
465
486
  Numeric
466
487
  end
@@ -487,16 +508,16 @@ module Lafcadio
487
508
  end
488
509
  end
489
510
 
490
- class PrimaryKeyField < IntegerField
511
+ class PrimaryKeyField < IntegerField #:nodoc:
491
512
  def initialize( domain_class )
492
513
  super( domain_class, 'pk_id' )
493
- @not_null = false
514
+ @not_nil = false
494
515
  end
495
516
  end
496
517
 
497
- # A StateField is a specialized subclass of EnumField; its possible values are
498
- # any of the 50 states of the United States, stored as each state's two-letter
499
- # postal code.
518
+ # A StateField is a specialized subclass of EnumField; its possible value
519
+ # are any of the 50 states of the United States, stored as each state's
520
+ # two-letter postal code.
500
521
  class StateField < EnumField
501
522
  def initialize( domain_class, name = "state" )
502
523
  super( domain_class, name, USCommerce::UsStates.states )
@@ -509,7 +530,7 @@ module Lafcadio
509
530
  parameters['subset_field'], parameters['name'] )
510
531
  end
511
532
 
512
- def self.instantiation_parameters( fieldElt )
533
+ def self.creation_parameters( fieldElt )
513
534
  parameters = super( fieldElt )
514
535
  parameters['subset_field'] = fieldElt.attributes['subset_field']
515
536
  parameters
@@ -554,10 +575,10 @@ module Lafcadio
554
575
  class TimeStampField < DateTimeField #:nodoc:
555
576
  def initialize( domain_class, name = 'timeStamp' )
556
577
  super( domain_class, name )
557
- @not_null = false
578
+ @not_nil = false
558
579
  end
559
580
 
560
- def db_will_automatically_write
581
+ def db_will_automatically_write?
561
582
  true
562
583
  end
563
584
  end