couchrest_model_thought 1.0.0.beta8

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 (70) hide show
  1. data/Gemfile +9 -0
  2. data/LICENSE +176 -0
  3. data/README.md +320 -0
  4. data/Rakefile +69 -0
  5. data/THANKS.md +19 -0
  6. data/examples/model/example.rb +144 -0
  7. data/lib/couchrest/model/associations.rb +207 -0
  8. data/lib/couchrest/model/attribute_protection.rb +74 -0
  9. data/lib/couchrest/model/attributes.rb +91 -0
  10. data/lib/couchrest/model/base.rb +111 -0
  11. data/lib/couchrest/model/callbacks.rb +27 -0
  12. data/lib/couchrest/model/casted_array.rb +39 -0
  13. data/lib/couchrest/model/casted_model.rb +68 -0
  14. data/lib/couchrest/model/class_proxy.rb +122 -0
  15. data/lib/couchrest/model/collection.rb +260 -0
  16. data/lib/couchrest/model/design_doc.rb +126 -0
  17. data/lib/couchrest/model/document_queries.rb +82 -0
  18. data/lib/couchrest/model/errors.rb +23 -0
  19. data/lib/couchrest/model/extended_attachments.rb +73 -0
  20. data/lib/couchrest/model/persistence.rb +141 -0
  21. data/lib/couchrest/model/properties.rb +144 -0
  22. data/lib/couchrest/model/property.rb +96 -0
  23. data/lib/couchrest/model/support/couchrest.rb +19 -0
  24. data/lib/couchrest/model/support/hash.rb +9 -0
  25. data/lib/couchrest/model/typecast.rb +170 -0
  26. data/lib/couchrest/model/validations/casted_model.rb +14 -0
  27. data/lib/couchrest/model/validations/locale/en.yml +5 -0
  28. data/lib/couchrest/model/validations/uniqueness.rb +42 -0
  29. data/lib/couchrest/model/validations.rb +68 -0
  30. data/lib/couchrest/model/version.rb +5 -0
  31. data/lib/couchrest/model/views.rb +160 -0
  32. data/lib/couchrest/model.rb +5 -0
  33. data/lib/couchrest_model.rb +53 -0
  34. data/spec/couchrest/assocations_spec.rb +213 -0
  35. data/spec/couchrest/attachment_spec.rb +148 -0
  36. data/spec/couchrest/attribute_protection_spec.rb +153 -0
  37. data/spec/couchrest/base_spec.rb +463 -0
  38. data/spec/couchrest/casted_model_spec.rb +424 -0
  39. data/spec/couchrest/casted_spec.rb +75 -0
  40. data/spec/couchrest/class_proxy_spec.rb +132 -0
  41. data/spec/couchrest/inherited_spec.rb +40 -0
  42. data/spec/couchrest/persistence_spec.rb +409 -0
  43. data/spec/couchrest/property_spec.rb +804 -0
  44. data/spec/couchrest/subclass_spec.rb +99 -0
  45. data/spec/couchrest/validations.rb +85 -0
  46. data/spec/couchrest/view_spec.rb +463 -0
  47. data/spec/fixtures/attachments/README +3 -0
  48. data/spec/fixtures/attachments/couchdb.png +0 -0
  49. data/spec/fixtures/attachments/test.html +11 -0
  50. data/spec/fixtures/base.rb +139 -0
  51. data/spec/fixtures/more/article.rb +35 -0
  52. data/spec/fixtures/more/card.rb +17 -0
  53. data/spec/fixtures/more/cat.rb +19 -0
  54. data/spec/fixtures/more/course.rb +25 -0
  55. data/spec/fixtures/more/event.rb +8 -0
  56. data/spec/fixtures/more/invoice.rb +14 -0
  57. data/spec/fixtures/more/person.rb +9 -0
  58. data/spec/fixtures/more/question.rb +7 -0
  59. data/spec/fixtures/more/service.rb +10 -0
  60. data/spec/fixtures/more/user.rb +22 -0
  61. data/spec/fixtures/views/lib.js +3 -0
  62. data/spec/fixtures/views/test_view/lib.js +3 -0
  63. data/spec/fixtures/views/test_view/only-map.js +4 -0
  64. data/spec/fixtures/views/test_view/test-map.js +3 -0
  65. data/spec/fixtures/views/test_view/test-reduce.js +3 -0
  66. data/spec/spec.opts +5 -0
  67. data/spec/spec_helper.rb +48 -0
  68. data/utils/remap.rb +27 -0
  69. data/utils/subset.rb +30 -0
  70. metadata +215 -0
@@ -0,0 +1,424 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../spec_helper', __FILE__)
4
+ require File.join(FIXTURE_PATH, 'more', 'cat')
5
+ require File.join(FIXTURE_PATH, 'more', 'person')
6
+ require File.join(FIXTURE_PATH, 'more', 'card')
7
+ require File.join(FIXTURE_PATH, 'more', 'question')
8
+ require File.join(FIXTURE_PATH, 'more', 'course')
9
+
10
+
11
+ class WithCastedModelMixin < Hash
12
+ include CouchRest::Model::CastedModel
13
+ property :name
14
+ property :no_value
15
+ property :details, Object, :default => {}
16
+ property :casted_attribute, WithCastedModelMixin
17
+ end
18
+
19
+ class DummyModel < CouchRest::Model::Base
20
+ use_database TEST_SERVER.default_database
21
+ raise "Default DB not set" if TEST_SERVER.default_database.nil?
22
+ property :casted_attribute, WithCastedModelMixin
23
+ property :keywords, [String]
24
+ property :sub_models do |child|
25
+ child.property :title
26
+ end
27
+ end
28
+
29
+ class WithCastedCallBackModel < Hash
30
+ include CouchRest::Model::CastedModel
31
+ property :name
32
+ property :run_before_validate
33
+ property :run_after_validate
34
+
35
+ before_validate do |object|
36
+ object.run_before_validate = true
37
+ end
38
+ after_validate do |object|
39
+ object.run_after_validate = true
40
+ end
41
+ end
42
+
43
+ class CastedCallbackDoc < CouchRest::Model::Base
44
+ use_database TEST_SERVER.default_database
45
+ raise "Default DB not set" if TEST_SERVER.default_database.nil?
46
+ property :callback_model, WithCastedCallBackModel
47
+ end
48
+
49
+ describe CouchRest::Model::CastedModel do
50
+
51
+ describe "A non hash class including CastedModel" do
52
+ it "should fail raising and include error" do
53
+ lambda do
54
+ class NotAHashButWithCastedModelMixin
55
+ include CouchRest::CastedModel
56
+ property :name
57
+ end
58
+
59
+ end.should raise_error
60
+ end
61
+ end
62
+
63
+ describe "isolated" do
64
+ before(:each) do
65
+ @obj = WithCastedModelMixin.new
66
+ end
67
+ it "should automatically include the property mixin and define getters and setters" do
68
+ @obj.name = 'Matt'
69
+ @obj.name.should == 'Matt'
70
+ end
71
+
72
+ it "should allow override of default" do
73
+ @obj = WithCastedModelMixin.new(:name => 'Eric', :details => {'color' => 'orange'})
74
+ @obj.name.should == 'Eric'
75
+ @obj.details['color'].should == 'orange'
76
+ end
77
+ end
78
+
79
+ describe "casted as an attribute, but without a value" do
80
+ before(:each) do
81
+ @obj = DummyModel.new
82
+ @casted_obj = @obj.casted_attribute
83
+ end
84
+ it "should be nil" do
85
+ @casted_obj.should == nil
86
+ end
87
+ end
88
+
89
+ describe "anonymous sub casted models" do
90
+ before :each do
91
+ @obj = DummyModel.new
92
+ end
93
+ it "should be empty initially" do
94
+ @obj.sub_models.should_not be_nil
95
+ @obj.sub_models.should be_empty
96
+ end
97
+ it "should be updatable using a hash" do
98
+ @obj.sub_models << {:title => 'test'}
99
+ @obj.sub_models.first.title.should eql('test')
100
+ end
101
+ end
102
+
103
+ describe "casted as attribute" do
104
+ before(:each) do
105
+ casted = {:name => 'not whatever'}
106
+ @obj = DummyModel.new(:casted_attribute => {:name => 'whatever', :casted_attribute => casted})
107
+ @casted_obj = @obj.casted_attribute
108
+ end
109
+
110
+ it "should be available from its parent" do
111
+ @casted_obj.should be_an_instance_of(WithCastedModelMixin)
112
+ end
113
+
114
+ it "should have the getters defined" do
115
+ @casted_obj.name.should == 'whatever'
116
+ end
117
+
118
+ it "should know who casted it" do
119
+ @casted_obj.casted_by.should == @obj
120
+ end
121
+
122
+ it "should return nil for the 'no_value' attribute" do
123
+ @casted_obj.no_value.should be_nil
124
+ end
125
+
126
+ it "should return nil for the unknown attribute" do
127
+ @casted_obj["unknown"].should be_nil
128
+ end
129
+
130
+ it "should return {} for the hash attribute" do
131
+ @casted_obj.details.should == {}
132
+ end
133
+
134
+ it "should cast its own attributes" do
135
+ @casted_obj.casted_attribute.should be_instance_of(WithCastedModelMixin)
136
+ end
137
+ end
138
+
139
+ describe "casted as an array of a different type" do
140
+ before(:each) do
141
+ @obj = DummyModel.new(:keywords => ['couch', 'sofa', 'relax', 'canapé'])
142
+ end
143
+
144
+ it "should cast the array properly" do
145
+ @obj.keywords.should be_an_instance_of(Array)
146
+ @obj.keywords.first.should == 'couch'
147
+ end
148
+ end
149
+
150
+ describe "update attributes without saving" do
151
+ before(:each) do
152
+ @question = Question.new(:q => "What is your quest?", :a => "To seek the Holy Grail")
153
+ end
154
+ it "should work for attribute= methods" do
155
+ @question.q.should == "What is your quest?"
156
+ @question['a'].should == "To seek the Holy Grail"
157
+ @question.update_attributes_without_saving(:q => "What is your favorite color?", 'a' => "Blue")
158
+ @question['q'].should == "What is your favorite color?"
159
+ @question.a.should == "Blue"
160
+ end
161
+
162
+ it "should also work for attributes= alias" do
163
+ @question.respond_to?(:attributes=).should be_true
164
+ @question.attributes = {:q => "What is your favorite color?", 'a' => "Blue"}
165
+ @question['q'].should == "What is your favorite color?"
166
+ @question.a.should == "Blue"
167
+ end
168
+
169
+ it "should flip out if an attribute= method is missing" do
170
+ lambda {
171
+ @q.update_attributes_without_saving('foo' => "something", :a => "No green")
172
+ }.should raise_error(NoMethodError)
173
+ end
174
+
175
+ it "should not change any attributes if there is an error" do
176
+ lambda {
177
+ @q.update_attributes_without_saving('foo' => "something", :a => "No green")
178
+ }.should raise_error(NoMethodError)
179
+ @question.q.should == "What is your quest?"
180
+ @question.a.should == "To seek the Holy Grail"
181
+ end
182
+ end
183
+
184
+ describe "saved document with casted models" do
185
+ before(:each) do
186
+ reset_test_db!
187
+ @obj = DummyModel.new(:casted_attribute => {:name => 'whatever'})
188
+ @obj.save.should be_true
189
+ @obj = DummyModel.get(@obj.id)
190
+ end
191
+
192
+ it "should be able to load with the casted models" do
193
+ casted_obj = @obj.casted_attribute
194
+ casted_obj.should_not be_nil
195
+ casted_obj.should be_an_instance_of(WithCastedModelMixin)
196
+ end
197
+
198
+ it "should have defined getters for the casted model" do
199
+ casted_obj = @obj.casted_attribute
200
+ casted_obj.name.should == "whatever"
201
+ end
202
+
203
+ it "should have defined setters for the casted model" do
204
+ casted_obj = @obj.casted_attribute
205
+ casted_obj.name = "test"
206
+ casted_obj.name.should == "test"
207
+ end
208
+
209
+ it "should retain an override of a casted model attribute's default" do
210
+ casted_obj = @obj.casted_attribute
211
+ casted_obj.details['color'] = 'orange'
212
+ @obj.save
213
+ casted_obj = DummyModel.get(@obj.id).casted_attribute
214
+ casted_obj.details['color'].should == 'orange'
215
+ end
216
+
217
+ end
218
+
219
+ describe "saving document with array of casted models and validation" do
220
+ before :each do
221
+ @cat = Cat.new :name => "felix"
222
+ @cat.save
223
+ end
224
+
225
+ it "should save" do
226
+ toy = CatToy.new :name => "Mouse"
227
+ @cat.toys.push(toy)
228
+ @cat.save.should be_true
229
+ @cat = Cat.get @cat.id
230
+ @cat.toys.class.should == CouchRest::Model::CastedArray
231
+ @cat.toys.first.class.should == CatToy
232
+ @cat.toys.first.should === toy
233
+ end
234
+
235
+ it "should fail because name is not present" do
236
+ toy = CatToy.new
237
+ @cat.toys.push(toy)
238
+ @cat.should_not be_valid
239
+ @cat.save.should be_false
240
+ end
241
+
242
+ it "should not fail if the casted model doesn't have validation" do
243
+ Cat.property :masters, [Person], :default => []
244
+ Cat.validates_presence_of :name
245
+ cat = Cat.new(:name => 'kitty')
246
+ cat.should be_valid
247
+ cat.masters.push Person.new
248
+ cat.should be_valid
249
+ end
250
+ end
251
+
252
+ describe "calling valid?" do
253
+ before :each do
254
+ @cat = Cat.new
255
+ @toy1 = CatToy.new
256
+ @toy2 = CatToy.new
257
+ @toy3 = CatToy.new
258
+ @cat.favorite_toy = @toy1
259
+ @cat.toys << @toy2
260
+ @cat.toys << @toy3
261
+ end
262
+
263
+ describe "on the top document" do
264
+ it "should put errors on all invalid casted models" do
265
+ @cat.should_not be_valid
266
+ @cat.errors.should_not be_empty
267
+ @toy1.errors.should_not be_empty
268
+ @toy2.errors.should_not be_empty
269
+ @toy3.errors.should_not be_empty
270
+ end
271
+
272
+ it "should not put errors on valid casted models" do
273
+ @toy1.name = "Feather"
274
+ @toy2.name = "Twine"
275
+ @cat.should_not be_valid
276
+ @cat.errors.should_not be_empty
277
+ @toy1.errors.should be_empty
278
+ @toy2.errors.should be_empty
279
+ @toy3.errors.should_not be_empty
280
+ end
281
+ end
282
+
283
+ describe "on a casted model property" do
284
+ it "should only validate itself" do
285
+ @toy1.should_not be_valid
286
+ @toy1.errors.should_not be_empty
287
+ @cat.errors.should be_empty
288
+ @toy2.errors.should be_empty
289
+ @toy3.errors.should be_empty
290
+ end
291
+ end
292
+
293
+ describe "on a casted model inside a casted collection" do
294
+ it "should only validate itself" do
295
+ @toy2.should_not be_valid
296
+ @toy2.errors.should_not be_empty
297
+ @cat.errors.should be_empty
298
+ @toy1.errors.should be_empty
299
+ @toy3.errors.should be_empty
300
+ end
301
+ end
302
+ end
303
+
304
+ describe "calling new? on a casted model" do
305
+ before :each do
306
+ reset_test_db!
307
+ @cat = Cat.new(:name => 'Sockington')
308
+ @favorite_toy = CatToy.new(:name => 'Catnip Ball')
309
+ @cat.favorite_toy = @favorite_toy
310
+ @cat.toys << CatToy.new(:name => 'Fuzzy Stick')
311
+ end
312
+
313
+ it "should be true on new" do
314
+ CatToy.new.should be_new
315
+ CatToy.new.new_record?.should be_true
316
+ end
317
+
318
+ it "should be true after assignment" do
319
+ @cat.should be_new
320
+ @cat.favorite_toy.should be_new
321
+ @cat.toys.first.should be_new
322
+ end
323
+
324
+ it "should not be true after create or save" do
325
+ @cat.create
326
+ @cat.save
327
+ @cat.favorite_toy.should_not be_new
328
+ @cat.toys.first.casted_by.should eql(@cat)
329
+ @cat.toys.first.should_not be_new
330
+ end
331
+
332
+ it "should not be true after get from the database" do
333
+ @cat.save
334
+ @cat = Cat.get(@cat.id)
335
+ @cat.favorite_toy.should_not be_new
336
+ @cat.toys.first.should_not be_new
337
+ end
338
+
339
+ it "should still be true after a failed create or save" do
340
+ @cat.name = nil
341
+ @cat.create.should be_false
342
+ @cat.save.should be_false
343
+ @cat.favorite_toy.should be_new
344
+ @cat.toys.first.should be_new
345
+ end
346
+ end
347
+
348
+ describe "calling base_doc from a nested casted model" do
349
+ before :each do
350
+ @course = Course.new(:title => 'Science 101')
351
+ @professor = Person.new(:name => ['Professor', 'Plum'])
352
+ @cat = Cat.new(:name => 'Scratchy')
353
+ @toy1 = CatToy.new
354
+ @toy2 = CatToy.new
355
+ @course.professor = @professor
356
+ @professor.pet = @cat
357
+ @cat.favorite_toy = @toy1
358
+ @cat.toys << @toy2
359
+ end
360
+
361
+ it "should reference the top document for" do
362
+ @course.base_doc.should === @course
363
+ @professor.casted_by.should === @course
364
+ @professor.base_doc.should === @course
365
+ @cat.base_doc.should === @course
366
+ @toy1.base_doc.should === @course
367
+ @toy2.base_doc.should === @course
368
+ end
369
+
370
+ it "should call setter on top document" do
371
+ @toy1.base_doc.should_not be_nil
372
+ @toy1.base_doc.title = 'Tom Foolery'
373
+ @course.title.should == 'Tom Foolery'
374
+ end
375
+
376
+ it "should return nil if not yet casted" do
377
+ person = Person.new
378
+ person.base_doc.should == nil
379
+ end
380
+ end
381
+
382
+ describe "calling base_doc.save from a nested casted model" do
383
+ before :each do
384
+ reset_test_db!
385
+ @cat = Cat.new(:name => 'Snowball')
386
+ @toy = CatToy.new
387
+ @cat.favorite_toy = @toy
388
+ end
389
+
390
+ it "should not save parent document when casted model is invalid" do
391
+ @toy.should_not be_valid
392
+ @toy.base_doc.save.should be_false
393
+ lambda{@toy.base_doc.save!}.should raise_error
394
+ end
395
+
396
+ it "should save parent document when nested casted model is valid" do
397
+ @toy.name = "Mr Squeaks"
398
+ @toy.should be_valid
399
+ @toy.base_doc.save.should be_true
400
+ lambda{@toy.base_doc.save!}.should_not raise_error
401
+ end
402
+ end
403
+
404
+ describe "callbacks" do
405
+ before(:each) do
406
+ @doc = CastedCallbackDoc.new
407
+ @model = WithCastedCallBackModel.new
408
+ @doc.callback_model = @model
409
+ end
410
+
411
+ describe "validate" do
412
+ it "should run before_validate before validating" do
413
+ @model.run_before_validate.should be_nil
414
+ @model.should be_valid
415
+ @model.run_before_validate.should be_true
416
+ end
417
+ it "should run after_validate after validating" do
418
+ @model.run_after_validate.should be_nil
419
+ @model.should be_valid
420
+ @model.run_after_validate.should be_true
421
+ end
422
+ end
423
+ end
424
+ end
@@ -0,0 +1,75 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+ require File.join(FIXTURE_PATH, 'more', 'cat')
3
+ require File.join(FIXTURE_PATH, 'more', 'person')
4
+ require File.join(FIXTURE_PATH, 'more', 'card')
5
+
6
+ class Driver < CouchRest::Model::Base
7
+ use_database TEST_SERVER.default_database
8
+ # You have to add a casted_by accessor if you want to reach a casted extended doc parent
9
+ attr_accessor :casted_by
10
+
11
+ property :name
12
+ end
13
+
14
+ class Car < CouchRest::Model::Base
15
+ use_database TEST_SERVER.default_database
16
+
17
+ property :name
18
+ property :driver, Driver
19
+ end
20
+
21
+ describe "casting an extended document" do
22
+
23
+ before(:each) do
24
+ @driver = Driver.new(:name => 'Matt')
25
+ @car = Car.new(:name => 'Renault 306', :driver => @driver)
26
+ end
27
+
28
+ it "should retain all properties of the casted attribute" do
29
+ @car.driver.should == @driver
30
+ end
31
+
32
+ it "should let the casted document know who casted it" do
33
+ @car.driver.casted_by.should == @car
34
+ end
35
+ end
36
+
37
+ describe "assigning a value to casted attribute after initializing an object" do
38
+
39
+ before(:each) do
40
+ @car = Car.new(:name => 'Renault 306')
41
+ @driver = Driver.new(:name => 'Matt')
42
+ end
43
+
44
+ it "should not create an empty casted object" do
45
+ @car.driver.should be_nil
46
+ end
47
+
48
+ it "should let you assign the value" do
49
+ @car.driver = @driver
50
+ @car.driver.name.should == 'Matt'
51
+ end
52
+
53
+ it "should cast attribute" do
54
+ @car.driver = JSON.parse(@driver.to_json)
55
+ @car.driver.should be_instance_of(Driver)
56
+ end
57
+
58
+ end
59
+
60
+ describe "casting a model from parsed JSON" do
61
+
62
+ before(:each) do
63
+ @driver = Driver.new(:name => 'Matt')
64
+ @car = Car.new(:name => 'Renault 306', :driver => @driver)
65
+ @new_car = Car.new(JSON.parse(@car.to_json))
66
+ end
67
+
68
+ it "should cast casted attribute" do
69
+ @new_car.driver.should be_instance_of(Driver)
70
+ end
71
+
72
+ it "should retain all properties of the casted attribute" do
73
+ @new_car.driver.should == @driver
74
+ end
75
+ end
@@ -0,0 +1,132 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ class UnattachedDoc < CouchRest::Model::Base
4
+ # Note: no use_database here
5
+ property :title
6
+ property :questions
7
+ property :professor
8
+ view_by :title
9
+ end
10
+
11
+
12
+ describe "Proxy Class" do
13
+
14
+ before(:all) do
15
+ reset_test_db!
16
+ # setup the class default doc to save the design doc
17
+ UnattachedDoc.use_database nil # just to be sure it is really unattached
18
+ @us = UnattachedDoc.on(DB)
19
+ %w{aaa bbb ddd eee}.each do |title|
20
+ u = @us.new(:title => title)
21
+ u.save
22
+ @first_id ||= u.id
23
+ end
24
+ end
25
+
26
+ it "should query all" do
27
+ rs = @us.all
28
+ rs.length.should == 4
29
+ end
30
+ it "should count" do
31
+ @us.count.should == 4
32
+ end
33
+ it "should make the design doc upon first query" do
34
+ @us.by_title
35
+ doc = @us.design_doc
36
+ doc['views']['all']['map'].should include('UnattachedDoc')
37
+ end
38
+ it "should merge query params" do
39
+ rs = @us.by_title :startkey=>"bbb", :endkey=>"eee"
40
+ rs.length.should == 3
41
+ end
42
+ it "should query via view" do
43
+ view = @us.view :by_title
44
+ designed = @us.by_title
45
+ view.should == designed
46
+ end
47
+
48
+ it "should query via first_from_view" do
49
+ UnattachedDoc.should_receive(:first_from_view).with('by_title', 'bbb', {:database => DB})
50
+ @us.first_from_view('by_title', 'bbb')
51
+ end
52
+
53
+ it "should query via first_from_view with complex options" do
54
+ UnattachedDoc.should_receive(:first_from_view).with('by_title', {:key => 'bbb', :database => DB})
55
+ @us.first_from_view('by_title', :key => 'bbb')
56
+ end
57
+
58
+ it "should query via first_from_view with complex extra options" do
59
+ UnattachedDoc.should_receive(:first_from_view).with('by_title', 'bbb', {:limit => 1, :database => DB})
60
+ @us.first_from_view('by_title', 'bbb', :limit => 1)
61
+ end
62
+
63
+ it "should allow dynamic view matching for single elements" do
64
+ @us.should_receive(:first_from_view).with('by_title', 'bbb')
65
+ @us.find_by_title('bbb')
66
+ end
67
+
68
+ it "should yield" do
69
+ things = []
70
+ @us.view(:by_title) do |thing|
71
+ things << thing
72
+ end
73
+ things[0]["doc"]["title"].should =='aaa'
74
+ end
75
+ it "should yield with by_key method" do
76
+ things = []
77
+ @us.by_title do |thing|
78
+ things << thing
79
+ end
80
+ things[0]["doc"]["title"].should =='aaa'
81
+ end
82
+ it "should get from specific database" do
83
+ u = @us.get(@first_id)
84
+ u.title.should == "aaa"
85
+ end
86
+ it "should get first" do
87
+ u = @us.first
88
+ u.title.should =~ /\A...\z/
89
+ end
90
+ it "should set database on first retreived document" do
91
+ u = @us.first
92
+ u.database.should === DB
93
+ end
94
+ it "should set database on all retreived documents" do
95
+ @us.all.each do |u|
96
+ u.database.should === DB
97
+ end
98
+ end
99
+ it "should set database on each retreived document" do
100
+ rs = @us.by_title :startkey=>"bbb", :endkey=>"eee"
101
+ rs.length.should == 3
102
+ rs.each do |u|
103
+ u.database.should === DB
104
+ end
105
+ end
106
+ it "should set database on document retreived by id" do
107
+ u = @us.get(@first_id)
108
+ u.database.should === DB
109
+ end
110
+ it "should not attempt to set database on raw results using :all" do
111
+ @us.all(:raw => true).each do |u|
112
+ u.respond_to?(:database).should be_false
113
+ end
114
+ end
115
+ it "should not attempt to set database on raw results using view" do
116
+ @us.by_title(:raw => true).each do |u|
117
+ u.respond_to?(:database).should be_false
118
+ end
119
+ end
120
+ # Sam Lown 2010-04-07
121
+ # Removed as unclear why this should happen as before my changes
122
+ # this happend by accident, not explicitly.
123
+ # If requested, this feature should be added as a specific method.
124
+ #
125
+ #it "should clean up design docs left around on specific database" do
126
+ # @us.by_title
127
+ # original_id = @us.model_design_doc['_rev']
128
+ # Unattached.view_by :professor
129
+ # @us.by_professor
130
+ # @us.model_design_doc['_rev'].should_not == original_id
131
+ #end
132
+ end
@@ -0,0 +1,40 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ begin
4
+ require 'rubygems' unless ENV['SKIP_RUBYGEMS']
5
+ require 'active_support/json'
6
+ ActiveSupport::JSON.backend = :JSONGem
7
+
8
+ class PlainParent
9
+ class_inheritable_accessor :foo
10
+ self.foo = :bar
11
+ end
12
+
13
+ class PlainChild < PlainParent
14
+ end
15
+
16
+ class ExtendedParent < CouchRest::Model::Base
17
+ class_inheritable_accessor :foo
18
+ self.foo = :bar
19
+ end
20
+
21
+ class ExtendedChild < ExtendedParent
22
+ end
23
+
24
+ describe "Using chained inheritance without CouchRest::ExtendedDocument" do
25
+ it "should preserve inheritable attributes" do
26
+ PlainParent.foo.should == :bar
27
+ PlainChild.foo.should == :bar
28
+ end
29
+ end
30
+
31
+ describe "Using chained inheritance with CouchRest::ExtendedDocument" do
32
+ it "should preserve inheritable attributes" do
33
+ ExtendedParent.foo.should == :bar
34
+ ExtendedChild.foo.should == :bar
35
+ end
36
+ end
37
+
38
+ rescue LoadError
39
+ puts "This spec requires 'active_support/json' to be loaded"
40
+ end