dao 4.2.1 → 4.4.2

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.
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
  }