lafcadio 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,8 +3,11 @@ require 'lafcadio/objectField'
3
3
  module Lafcadio
4
4
  class CreateTableStatement #:nodoc:
5
5
  @@simple_field_clauses = {
6
- FloatField => 'float', DateField => 'date', BooleanField => 'bool',
7
- TimeStampField => 'timestamp', DateTimeField => 'datetime'
6
+ BooleanField => 'bool', BlobField => 'blob', DateField => 'date',
7
+ DomainObjectField => 'int', FloatField => 'float',
8
+ DateTimeField => 'datetime', IntegerField => 'int',
9
+ StringField => 'varchar(255)', TextListField => 'varchar(255)',
10
+ TimeStampField => 'timestamp'
8
11
  }
9
12
 
10
13
  def initialize( domain_class )
@@ -15,15 +18,16 @@ module Lafcadio
15
18
  definitionTerms = []
16
19
  definitionTerms << field.db_field_name
17
20
  definitionTerms << type_clause( field )
18
- definitionTerms << 'not null' if field.not_null
21
+ definitionTerms << 'not null' if field.not_nil
19
22
  definitionTerms.join( ' ' )
20
23
  end
21
24
 
22
25
  def to_sql
23
26
  createDefinitions = []
24
- createDefinitions << "#{ @domain_class.sql_primary_key_name } " +
25
- "int not null auto_increment"
26
- createDefinitions << "primary key (#{ @domain_class.sql_primary_key_name })"
27
+ createDefinitions <<
28
+ "#{ @domain_class.sql_primary_key_name } int not null auto_increment"
29
+ createDefinitions <<
30
+ "primary key (#{ @domain_class.sql_primary_key_name })"
27
31
  @domain_class.class_fields.each { |field|
28
32
  createDefinitions << definition_terms( field )
29
33
  }
@@ -42,14 +46,6 @@ module Lafcadio
42
46
  "'#{ enumValue }'"
43
47
  }
44
48
  "enum( #{ singleQuotedValues.join( ', ' ) } )"
45
- elsif ( field.class <= StringField || field.class <= TextListField )
46
- 'varchar(255)'
47
- elsif ( field.class <= DomainObjectField || field.class <= IntegerField )
48
- 'int'
49
- elsif ( field.class <= FloatField )
50
- 'float(10, 2)'
51
- elsif ( field.class <= BlobField )
52
- 'blob'
53
49
  end
54
50
  end
55
51
  end
@@ -4,7 +4,7 @@ module Lafcadio
4
4
  class CreateTableStatement #:nodoc:
5
5
  @@simple_field_clauses = {
6
6
  FloatField => 'float', DateField => 'date', BooleanField => 'bool',
7
- TimeStampField => 'timestamp', TimeField => 'datetime'
7
+ TimeStampField => 'timestamp', DateTimeField => 'datetime'
8
8
  }
9
9
 
10
10
  def initialize( domain_class )
@@ -21,28 +21,37 @@ class LafcadioTestCase < Test::Unit::TestCase
21
21
  )
22
22
  end
23
23
 
24
- def default_test; end
24
+ # Asserts that for each key-value pair in +att_values+, sending the key to
25
+ # +object+ will return the value.
26
+ # u = User.new( 'fname' => 'Francis', 'lname' => 'Hwang' )
27
+ # assert_attributes( u, { 'fname' => 'Francis', 'lname' => 'Hwang' } )
28
+ def assert_attributes( object, att_values )
29
+ att_values.each { |method, expected|
30
+ assert_equal( expected, object.send( method ), method.to_s )
31
+ }
32
+ end
33
+
34
+ def default_test #:nodoc:
35
+ end
25
36
  end
26
37
 
27
38
  module Lafcadio
28
- def BooleanField.mock_value; true; end
39
+ def BooleanField.mock_value #:nodoc:
40
+ true
41
+ end
29
42
 
30
- def DateField.mock_value; Date.today; end
43
+ def DateField.mock_value #:nodoc:
44
+ Date.today
45
+ end
31
46
 
32
- def DateTimeField.mock_value; Time.now; end
47
+ def DateTimeField.mock_value #:nodoc:
48
+ Time.now
49
+ end
33
50
 
34
- module DomainMock
51
+ module DomainMock #:nodoc:
35
52
  Version = '0.1.0'
36
53
 
37
54
  def self.included( includer )
38
- def includer.setup_procs
39
- unless defined? @@all_setup_procs
40
- @@all_setup_procs = Hash.new { |hash, domain_class|
41
- hash[domain_class] = []
42
- }
43
- end
44
- @@all_setup_procs[self]
45
- end
46
55
  def includer.setup_mock_dobjs( *domain_classes_or_symbol_names )
47
56
  domain_classes = DomainClassSymbolMapper.new
48
57
  domain_classes_or_symbol_names.each { |domain_class_or_symbol_name|
@@ -58,6 +67,15 @@ module Lafcadio
58
67
  setup_procs << proc
59
68
  }
60
69
  end
70
+
71
+ def includer.setup_procs
72
+ unless defined? @@all_setup_procs
73
+ @@all_setup_procs = Hash.new { |hash, domain_class|
74
+ hash[domain_class] = []
75
+ }
76
+ end
77
+ @@all_setup_procs[self]
78
+ end
61
79
  end
62
80
 
63
81
  def commit_domain_object( domain_class, non_default_values = {} )
@@ -82,7 +100,7 @@ module Lafcadio
82
100
  self.class.setup_procs.each { |proc| proc.call( self ) }
83
101
  end
84
102
 
85
- class DomainClassSymbolMapper < Hash
103
+ class DomainClassSymbolMapper < Hash #:nodoc:
86
104
  def initialize; @last_domain_class = nil; end
87
105
 
88
106
  def default_symbol_name( domain_class )
@@ -119,26 +137,73 @@ module Lafcadio
119
137
  hash[a_class] = default_args
120
138
  }
121
139
 
122
- def self.commit_mock( args, caller = nil )
140
+ def self.commit_mock( args, caller = nil ) #:nodoc:
123
141
  dobj = self.new( args )
124
142
  link_fields = all_fields.select { |field| field.is_a? DomainObjectField }
125
143
  link_fields.each do |field|
126
144
  val = dobj.send( field.name )
127
- if val and val.pk_id == 1
128
- linked_type = field.linked_type
129
- begin
130
- ObjectStore.get_object_store.get( linked_type, 1 )
131
- rescue DomainObjectNotFoundError
132
- unless linked_type == caller
133
- linked_type.send( 'default_mock', self )
134
- end
135
- end
136
- end
145
+ maybe_call_default_mock( field, caller ) if ( val and val.pk_id == 1 )
137
146
  end
138
147
  dobj.commit
139
148
  dobj
140
149
  end
141
150
 
151
+ # Commits and returns a custom mock object of the given domain class. All
152
+ # the field values are set to defaults, except for the fields passed in
153
+ # through +custom_args+. This mock object will have a +pk_id+ greater than
154
+ # 1, and each successive call to DomainObject.custom_mock will return an
155
+ # object with a unique +pk_id+.
156
+ #
157
+ # This class method is only visible if you include
158
+ # <tt>lafcadio/test.rb</tt>.
159
+ #
160
+ # class User < Lafcadio::DomainObject
161
+ # string :fname, :lname, :email
162
+ # end
163
+ # u1 = User.custom_mock
164
+ # u1.fname # => 'test text'
165
+ # u1.lname # => 'test text'
166
+ # u1.email # => 'test text'
167
+ # u1.pk_id # => probably 2, guaranteed to be greater than 1
168
+ # u2 = User.custom_mock( 'fname' => 'Francis', 'lname' => 'Hwang' )
169
+ # u2.fname # => 'Francis'
170
+ # u2.lname # => 'Hwang'
171
+ # u2.email # => 'test text'
172
+ # u2.pk_id # => probably 3, guaranteed to not be u1.pk_id and to be
173
+ # # greater than 1
174
+ def self.custom_mock( custom_args = nil )
175
+ dobj_args = default_args
176
+ object_store = ObjectStore.get_object_store
177
+ dbb = object_store.db_bridge
178
+ dbb.set_next_pk_id( self, 2 ) if dbb.next_pk_id( self ) == 1
179
+ dobj_args['pk_id'] = nil
180
+ if custom_args.is_a? Hash
181
+ custom_args.each do |k, v| dobj_args[k.to_s] = v; end
182
+ end
183
+ commit_mock( dobj_args )
184
+ end
185
+
186
+ # Returns a hash of default arguments for mock instances of this domain
187
+ # class. DomainObject.default_mock uses exactly these arguments to create
188
+ # the default mock for a given domain class, and DomainObject.custom_mock
189
+ # overrides some of the field arguments based on its custom arguments.
190
+ #
191
+ # By default this will retrieve simple values based on the field type:
192
+ # * BooleanField: +true+
193
+ # * DateField: Date.today
194
+ # * DateTimeField: Time.now
195
+ # * DomainObjectField: The instance of the domain class with +pk_id+ 1
196
+ # * EmailField: "john.doe@email.com"
197
+ # * FloatField: 0.0
198
+ # * IntegerField: 1
199
+ # * StringField: "test text"
200
+ # * TextListField: [ 'a', 'b', 'c' ]
201
+ #
202
+ # You can override this method, if you like. However, it will probably be
203
+ # simpler just to call DomainObject.mock_value.
204
+ #
205
+ # This class method is only visible if you include
206
+ # <tt>lafcadio/test.rb</tt>.
142
207
  def self.default_args
143
208
  default_args = {}
144
209
  @@default_arg_directives[self].each do |name, value_or_proc|
@@ -151,23 +216,29 @@ module Lafcadio
151
216
  default_args
152
217
  end
153
218
 
154
- def self.custom_mock( custom_args = nil )
155
- dobj_args = default_args
156
- object_store = ObjectStore.get_object_store
157
- dbb = object_store.get_db_bridge
158
- dbb.set_next_pk_id( self, 2 ) if dbb.next_pk_id( self ) == 1
159
- dobj_args['pk_id'] = nil
160
- dobj_args = dobj_args.merge( custom_args ) if custom_args.is_a?( Hash )
161
- commit_mock( dobj_args )
162
- end
163
-
219
+ # Commits and returns a mock object of the given domain class. All
220
+ # the field values are set to defaults. This mock object will have a
221
+ # +pk_id+ of 1. Successive calls to DomainObject.default_mock will always
222
+ # return the same mock object.
223
+ #
224
+ # This class method is only visible if you include
225
+ # <tt>lafcadio/test.rb</tt>.
226
+ #
227
+ # class User < Lafcadio::DomainObject
228
+ # string :fname, :lname, :email
229
+ # end
230
+ # u1 = User.default_mock
231
+ # u1.fname # => 'test text'
232
+ # u1.lname # => 'test text'
233
+ # u1.email # => 'test text'
234
+ # u1.pk_id # => 1
164
235
  def self.default_mock( calling_class = nil )
165
236
  if @@default_mock_available[self]
166
237
  begin
167
238
  dobj = ObjectStore.get_object_store.get( self, 1 )
168
239
  dobj
169
240
  rescue DomainObjectNotFoundError
170
- dbb = ObjectStore.get_object_store.get_db_bridge
241
+ dbb = ObjectStore.get_object_store.db_bridge
171
242
  dbb.set_next_pk_id( self, 1 ) if dbb.next_pk_id( self ) > 1
172
243
  commit_mock( default_args, calling_class )
173
244
  end
@@ -176,68 +247,96 @@ module Lafcadio
176
247
  end
177
248
  end
178
249
 
179
- def self.default_mock_available( is_avail )
250
+ def self.default_mock_available( is_avail ) #:nodoc:
180
251
  @@default_mock_available[self] = is_avail
181
252
  end
253
+
254
+ def self.maybe_call_default_mock( field, caller ) #:nodoc:
255
+ linked_type = field.linked_type
256
+ begin
257
+ ObjectStore.get_object_store.get( linked_type, 1 )
258
+ rescue DomainObjectNotFoundError
259
+ unless linked_type == caller
260
+ linked_type.send( 'default_mock', self )
261
+ end
262
+ end
263
+ end
182
264
 
265
+ # Sets the mock value for the given field. These mock values are used in
266
+ # DomainObject.default_mock and DomainObject.custom_mock
267
+ #
268
+ # This class method is only visible if you include
269
+ # <tt>lafcadio/test.rb</tt>.
270
+ #
271
+ # class User < Lafcadio::DomainObject
272
+ # string :fname, :lname, :email
273
+ # end
274
+ # User.mock_value :fname, 'Bill'
275
+ # User.mock_value :lname, 'Smith'
276
+ # u1 = User.default_mock
277
+ # u1.fname # => 'Bill'
278
+ # u1.lname # => 'Smith'
279
+ # u1.email # => 'test text'
280
+ # u1.pk_id # => 1
183
281
  def self.mock_value( field_sym, value )
184
282
  @@default_arg_directives[self][field_sym.id2name] = value
185
283
  end
186
284
 
285
+ # Sets the mock value for the fields in +hash+. These mock values are used
286
+ # in DomainObject.default_mock and DomainObject.custom_mock
287
+ #
288
+ # This class method is only visible if you include
289
+ # <tt>lafcadio/test.rb</tt>.
290
+ #
291
+ # class User < Lafcadio::DomainObject
292
+ # string :fname, :lname, :email
293
+ # end
294
+ # User.mock_values { :fname => 'Bill', :lname => 'Smith' }
295
+ # u1 = User.default_mock
296
+ # u1.fname # => 'Bill'
297
+ # u1.lname # => 'Smith'
298
+ # u1.email # => 'test text'
299
+ # u1.pk_id # => 1
187
300
  def self.mock_values( hash )
188
301
  hash.each do |field_sym, value| mock_value( field_sym, value ); end
189
302
  end
190
303
  end
191
304
 
192
305
  class DomainObjectField < ObjectField
193
- def default_mock_value; DomainObjectProxy.new( linked_type, 1 ); end
306
+ def default_mock_value #:nodoc:
307
+ DomainObjectProxy.new( linked_type, 1 )
308
+ end
194
309
  end
195
310
 
196
- def EmailField.mock_value; 'john.doe@email.com'; end
197
-
198
- def FloatField.mock_value; 0.0; end
199
-
200
- def IntegerField.mock_value; 1; end
311
+ def EmailField.mock_value #:nodoc:
312
+ 'john.doe@email.com'
313
+ end
201
314
 
202
- class MockDbBridge
203
- unless instance_methods.include?( 'orig_get_pk_id_before_committing' )
204
- alias_method(
205
- :orig_get_pk_id_before_committing, :get_pk_id_before_committing
206
- )
207
-
208
- def get_pk_id_before_committing( domain_object )
209
- @next_pk_ids = {} unless @next_pk_ids
210
- orig_pk_id = orig_get_pk_id_before_committing domain_object
211
- if (next_pk_id = @next_pk_ids[domain_object.domain_class])
212
- @last_pk_id_inserted = next_pk_id
213
- @next_pk_ids[domain_object.domain_class] = nil
214
- next_pk_id
215
- else
216
- orig_pk_id
217
- end
218
- end
219
- end
220
-
221
- def next_pk_id( domain_class )
222
- dobjs = get_objects_by_domain_class( domain_class ).values
223
- dobjs.inject( 0 ) { |memo, obj| memo > obj.pk_id ? memo : obj.pk_id } + 1
224
- end
315
+ def FloatField.mock_value #:nodoc:
316
+ 0.0
317
+ end
225
318
 
226
- def set_next_pk_id( domain_class, npi )
227
- @next_pk_ids = {} unless @next_pk_ids
228
- @next_pk_ids[ domain_class ] = npi
229
- end
319
+ def IntegerField.mock_value #:nodoc:
320
+ 1
230
321
  end
231
-
322
+
232
323
  class ObjectField
233
324
  attr_writer :mock_value
234
325
 
235
- def default_mock_value; self.class.mock_value; end
326
+ def default_mock_value #:nodoc:
327
+ self.class.mock_value
328
+ end
236
329
  end
237
330
 
238
- def PrimaryKeyField.mock_value; nil; end
331
+ def PrimaryKeyField.mock_value #:nodoc:
332
+ nil
333
+ end
239
334
 
240
- def StringField.mock_value; 'test text'; end
335
+ def StringField.mock_value #:nodoc:
336
+ 'test text'
337
+ end
241
338
 
242
- def TextListField.mock_value; %w( a b c ); end
339
+ def TextListField.mock_value #:nodoc:
340
+ %w( a b c )
341
+ end
243
342
  end
@@ -23,3 +23,194 @@ class LafcadioTestCase < Test::Unit::TestCase
23
23
 
24
24
  def default_test; end
25
25
  end
26
+
27
+ module Lafcadio
28
+ def BooleanField.mock_value; true; end
29
+
30
+ def DateField.mock_value; Date.today; end
31
+
32
+ def DateTimeField.mock_value; Time.now; end
33
+
34
+ module DomainMock
35
+ Version = '0.1.0'
36
+
37
+ def self.included( includer )
38
+ def includer.setup_mock_dobjs( *domain_classes_or_symbol_names )
39
+ domain_classes = DomainClassSymbolMapper.new
40
+ domain_classes_or_symbol_names.each { |domain_class_or_symbol_name|
41
+ domain_classes.process( domain_class_or_symbol_name )
42
+ }
43
+ domain_classes.finish
44
+ domain_classes.each { |my_domain_class, my_symbol_name|
45
+ proc = Proc.new { |test_case|
46
+ test_case.instance_variable_set(
47
+ my_symbol_name, my_domain_class.default_mock
48
+ )
49
+ }
50
+ setup_procs << proc
51
+ }
52
+ end
53
+
54
+ def includer.setup_procs
55
+ unless defined? @@all_setup_procs
56
+ @@all_setup_procs = Hash.new { |hash, domain_class|
57
+ hash[domain_class] = []
58
+ }
59
+ end
60
+ @@all_setup_procs[self]
61
+ end
62
+ end
63
+
64
+ def commit_domain_object( domain_class, non_default_values = {} )
65
+ self.class.mock_domain_files.each do |file| require file; end
66
+ dobj = domain_class.send( :custom_mock, non_default_values )
67
+ dobj.commit
68
+ end
69
+
70
+ def method_missing( sym, *args )
71
+ method_name = sym.id2name
72
+ if method_name =~ /^custom_mock_(.*)/
73
+ domain_class = Module.by_name( $1.underscore_to_camel_case )
74
+ commit_domain_object( domain_class, *args )
75
+ elsif method_name =~ /^default_mock_(.*)/
76
+ Module.by_name( $1.underscore_to_camel_case ).default_mock
77
+ else
78
+ super
79
+ end
80
+ end
81
+
82
+ def setup
83
+ self.class.setup_procs.each { |proc| proc.call( self ) }
84
+ end
85
+
86
+ class DomainClassSymbolMapper < Hash
87
+ def initialize; @last_domain_class = nil; end
88
+
89
+ def default_symbol_name( domain_class )
90
+ "@#{ domain_class.name.camel_case_to_underscore }"
91
+ end
92
+
93
+ def finish
94
+ if @last_domain_class
95
+ self[@last_domain_class] = default_symbol_name( @last_domain_class )
96
+ end
97
+ end
98
+
99
+ def process( domain_class_or_symbol_name )
100
+ if domain_class_or_symbol_name.class == Class
101
+ if @last_domain_class
102
+ self[@last_domain_class] = default_symbol_name( @last_domain_class )
103
+ end
104
+ @last_domain_class = domain_class_or_symbol_name
105
+ else
106
+ self[@last_domain_class] = domain_class_or_symbol_name
107
+ @last_domain_class = nil
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ class DomainObject
114
+ @@default_mock_available = Hash.new true
115
+ @@default_arg_directives = Hash.new { |hash, a_class|
116
+ default_args = {}
117
+ a_class.all_fields.each do |field|
118
+ default_args[field.name] = field.default_mock_value
119
+ end
120
+ hash[a_class] = default_args
121
+ }
122
+
123
+ def self.commit_mock( args, caller = nil )
124
+ dobj = self.new( args )
125
+ link_fields = all_fields.select { |field| field.is_a? DomainObjectField }
126
+ link_fields.each do |field|
127
+ val = dobj.send( field.name )
128
+ maybe_call_default_mock( field, caller ) if ( val and val.pk_id == 1 )
129
+ end
130
+ dobj.commit
131
+ dobj
132
+ end
133
+
134
+ def self.custom_mock( custom_args = nil )
135
+ dobj_args = default_args
136
+ object_store = ObjectStore.get_object_store
137
+ dbb = object_store.get_db_bridge
138
+ dbb.set_next_pk_id( self, 2 ) if dbb.next_pk_id( self ) == 1
139
+ dobj_args['pk_id'] = nil
140
+ dobj_args = dobj_args.merge( custom_args ) if custom_args.is_a?( Hash )
141
+ commit_mock( dobj_args )
142
+ end
143
+
144
+ def self.default_args
145
+ default_args = {}
146
+ @@default_arg_directives[self].each do |name, value_or_proc|
147
+ if value_or_proc.is_a? Proc
148
+ default_args[name] = value_or_proc.call
149
+ else
150
+ default_args[name] = value_or_proc
151
+ end
152
+ end
153
+ default_args
154
+ end
155
+
156
+ def self.default_mock( calling_class = nil )
157
+ if @@default_mock_available[self]
158
+ begin
159
+ dobj = ObjectStore.get_object_store.get( self, 1 )
160
+ dobj
161
+ rescue DomainObjectNotFoundError
162
+ dbb = ObjectStore.get_object_store.get_db_bridge
163
+ dbb.set_next_pk_id( self, 1 ) if dbb.next_pk_id( self ) > 1
164
+ commit_mock( default_args, calling_class )
165
+ end
166
+ else
167
+ raise( TypeError, self.name + ".default_mock not allowed", caller )
168
+ end
169
+ end
170
+
171
+ def self.default_mock_available( is_avail )
172
+ @@default_mock_available[self] = is_avail
173
+ end
174
+
175
+ def self.maybe_call_default_mock( field, caller )
176
+ linked_type = field.linked_type
177
+ begin
178
+ ObjectStore.get_object_store.get( linked_type, 1 )
179
+ rescue DomainObjectNotFoundError
180
+ unless linked_type == caller
181
+ linked_type.send( 'default_mock', self )
182
+ end
183
+ end
184
+ end
185
+
186
+ def self.mock_value( field_sym, value )
187
+ @@default_arg_directives[self][field_sym.id2name] = value
188
+ end
189
+
190
+ def self.mock_values( hash )
191
+ hash.each do |field_sym, value| mock_value( field_sym, value ); end
192
+ end
193
+ end
194
+
195
+ class DomainObjectField < ObjectField
196
+ def default_mock_value; DomainObjectProxy.new( linked_type, 1 ); end
197
+ end
198
+
199
+ def EmailField.mock_value; 'john.doe@email.com'; end
200
+
201
+ def FloatField.mock_value; 0.0; end
202
+
203
+ def IntegerField.mock_value; 1; end
204
+
205
+ class ObjectField
206
+ attr_writer :mock_value
207
+
208
+ def default_mock_value; self.class.mock_value; end
209
+ end
210
+
211
+ def PrimaryKeyField.mock_value; nil; end
212
+
213
+ def StringField.mock_value; 'test text'; end
214
+
215
+ def TextListField.mock_value; %w( a b c ); end
216
+ end