dao 4.2.1 → 4.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/README +103 -63
  2. data/Rakefile +3 -3
  3. data/dao.gemspec +27 -16
  4. data/lib/dao.rb +17 -17
  5. data/lib/dao/active_record.rb +1 -0
  6. data/lib/dao/api.rb +2 -1
  7. data/lib/dao/api/{endpoints.rb → call.rb} +1 -0
  8. data/lib/dao/api/context.rb +2 -0
  9. data/lib/dao/api/dsl.rb +1 -0
  10. data/lib/dao/api/initializers.rb +1 -0
  11. data/lib/dao/api/modes.rb +1 -0
  12. data/lib/dao/api/routes.rb +1 -0
  13. data/lib/dao/blankslate.rb +1 -0
  14. data/lib/dao/conducer.rb +315 -274
  15. data/lib/dao/conducer/active_model.rb +98 -0
  16. data/lib/dao/conducer/attributes.rb +1 -0
  17. data/lib/dao/conducer/autocrud.rb +58 -0
  18. data/lib/dao/conducer/callback_support.rb +20 -0
  19. data/lib/dao/conducer/collection.rb +45 -0
  20. data/lib/dao/conducer/controller_support.rb +104 -0
  21. data/lib/dao/conducer/nav_support.rb +9 -0
  22. data/lib/dao/conducer/view_support.rb +16 -0
  23. data/lib/dao/data.rb +2 -1
  24. data/lib/dao/db.rb +2 -0
  25. data/lib/dao/endpoint.rb +1 -0
  26. data/lib/dao/engine.rb +1 -0
  27. data/lib/dao/errors.rb +109 -99
  28. data/lib/dao/exceptions.rb +1 -0
  29. data/lib/dao/extractor.rb +1 -0
  30. data/lib/dao/form.rb +175 -20
  31. data/lib/dao/instance_exec.rb +1 -0
  32. data/lib/dao/mode.rb +1 -0
  33. data/lib/dao/mongo_mapper.rb +1 -0
  34. data/lib/dao/name.rb +1 -0
  35. data/lib/dao/params.rb +2 -1
  36. data/lib/dao/path.rb +1 -0
  37. data/lib/dao/path_map.rb +24 -0
  38. data/lib/dao/rack.rb +1 -0
  39. data/lib/dao/rack/middleware.rb +1 -0
  40. data/lib/dao/rack/middleware/params_parser.rb +1 -0
  41. data/lib/dao/rails.rb +12 -32
  42. data/lib/dao/rails/lib/generators/dao/USAGE +2 -2
  43. data/lib/dao/rails/lib/generators/dao/dao_generator.rb +8 -27
  44. data/lib/dao/rails/lib/generators/dao/templates/api.rb +2 -1
  45. data/lib/dao/rails/lib/generators/dao/templates/api_controller.rb +22 -20
  46. data/lib/dao/rails/lib/generators/dao/templates/conducer.rb +49 -43
  47. data/lib/dao/rails/lib/generators/dao/templates/dao.css +26 -25
  48. data/lib/dao/rails/lib/generators/dao/templates/dao.js +3 -0
  49. data/lib/dao/rails/lib/generators/dao/templates/dao_helper.rb +58 -45
  50. data/lib/dao/result.rb +50 -1
  51. data/lib/dao/route.rb +1 -0
  52. data/lib/dao/slug.rb +12 -36
  53. data/lib/dao/status.rb +91 -7
  54. data/lib/dao/stdext.rb +1 -0
  55. data/lib/dao/support.rb +90 -80
  56. data/lib/dao/upload.rb +396 -0
  57. data/lib/dao/validations.rb +23 -5
  58. data/lib/dao/validations/callback.rb +5 -0
  59. data/lib/dao/validations/common.rb +100 -3
  60. data/lib/dao/validations/instance.rb +17 -0
  61. data/lib/dao/validations/validator.rb +192 -91
  62. data/test/active_model_conducer_lint_test.rb +1 -0
  63. data/test/api_test.rb +15 -0
  64. data/test/conducer_test.rb +608 -90
  65. data/test/data/han-solo.jpg +0 -0
  66. data/test/form_test.rb +1 -0
  67. data/test/helper.rb +1 -0
  68. data/test/leak.rb +1 -0
  69. data/test/support_test.rb +4 -1
  70. data/test/testing.rb +1 -0
  71. data/test/validations_test.rb +176 -30
  72. metadata +120 -131
  73. data/b.rb +0 -38
  74. data/lib/dao/conducer/crud.rb +0 -70
  75. data/lib/dao/current.rb +0 -66
  76. data/lib/dao/image_cache.rb +0 -193
  77. data/lib/dao/rails/lib/generators/dao/templates/conducer_controller.rb +0 -79
  78. data/test/db.yml +0 -9
@@ -1,3 +1,4 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  class LintTest < ActiveModel::TestCase
2
3
  include ActiveModel::Lint::Tests
3
4
 
data/test/api_test.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # -*- encoding : utf-8 -*-
1
2
 
2
3
 
3
4
  Testing Dao do
@@ -132,6 +133,20 @@ Testing Dao do
132
133
  end
133
134
  end
134
135
 
136
+ ## context
137
+ #
138
+ testing 'that calls have a shortcut to status' do
139
+ api_class =
140
+ assert{
141
+ Dao.api do
142
+ call(:foo){ status! 420 }
143
+ end
144
+ }
145
+ api = assert{ api_class.new }
146
+ result = assert{ api.call(:foo) }
147
+ assert{ result.status =~ 420 }
148
+ end
149
+
135
150
  ## results
136
151
  #
137
152
  testing 'that results can be created' do
@@ -1,52 +1,329 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+
1
4
  Testing Dao::Conducer do
2
5
  ##
3
6
  #
4
- testing 'that base classes can be constructed and named' do
5
- new_foo_conducer_class()
7
+ context :teh_ctor do
8
+ #
9
+ testing 'conducers have a POLS .new method' do
10
+ [
11
+ {:key => :val, :array => [0,1,2]},
12
+ {}
13
+ ].each do |attributes|
14
+ c = new_conducer(attributes)
15
+ assert{ c.attributes =~ attributes }
16
+ end
17
+ end
18
+
19
+ #
20
+ testing 'models passed to .new are automatically tracked' do
21
+ user = User.new
22
+ post = Post.new
23
+ comment = Comment.new
24
+ params = {}
25
+
26
+ args = [comment, post, user, params]
27
+
28
+ c = new_conducer(*args)
29
+
30
+ assert{ c.models == [comment, post, user] }
31
+ assert{ c.model == comment }
32
+ assert{ c.model == c.conduces }
33
+
34
+ assert{ c.conduces(post) }
35
+ assert{ c.models == [post, comment, user] }
36
+ assert{ c.model == post }
37
+ assert{ c.model == c.conduces }
38
+ end
6
39
  end
7
40
 
8
41
  ##
9
42
  #
10
- testing 'that basic validations/errors work' do
11
- c =
12
- assert{
13
- new_foo_conducer_class do
14
- validates_presence_of :bar
15
- validates_presence_of :foo, :bar
43
+ context :teh_default_initialize do
44
+ #
45
+ testing 'that the last mode determines the lifecycle state when a models are passed in' do
46
+ user = User.new
47
+ post = Post.new
48
+ comment = Comment.new
49
+ params = {}
50
+
51
+ args = [comment, post, user, params]
52
+
53
+ c = new_conducer(*args)
54
+
55
+ %w( new_record? persisted? destroyed? ).each do |state|
56
+ assert{ comment.send(state) == c.send(state) }
57
+ end
58
+
59
+ comment.new_record = false
60
+ comment.persisted = true
61
+ assert{ c.new_record? == false }
62
+ assert{ c.persisted == true }
63
+ end
64
+
65
+ #
66
+ testing 'that passed in models/params are sanely ker-sploded onto the attributes' do
67
+ user = User.new :k => 1
68
+ post = Post.new :k => 2
69
+ comment = Comment.new :k => 3, :x => 4
70
+ params = {:x => 5}
71
+
72
+ args = [comment, post, user, params]
73
+
74
+ c = new_conducer(*args)
75
+
76
+ assert{ c.attributes[:user] =~ {:k => 1} }
77
+ assert{ c.instance_variable_get('@user') == user }
78
+
79
+ assert{ c.attributes[:post] =~ {:k => 2} }
80
+ assert{ c.instance_variable_get('@post') == post }
81
+
82
+ expected = Map.new
83
+ expected.update :user => user.attributes
84
+ expected.update :post => post.attributes
85
+ expected.update comment.attributes
86
+ expected.update params
87
+
88
+ assert{ c.attributes =~ expected }
89
+ assert{ c.instance_variable_get('@comment') == comment }
90
+ end
91
+
92
+ #
93
+ testing 'that .new specialises based on current action' do
94
+ conducer_class =
95
+ new_conducer_class do
96
+ def initialize_for_new
97
+ attributes.update(:new => Time.now)
98
+ end
99
+ def initialize_for_create
100
+ attributes.update(:create => Time.now)
101
+ end
102
+ def initialize_for_edit
103
+ attributes.update(:edit => Time.now)
104
+ end
16
105
  end
17
- }
106
+
107
+ post = Post.new
18
108
 
19
- o = assert{ c.new }
20
- assert{ !o.valid? }
109
+ %w( new create edit ).each do |action|
110
+ c = conducer_class.for(action, post)
111
+ assert{ c.action == action }
112
+ assert{ c.respond_to?("initialize_for_#{ action }") }
113
+ assert{ c.attributes[action].is_a?(Time) }
114
+ assert{ c.attributes.size == 1 }
115
+ end
116
+ end
21
117
 
22
- assert{ !Array(o.errors.get(:bar)).empty? }
23
- assert{ !Array(o.errors.get(:foo, :bar)).empty? }
118
+ #
119
+ testing 'that conducers can build a highly specialized .new method based on action' do
120
+ c =
121
+ new_conducer_class do
122
+ def initialize(a, b, c, params)
123
+ @a, @b, @c = a, b, c
24
124
 
25
- o.attributes.set :foo, :bar, 42
26
- assert{ !o.valid? }
125
+ update_attributes(
126
+ :foo => :bar
127
+ )
27
128
 
28
- assert{ Array(o.errors.get(:foo, :bar)).empty? }
129
+ case action
130
+ when 'new'
131
+ update_attributes(:action => :new)
132
+ when 'edit'
133
+ update_attributes(:action => :edit)
134
+ else
135
+ update_attributes(:action => nil)
136
+ end
137
+
138
+ update_attributes(params)
139
+ end
140
+ end
141
+
142
+ params = {:key => :val}
143
+
144
+ %w( new edit ).each do |action|
145
+ o = assert{ c.for(action, :a, :b, :c, params) }
146
+ assert{ o.action == action }
147
+ assert{ o.key == :val }
148
+ assert{ o.foo == :bar }
149
+ %w( a b c ).each{|var| assert{ o.instance_variable_get("@#{ var }") == var.to_sym } }
150
+ end
151
+ end
29
152
  end
30
153
 
31
154
  ##
32
155
  #
33
- testing 'that basic form elements work' do
34
- c =
35
- assert{
36
- new_foo_conducer_class do
37
- validates_presence_of :bar
156
+ context :teh_default_save do
157
+ #
158
+ testing 'is sane and based solely on the last model' do
159
+ user = User.new
160
+ post = Post.new
161
+ comment = Comment.new
162
+ params = {:text => 'hai!', :user => {:params => 'are ignored'}, :post => {:params => 'are ignored'}}
163
+
164
+ args = [comment, post, user, params]
165
+
166
+ c = new_conducer(*args)
167
+
168
+ assert{ comment[:text].nil? }
169
+ assert{ c.save }
170
+ assert{ comment.text == 'hai!' }
171
+ assert{ comment[:user].nil? }
172
+ assert{ comment[:post].nil? }
173
+ end
174
+
175
+ #
176
+ testing 'halts when the conducer is invalid with errors' do
177
+ conducer_class =
178
+ new_conducer_class do
179
+ validates_presence_of(:foo)
38
180
  end
39
- }
40
181
 
41
- o = assert{ c.new }
42
- assert{ o.form }
43
- assert{ o.form.input(:foo) }
44
- assert{ o.form.input(:bar) }
182
+ c = conducer_class.new
183
+
184
+ assert{ !c.save }
185
+ assert{ !c.valid? }
186
+ assert{ !c.errors.empty? }
187
+ end
188
+
189
+ #
190
+ testing 'halts when the model is invalid and relays errors' do
191
+ post = Post.new
192
+ post.errors[:foo] = 'is fucked'
193
+ c = new_conducer(post)
194
+ assert{ !c.save }
195
+ assert{ c.errors[:foo] == Array(post.errors[:foo]) }
196
+ end
197
+
198
+ #
199
+ testing 'raises a validation error on #save!' do
200
+ post = Post.new
201
+ post.errors[:foo] = 'is fucked'
202
+ c = new_conducer(post)
203
+
204
+ error = assert{ begin; c.save!; rescue Object => e; e; end; }
205
+
206
+ assert{ error.errors == c.errors }
207
+ assert{ error.errors[:foo] = Array(post.errors[:foo]) }
208
+ assert{ c.errors[:foo] = Array(post.errors[:foo]) }
209
+ end
45
210
  end
46
211
 
47
212
  ##
48
213
  #
49
- context 'class endpoint' do
214
+ context :validations do
215
+ #
216
+ testing 'that simple validations/errors work' do
217
+ c =
218
+ assert{
219
+ new_foo_conducer_class do
220
+ validates_presence_of :bar
221
+ validates_presence_of :foo, :bar
222
+ end
223
+ }
224
+
225
+ o = assert{ c.new }
226
+ assert{ !o.valid? }
227
+
228
+ assert{ Array(o.errors.get(:bar)).size == 1 }
229
+ assert{ Array(o.errors.get(:foo, :bar)).size == 1 }
230
+
231
+ o.attributes.set :foo, :bar, 42
232
+ assert{ !o.valid? }
233
+
234
+ assert{ Array(o.errors.get(:bar)).size == 1 }
235
+ assert{ Array(o.errors.get(:foo, :bar)).size == 0 }
236
+
237
+ assert{ Array(o.errors.get(:foo, :bar)).empty? }
238
+ end
239
+
240
+ #
241
+ testing 'that validations are evaluated in the context of the object' do
242
+ c =
243
+ assert{
244
+ new_foo_conducer_class do
245
+ klass = self
246
+ validates(:a){ klass == self.class }
247
+
248
+ validates(:b){ value != 42.0 }
249
+
250
+ def value() 42 end
251
+ end
252
+ }
253
+
254
+ o = assert{ c.new }
255
+ assert{ !o.valid? }
256
+ assert{ o.errors.get(:a).empty? }
257
+ assert{ !o.errors.get(:b).empty? }
258
+ end
259
+
260
+ #
261
+ testing 'that validates_each werks at the class and instance level' do
262
+ conducer_class =
263
+ new_conducer_class do
264
+ validates_each :a do |item|
265
+ validated.push(item)
266
+ true
267
+ end
268
+
269
+ def save
270
+ validates_each :b do |item|
271
+ validated.push(item)
272
+ true
273
+ end
274
+ return valid?
275
+ end
276
+
277
+ def validated
278
+ @validated ||= []
279
+ end
280
+ end
281
+
282
+ a = %w( a b c )
283
+ b = %w( 1 2 3 )
284
+
285
+ c = assert{ conducer_class.new(:a => a, :b => b) }
286
+ assert{ c.run_validations }
287
+ assert{ c.validated == %w( a b c ) }
288
+
289
+
290
+ c = conducer_class.new(:a => a, :b => b)
291
+ assert{ c.save }
292
+ assert{ c.validated == %w( a b c 1 2 3 ) }
293
+ end
294
+ end
295
+
296
+ ##
297
+ #
298
+ context :forms do
299
+ #
300
+ testing 'that basic form helpers work' do
301
+ c =
302
+ assert{
303
+ new_foo_conducer_class do
304
+ validates_presence_of :bar
305
+ end
306
+ }
307
+
308
+ o = assert{ c.new }
309
+ assert{ !o.valid? } # make validations run...
310
+ assert{ o.form }
311
+ assert{ o.form.input(:foo) =~ /\<input/ }
312
+ assert{ o.form.input(:foo) !~ /errors/ }
313
+ assert{ o.form.textarea(:bar) =~ /\<textarea/ }
314
+ assert{ o.form.textarea(:bar) =~ /errors/ }
315
+ end
316
+ end
317
+
318
+ ##
319
+ #
320
+ context :class_methods do
321
+ #
322
+ testing 'that base classes can be constructed and named' do
323
+ new_foo_conducer_class()
324
+ end
325
+
326
+ #
50
327
  testing '.new' do
51
328
  c = assert{ new_foo_conducer_class }
52
329
  controller = assert{ Dao.mock_controller }
@@ -70,19 +347,7 @@ Testing Dao::Conducer do
70
347
  end
71
348
  end
72
349
 
73
- testing '.all' do
74
- c = assert{ new_foo_conducer_class }
75
- assert{ c.all().is_a?(Array) }
76
- assert{ c.all(nil).is_a?(Array) }
77
- assert{ c.all({}).is_a?(Array) }
78
- end
79
-
80
- testing '.find' do
81
- c = assert{ new_foo_conducer_class }
82
- o = assert{ c.new }
83
- assert{ c.find(o.id).is_a?(Dao::Conducer) }
84
- end
85
-
350
+ #
86
351
  testing '.model_name' do
87
352
  c = assert{ new_foo_conducer_class }
88
353
  assert{ c.model_name }
@@ -91,54 +356,21 @@ Testing Dao::Conducer do
91
356
  end
92
357
  end
93
358
 
94
- context 'current' do
95
- testing 'class and instance endpoints' do
96
- c = assert{ new_foo_conducer_class }
97
- o = c.new
98
- %w(
99
- current_controller
100
- current_request
101
- current_response
102
- current_session
103
- current_user
104
- ).each do |method|
105
- assert{ o.respond_to?(method) }
106
- assert{ c.respond_to?(method) }
359
+ ##
360
+ #
361
+ context :instance_methods do
362
+ testing '#id' do
363
+ [:_id, :id].each do |id_key|
364
+ o = assert{ new_foo_conducer() }
365
+ assert{ o.id.nil? }
366
+ o.attributes.update(id_key => 42)
367
+ assert{ o.id==42 }
368
+ assert{ o.id = nil; true }
369
+ assert{ !o.id }
370
+ assert{ o.attributes[:id].nil? }
371
+ assert{ o.attributes[:_id].nil? }
107
372
  end
108
373
  end
109
- end
110
-
111
- context 'instance endpoint' do
112
- testing '#save' do
113
- params = {:k => :v}
114
- o = assert{ new_foo_conducer(params) }
115
- assert{ o.save }
116
- id = assert{ o.id }
117
- assert{ db.foos.find(id)[:k] == o.attributes[:k] }
118
- assert{ id == o.id }
119
- assert{ o.attributes =~ params.merge(:id => id) }
120
- end
121
-
122
- testing '#update_attributes' do
123
- params = {:k => :v}
124
- o = assert{ new_foo_conducer(params) }
125
- t = Time.now
126
- assert{ o.update_attributes :t => t }
127
- assert{ o.save }
128
- id = assert{ o.id }
129
- assert{ db.foos.find(id).id == o.id }
130
- assert{ db.foos.find(id) =~ params.merge(:id => id, :t => t) }
131
- end
132
-
133
- testing '#destroy' do
134
- params = {:k => :v}
135
- o = assert{ new_foo_conducer(params) }
136
- assert{ o.save }
137
- id = assert{ o.id }
138
- assert{ db.foos.find(id).id == o.id }
139
- assert{ o.destroy }
140
- assert{ db.foos.find(id).nil? }
141
- end
142
374
 
143
375
  testing '#to_param' do
144
376
  o = assert{ new_foo_conducer() }
@@ -151,24 +383,181 @@ Testing Dao::Conducer do
151
383
  o = assert{ new_foo_conducer() }
152
384
  assert{ o.errors.respond_to?(:[]) }
153
385
  end
386
+
387
+ =begin
388
+ testing 'that conducers can register handlers for setting deeply nested attributes' do
389
+ c =
390
+ new_conducer_class do
391
+ def _update_attributes(attributes = {})
392
+ attributes.each do |key, value|
393
+ case Array(key).join('.')
394
+ when 'user.first_name'
395
+ set(key, value.to_s.upcase)
396
+ return true
397
+ else
398
+ return false
399
+ end
400
+ end
401
+ end
402
+ end
403
+
404
+ o = assert{ c.new :user => {:first_name => 'ara', :last_name => 'howard'} }
405
+ assert{ o.user.first_name == 'ARA' }
406
+ assert{ o.user.last_name == 'howard' }
407
+
408
+ o = assert{ c.new :name => 'ara howard' }
409
+ assert{ o.attributes.get(:name) == 'ara howard' }
410
+ end
411
+ =end
154
412
  end
155
413
 
156
-
414
+
415
+ ##
416
+ #
417
+ context :teh_mount do
418
+ #
419
+ testing 'that mounted objects can be declared at the class level' do
420
+ conducer_class =
421
+ new_conducer_class do
422
+ mount Dao::Upload, :a, :b, :placeholder => '/images/foo.jpg'
423
+ end
424
+
425
+ assert{ !conducer_class.mounted.empty? }
426
+
427
+ c = conducer_class.new
428
+
429
+ assert{ c.mounted.first.is_a?(Dao::Upload) }
430
+ assert{ c.mounted.first._key.join('.') == 'a.b' }
431
+ assert{ c.mounted.first._value.nil? }
432
+ end
433
+
434
+ #
435
+ testing 'that mounted objects replace their location in attributes' do
436
+ conducer_class =
437
+ new_conducer_class do
438
+ mount Dao::Upload, :a, :b, :placeholder => '/images/foo.jpg'
439
+ end
440
+
441
+ path = __FILE__
442
+ up = Upload.new(path)
443
+
444
+ c = conducer_class.new( :a => {:b => {:file => up}} )
445
+
446
+ upload = assert{ c.get(:a, :b) }
447
+
448
+ assert{ upload.is_a?(Dao::Upload) }
449
+ assert{ test(?f, upload._value) }
450
+ end
451
+
452
+ #
453
+ testing 'that the default save uses the mounted _value and _clears it' do
454
+ conducer_class =
455
+ new_conducer_class do
456
+ mount Dao::Upload, :up, :placeholder => '/images/foo.jpg'
457
+ end
458
+
459
+ path = File.join(File.dirname(__FILE__), 'data/han-solo.jpg')
460
+ assert{ test(?s, path) }
461
+ up = Upload.new(path)
462
+ comment = Comment.new
463
+
464
+ c = conducer_class.new( comment, :up => {:file => up} )
465
+
466
+ upload = assert{ c.get(:up) }
467
+ assert{ upload.is_a?(Dao::Upload) }
468
+
469
+ assert{ test(?f, upload.path) }
470
+ assert{ File.basename(upload.path) == File.basename(path) }
471
+ assert{ IO.read(upload.path) == IO.read(path) }
472
+
473
+ assert{ c.save }
474
+
475
+ value_was_relayed = assert{ comment.attributes[:up] == upload._value }
476
+ value_was_cleared = assert{ !test(?f, upload.path) }
477
+
478
+ assert{ test(?s, path) }
479
+ end
480
+ end
481
+
482
+ ##
483
+ #
484
+ context :collections do
485
+ testing 'can be created from page-y blessed arrays' do
486
+ paginated = Paginated[Post.new, Post.new, Post.new]
487
+ paginated.limit = 42
488
+ paginated.offset = 42.0
489
+ paginated.total_count = 420
490
+
491
+ conducer_class = new_conducer_class
492
+
493
+ conducer_class.collection_for(paginated)
494
+ collection = assert{ conducer_class.collection_for(paginated) }
495
+ assert{ collection.models == paginated }
496
+ assert{ collection.limit == 42 }
497
+ assert{ collection.offset == 42.0 }
498
+ assert{ collection.total_count == 420 }
499
+
500
+ user = User.new
501
+ collection = assert{ conducer_class.collection_for(paginated){|model| conducer_class.for(:show, user, model)} }
502
+ assert{ collection.all?{|conducer| conducer.action == :show} }
503
+ assert{ collection.all?{|conducer| conducer.models.first==user} }
504
+ assert{ collection.all?{|conducer| conducer.models.last.is_a?(Post)} }
505
+ end
506
+ end
507
+
508
+ ##
509
+ #
510
+ context :callbacks do
511
+ testing 'can be added lazily in an ad-hoc fashion' do
512
+ callbacks = []
513
+
514
+ conducer_class =
515
+ new_conducer_class do
516
+ before_initialize do
517
+ callbacks.push(:before_initialize)
518
+ end
519
+
520
+ after_initialize do
521
+ callbacks.push(:after_initialize)
522
+ end
523
+
524
+ define_method(:foobar){ 42 }
525
+
526
+ before :foobar do
527
+ callbacks.push(:before_foobar)
528
+ end
529
+
530
+ after :foobar do
531
+ callbacks.push(:after_foobar)
532
+ end
533
+ end
534
+
535
+ c = assert{ conducer_class.new }
536
+ assert{ callbacks == [:before_initialize, :after_initialize] }
537
+ assert{ c.foobar; true }
538
+ assert{ callbacks == [:before_initialize, :after_initialize, :before_foobar, :after_foobar] }
539
+ end
540
+ end
157
541
 
158
542
  protected
159
543
  def new_foo_conducer_class(&block)
160
- name = 'FooConducer'
161
- c = assert{ Class.new(Dao::Conducer){ self.name = name; crud! } }
544
+ const = :FooConducer
545
+ Object.send(:remove_const, const) if Object.send(:const_defined?, const)
546
+ name = const.to_s
547
+ c = assert{ Class.new(Dao::Conducer){ self.name = name } }
548
+ Object.send(:const_set, const, c)
162
549
  assert{ c.name == 'FooConducer' }
163
550
  assert{ c.model_name == 'Foo' }
164
551
  assert{ c.table_name == 'foos' && c.collection_name == 'foos' }
165
- assert{ c.module_eval(&block); true } if block
552
+ assert{ c.class_eval(&block); true } if block
166
553
  c
167
554
  end
555
+ alias_method :new_conducer_class, :new_foo_conducer_class
168
556
 
169
557
  def new_foo_conducer(*args, &block)
170
558
  assert{ new_foo_conducer_class(&block).new(*args) }
171
559
  end
560
+ alias_method :new_conducer, :new_foo_conducer
172
561
 
173
562
  prepare do
174
563
  $db = Dao::Db.new(:path => 'test/db.yml')
@@ -193,6 +582,134 @@ protected
193
582
  def collection
194
583
  $db[:foos]
195
584
  end
585
+
586
+ class Mounted
587
+ def Mounted.mount(*args, &block)
588
+ new(*args, &block)
589
+ end
590
+
591
+ def _set
592
+ end
593
+
594
+ def _key
595
+ end
596
+
597
+ def _value
598
+ end
599
+
600
+ def _clear
601
+ end
602
+ end
603
+
604
+ class Upload < StringIO
605
+ attr_accessor :path
606
+
607
+ def initialize(path)
608
+ super(IO.read(@path = path))
609
+ end
610
+ end
611
+
612
+ class Model
613
+ class << self
614
+ def model_name
615
+ name = self.name.split(/::/).last
616
+ ActiveModel::Name.new(Map[:name, name])
617
+ end
618
+ end
619
+
620
+ {
621
+ :new_record => true,
622
+ :persisted => false,
623
+ :destroyed => false,
624
+ }.each do |state, value|
625
+ class_eval <<-__
626
+ attr_writer :#{ state }
627
+
628
+ def #{ state }
629
+ @#{ state } = #{ value } unless defined?(@#{ state })
630
+ @#{ state }
631
+ end
632
+
633
+ def #{ state }?
634
+ #{ state }
635
+ end
636
+ __
637
+ end
638
+
639
+ def initialize(attributes = {})
640
+ self.attributes.update(attributes)
641
+ end
642
+
643
+ def attributes
644
+ @attributes ||= Map.new
645
+ end
646
+
647
+ def [](key)
648
+ attributes[key]
649
+ end
650
+
651
+ def []=(key, val)
652
+ attributes[key] = val
653
+ end
654
+
655
+ def update_attributes(hash = {})
656
+ hash.each{|k,v| attributes[k] = v }
657
+ end
658
+
659
+ def method_missing(method, *args, &block)
660
+ re = /^([^=!?]+)([=!?])?$/imox
661
+ matched, key, suffix = re.match(method.to_s).to_a
662
+
663
+ case suffix
664
+ when '=' then attributes.set(key, args.first)
665
+ when '!' then attributes.set(key, args.size > 0 ? args.first : true)
666
+ when '?' then attributes.has?(key)
667
+ else
668
+ attributes.has?(key) ? attributes.get(key) : super
669
+ end
670
+ end
671
+
672
+ def inspect(*args, &block)
673
+ "#{ self.class.name }( #{ attributes.inspect } )"
674
+ end
675
+
676
+ def errors
677
+ @errors ||= Map.new
678
+ end
679
+
680
+ def valid?
681
+ errors.empty?
682
+ end
683
+
684
+ def save
685
+ return false unless valid?
686
+ self.new_record = false
687
+ self.persisted = true
688
+ return true
689
+ end
690
+
691
+ def destroy
692
+ true
693
+ ensure
694
+ self.new_record = false
695
+ self.destroyed = true
696
+ end
697
+ end
698
+
699
+ class Paginated < ::Array
700
+ attr_accessor :limit
701
+ attr_accessor :offset
702
+ attr_accessor :total_count
703
+ end
704
+
705
+ class User < Model
706
+ end
707
+
708
+ class Post < Model
709
+ end
710
+
711
+ class Comment < Model
712
+ end
196
713
  end
197
714
 
198
715
 
@@ -202,4 +719,5 @@ BEGIN {
202
719
  libdir = File.join(rootdir, 'lib')
203
720
  require File.join(libdir, 'dao')
204
721
  require File.join(testdir, 'testing')
722
+ require 'stringio'
205
723
  }