openlogic-couchrest_model 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. data/.gitignore +11 -0
  2. data/.rspec +4 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +176 -0
  5. data/README.md +137 -0
  6. data/Rakefile +38 -0
  7. data/THANKS.md +21 -0
  8. data/VERSION +1 -0
  9. data/benchmarks/dirty.rb +118 -0
  10. data/couchrest_model.gemspec +36 -0
  11. data/history.md +309 -0
  12. data/init.rb +1 -0
  13. data/lib/couchrest/model.rb +10 -0
  14. data/lib/couchrest/model/associations.rb +231 -0
  15. data/lib/couchrest/model/base.rb +129 -0
  16. data/lib/couchrest/model/callbacks.rb +28 -0
  17. data/lib/couchrest/model/casted_array.rb +83 -0
  18. data/lib/couchrest/model/casted_by.rb +33 -0
  19. data/lib/couchrest/model/casted_hash.rb +84 -0
  20. data/lib/couchrest/model/class_proxy.rb +135 -0
  21. data/lib/couchrest/model/collection.rb +273 -0
  22. data/lib/couchrest/model/configuration.rb +67 -0
  23. data/lib/couchrest/model/connection.rb +70 -0
  24. data/lib/couchrest/model/core_extensions/hash.rb +9 -0
  25. data/lib/couchrest/model/core_extensions/time_parsing.rb +66 -0
  26. data/lib/couchrest/model/design_doc.rb +128 -0
  27. data/lib/couchrest/model/designs.rb +91 -0
  28. data/lib/couchrest/model/designs/view.rb +513 -0
  29. data/lib/couchrest/model/dirty.rb +39 -0
  30. data/lib/couchrest/model/document_queries.rb +99 -0
  31. data/lib/couchrest/model/embeddable.rb +78 -0
  32. data/lib/couchrest/model/errors.rb +25 -0
  33. data/lib/couchrest/model/extended_attachments.rb +83 -0
  34. data/lib/couchrest/model/persistence.rb +178 -0
  35. data/lib/couchrest/model/properties.rb +228 -0
  36. data/lib/couchrest/model/property.rb +114 -0
  37. data/lib/couchrest/model/property_protection.rb +71 -0
  38. data/lib/couchrest/model/proxyable.rb +183 -0
  39. data/lib/couchrest/model/support/couchrest_database.rb +13 -0
  40. data/lib/couchrest/model/support/couchrest_design.rb +33 -0
  41. data/lib/couchrest/model/typecast.rb +154 -0
  42. data/lib/couchrest/model/validations.rb +80 -0
  43. data/lib/couchrest/model/validations/casted_model.rb +16 -0
  44. data/lib/couchrest/model/validations/locale/en.yml +5 -0
  45. data/lib/couchrest/model/validations/uniqueness.rb +69 -0
  46. data/lib/couchrest/model/views.rb +151 -0
  47. data/lib/couchrest/railtie.rb +24 -0
  48. data/lib/couchrest_model.rb +66 -0
  49. data/lib/rails/generators/couchrest_model.rb +16 -0
  50. data/lib/rails/generators/couchrest_model/config/config_generator.rb +18 -0
  51. data/lib/rails/generators/couchrest_model/config/templates/couchdb.yml +21 -0
  52. data/lib/rails/generators/couchrest_model/model/model_generator.rb +27 -0
  53. data/lib/rails/generators/couchrest_model/model/templates/model.rb +2 -0
  54. data/spec/.gitignore +1 -0
  55. data/spec/fixtures/attachments/README +3 -0
  56. data/spec/fixtures/attachments/couchdb.png +0 -0
  57. data/spec/fixtures/attachments/test.html +11 -0
  58. data/spec/fixtures/config/couchdb.yml +10 -0
  59. data/spec/fixtures/models/article.rb +36 -0
  60. data/spec/fixtures/models/base.rb +164 -0
  61. data/spec/fixtures/models/card.rb +19 -0
  62. data/spec/fixtures/models/cat.rb +23 -0
  63. data/spec/fixtures/models/client.rb +6 -0
  64. data/spec/fixtures/models/course.rb +27 -0
  65. data/spec/fixtures/models/event.rb +8 -0
  66. data/spec/fixtures/models/invoice.rb +14 -0
  67. data/spec/fixtures/models/key_chain.rb +5 -0
  68. data/spec/fixtures/models/membership.rb +4 -0
  69. data/spec/fixtures/models/person.rb +11 -0
  70. data/spec/fixtures/models/project.rb +6 -0
  71. data/spec/fixtures/models/question.rb +7 -0
  72. data/spec/fixtures/models/sale_entry.rb +9 -0
  73. data/spec/fixtures/models/sale_invoice.rb +14 -0
  74. data/spec/fixtures/models/service.rb +10 -0
  75. data/spec/fixtures/models/user.rb +22 -0
  76. data/spec/fixtures/views/lib.js +3 -0
  77. data/spec/fixtures/views/test_view/lib.js +3 -0
  78. data/spec/fixtures/views/test_view/only-map.js +4 -0
  79. data/spec/fixtures/views/test_view/test-map.js +3 -0
  80. data/spec/fixtures/views/test_view/test-reduce.js +3 -0
  81. data/spec/functional/validations_spec.rb +8 -0
  82. data/spec/spec_helper.rb +60 -0
  83. data/spec/unit/active_model_lint_spec.rb +30 -0
  84. data/spec/unit/assocations_spec.rb +242 -0
  85. data/spec/unit/attachment_spec.rb +176 -0
  86. data/spec/unit/base_spec.rb +537 -0
  87. data/spec/unit/casted_spec.rb +72 -0
  88. data/spec/unit/class_proxy_spec.rb +167 -0
  89. data/spec/unit/collection_spec.rb +86 -0
  90. data/spec/unit/configuration_spec.rb +77 -0
  91. data/spec/unit/connection_spec.rb +148 -0
  92. data/spec/unit/core_extensions/time_parsing.rb +77 -0
  93. data/spec/unit/design_doc_spec.rb +241 -0
  94. data/spec/unit/designs/view_spec.rb +831 -0
  95. data/spec/unit/designs_spec.rb +134 -0
  96. data/spec/unit/dirty_spec.rb +436 -0
  97. data/spec/unit/embeddable_spec.rb +498 -0
  98. data/spec/unit/inherited_spec.rb +33 -0
  99. data/spec/unit/persistence_spec.rb +481 -0
  100. data/spec/unit/property_protection_spec.rb +192 -0
  101. data/spec/unit/property_spec.rb +481 -0
  102. data/spec/unit/proxyable_spec.rb +376 -0
  103. data/spec/unit/subclass_spec.rb +85 -0
  104. data/spec/unit/typecast_spec.rb +521 -0
  105. data/spec/unit/validations_spec.rb +140 -0
  106. data/spec/unit/view_spec.rb +367 -0
  107. metadata +301 -0
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ class PlainParent
4
+ class_inheritable_accessor :foo
5
+ self.foo = :bar
6
+ end
7
+
8
+ class PlainChild < PlainParent
9
+ end
10
+
11
+ class ExtendedParent < CouchRest::Model::Base
12
+ class_inheritable_accessor :foo
13
+ self.foo = :bar
14
+ end
15
+
16
+ class ExtendedChild < ExtendedParent
17
+ end
18
+
19
+ describe "Using chained inheritance without CouchRest::Model::Base" do
20
+ it "should preserve inheritable attributes" do
21
+ PlainParent.foo.should == :bar
22
+ PlainChild.foo.should == :bar
23
+ end
24
+ end
25
+
26
+ describe "Using chained inheritance with CouchRest::Model::Base" do
27
+ it "should preserve inheritable attributes" do
28
+ ExtendedParent.foo.should == :bar
29
+ ExtendedChild.foo.should == :bar
30
+ end
31
+ end
32
+
33
+
@@ -0,0 +1,481 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe CouchRest::Model::Persistence do
5
+
6
+ before(:each) do
7
+ @obj = WithDefaultValues.new
8
+ end
9
+
10
+ describe "creating a new document from database" do
11
+
12
+ it "should instantialize" do
13
+ doc = Article.build_from_database({'_id' => 'testitem1', '_rev' => 123, 'couchrest-type' => 'Article', 'name' => 'my test'})
14
+ doc.class.should eql(Article)
15
+ end
16
+
17
+ it "should instantialize of same class if no couchrest-type included from DB" do
18
+ doc = Article.build_from_database({'_id' => 'testitem1', '_rev' => 123, 'name' => 'my test'})
19
+ doc.class.should eql(Article)
20
+ end
21
+
22
+ it "should instantialize document of different type" do
23
+ doc = Article.build_from_database({'_id' => 'testitem2', '_rev' => 123, Article.model_type_key => 'WithTemplateAndUniqueID', 'name' => 'my test'})
24
+ doc.class.should eql(WithTemplateAndUniqueID)
25
+ end
26
+
27
+ end
28
+
29
+ describe "basic saving and retrieving" do
30
+ it "should work fine" do
31
+ @obj.name = "should be easily saved and retrieved"
32
+ @obj.save!
33
+ saved_obj = WithDefaultValues.get!(@obj.id)
34
+ saved_obj.should_not be_nil
35
+ end
36
+
37
+ it "should parse the Time attributes automatically" do
38
+ @obj.name = "should parse the Time attributes automatically"
39
+ @obj.set_by_proc.should be_an_instance_of(Time)
40
+ @obj.save
41
+ @obj.set_by_proc.should be_an_instance_of(Time)
42
+ saved_obj = WithDefaultValues.get(@obj.id)
43
+ saved_obj.set_by_proc.should be_an_instance_of(Time)
44
+ end
45
+ end
46
+
47
+ describe "creating a model" do
48
+
49
+ before(:each) do
50
+ @sobj = Basic.new
51
+ end
52
+
53
+ it "should accept true or false on save for validation" do
54
+ @sobj.should_receive(:valid?)
55
+ @sobj.save(true)
56
+ end
57
+
58
+ it "should accept hash with validation option" do
59
+ @sobj.should_receive(:valid?)
60
+ @sobj.save(:validate => true)
61
+ end
62
+
63
+ it "should not call validation when option is false" do
64
+ @sobj.should_not_receive(:valid?)
65
+ @sobj.save(false)
66
+ end
67
+
68
+ it "should not call validation when option :validate is false" do
69
+ @sobj.should_not_receive(:valid?)
70
+ @sobj.save(:validate => false)
71
+ end
72
+
73
+ it "should instantialize and save a document" do
74
+ article = Article.create(:title => 'my test')
75
+ article.title.should == 'my test'
76
+ article.should_not be_new
77
+ end
78
+
79
+ it "yields new instance to block before saving (#create)" do
80
+ article = Article.create{|a| a.title = 'my create init block test'}
81
+ article.title.should == 'my create init block test'
82
+ article.should_not be_new
83
+ end
84
+
85
+ it "yields new instance to block before saving (#create!)" do
86
+ article = Article.create{|a| a.title = 'my create bang init block test'}
87
+ article.title.should == 'my create bang init block test'
88
+ article.should_not be_new
89
+ end
90
+
91
+ it "should trigger the create callbacks" do
92
+ doc = WithCallBacks.create(:name => 'my other test')
93
+ doc.run_before_create.should be_true
94
+ doc.run_after_create.should be_true
95
+ doc.run_before_save.should be_true
96
+ doc.run_after_save.should be_true
97
+ end
98
+
99
+ end
100
+
101
+ describe "saving a model" do
102
+ before(:all) do
103
+ @sobj = Basic.new
104
+ @sobj.save.should be_true
105
+ end
106
+
107
+ it "should save the doc" do
108
+ doc = Basic.get(@sobj.id)
109
+ doc['_id'].should == @sobj.id
110
+ end
111
+
112
+ it "should be set for resaving" do
113
+ rev = @obj.rev
114
+ @sobj['another-key'] = "some value"
115
+ @sobj.save
116
+ @sobj.rev.should_not == rev
117
+ end
118
+
119
+ it "should set the id" do
120
+ @sobj.id.should be_an_instance_of(String)
121
+ end
122
+
123
+ it "should set the type" do
124
+ @sobj[@sobj.model_type_key].should == 'Basic'
125
+ end
126
+
127
+ it "should accept true or false on save for validation" do
128
+ @sobj.should_receive(:valid?)
129
+ @sobj.save(true)
130
+ end
131
+
132
+ it "should accept hash with validation option" do
133
+ @sobj.should_receive(:valid?)
134
+ @sobj.save(:validate => true)
135
+ end
136
+
137
+ it "should not call validation when option is false" do
138
+ @sobj.should_not_receive(:valid?)
139
+ @sobj.save(false)
140
+ end
141
+
142
+ it "should not call validation when option :validate is false" do
143
+ @sobj.should_not_receive(:valid?)
144
+ @sobj.save(:validate => false)
145
+ end
146
+
147
+ describe "save!" do
148
+
149
+ before(:each) do
150
+ @sobj = Card.new(:first_name => "Marcos", :last_name => "Tapajós")
151
+ end
152
+
153
+ it "should return true if save the document" do
154
+ @sobj.save!.should be_true
155
+ end
156
+
157
+ it "should raise error if don't save the document" do
158
+ @sobj.first_name = nil
159
+ lambda { @sobj.save! }.should raise_error(CouchRest::Model::Errors::Validations)
160
+ end
161
+
162
+ end
163
+ end
164
+
165
+ describe "saving a model with a unique_id configured" do
166
+ before(:each) do
167
+ @art = Article.new
168
+ @old = Article.database.get('this-is-the-title') rescue nil
169
+ Article.database.delete_doc(@old) if @old
170
+ end
171
+
172
+ it "should be a new document" do
173
+ @art.should be_new
174
+ @art.title.should be_nil
175
+ end
176
+
177
+ it "should require the title" do
178
+ lambda{@art.save}.should raise_error
179
+ @art.title = 'This is the title'
180
+ @art.save.should be_true
181
+ end
182
+
183
+ it "should not change the slug on update" do
184
+ @art.title = 'This is the title'
185
+ @art.save.should be_true
186
+ @art.title = 'new title'
187
+ @art.save.should be_true
188
+ @art.slug.should == 'this-is-the-title'
189
+ end
190
+
191
+ it "should raise an error when the slug is taken" do
192
+ @art.title = 'This is the title'
193
+ @art.save.should be_true
194
+ @art2 = Article.new(:title => 'This is the title!')
195
+ lambda{@art2.save}.should raise_error
196
+ end
197
+
198
+ it "should set the slug" do
199
+ @art.title = 'This is the title'
200
+ @art.save.should be_true
201
+ @art.slug.should == 'this-is-the-title'
202
+ end
203
+
204
+ it "should set the id" do
205
+ @art.title = 'This is the title'
206
+ @art.save.should be_true
207
+ @art.id.should == 'this-is-the-title'
208
+ end
209
+ end
210
+
211
+ describe "saving a model with a unique_id lambda" do
212
+ before(:each) do
213
+ @templated = WithTemplateAndUniqueID.new
214
+ @old = WithTemplateAndUniqueID.get('very-important') rescue nil
215
+ @old.destroy if @old
216
+ end
217
+
218
+ it "should require the field" do
219
+ lambda{@templated.save}.should raise_error
220
+ @templated['slug'] = 'very-important'
221
+ @templated.save.should be_true
222
+ end
223
+
224
+ it "should save with the id" do
225
+ @templated['slug'] = 'very-important'
226
+ @templated.save.should be_true
227
+ t = WithTemplateAndUniqueID.get('very-important')
228
+ t.should == @templated
229
+ end
230
+
231
+ it "should not change the id on update" do
232
+ @templated['slug'] = 'very-important'
233
+ @templated.save.should be_true
234
+ @templated['slug'] = 'not-important'
235
+ @templated.save.should be_true
236
+ t = WithTemplateAndUniqueID.get('very-important')
237
+ t.id.should == @templated.id
238
+ end
239
+
240
+ it "should raise an error when the id is taken" do
241
+ @templated['slug'] = 'very-important'
242
+ @templated.save.should be_true
243
+ lambda{WithTemplateAndUniqueID.new('slug' => 'very-important').save}.should raise_error
244
+ end
245
+
246
+ it "should set the id" do
247
+ @templated['slug'] = 'very-important'
248
+ @templated.save.should be_true
249
+ @templated.id.should == 'very-important'
250
+ end
251
+ end
252
+
253
+ describe "destroying an instance" do
254
+ before(:each) do
255
+ @dobj = Event.new
256
+ @dobj.save.should be_true
257
+ end
258
+ it "should return true" do
259
+ result = @dobj.destroy
260
+ result.should be_true
261
+ end
262
+ it "should make it go away" do
263
+ @dobj.destroy
264
+ lambda{Basic.get!(@dobj.id)}.should raise_error(CouchRest::Model::DocumentNotFound)
265
+ end
266
+ it "should freeze the object" do
267
+ @dobj.destroy
268
+ # In Ruby 1.9.2 this raises RuntimeError, in 1.8.7 TypeError, D'OH!
269
+ lambda { @dobj.subject = "Test" }.should raise_error(StandardError)
270
+ end
271
+ it "trying to save after should fail" do
272
+ @dobj.destroy
273
+ lambda { @dobj.save }.should raise_error(StandardError)
274
+ lambda{Basic.get!(@dobj.id)}.should raise_error(CouchRest::Model::DocumentNotFound)
275
+ end
276
+ it "should make destroyed? true" do
277
+ @dobj.destroyed?.should be_false
278
+ @dobj.destroy
279
+ @dobj.destroyed?.should be_true
280
+ end
281
+ end
282
+
283
+
284
+ describe "getting a model" do
285
+ before(:all) do
286
+ @art = Article.new(:title => 'All About Getting')
287
+ @art.save
288
+ end
289
+ it "should load and instantiate it" do
290
+ foundart = Article.get @art.id
291
+ foundart.title.should == "All About Getting"
292
+ end
293
+ it "should load and instantiate with find" do
294
+ foundart = Article.find @art.id
295
+ foundart.title.should == "All About Getting"
296
+ end
297
+ it "should return nil if `get` is used and the document doesn't exist" do
298
+ foundart = Article.get 'matt aimonetti'
299
+ foundart.should be_nil
300
+ end
301
+ it "should return nil if a blank id is requested" do
302
+ Article.get("").should be_nil
303
+ end
304
+ it "should raise an error if `get!` is used and the document doesn't exist" do
305
+ expect{ Article.get!('matt aimonetti') }.to raise_error
306
+ end
307
+ it "should raise an error if `get!` is requested with a blank id" do
308
+ expect{ Article.get!("") }.to raise_error
309
+ end
310
+ it "should raise an error if `find!` is used and the document doesn't exist" do
311
+ expect{ Article.find!('matt aimonetti') }.to raise_error
312
+ end
313
+ end
314
+
315
+ describe "getting a model with a subobjects array" do
316
+ before(:all) do
317
+ course_doc = {
318
+ "title" => "Metaphysics 200",
319
+ "questions" => [
320
+ {
321
+ "q" => "Carve the ___ of reality at the ___.",
322
+ "a" => ["beast","joints"]
323
+ },{
324
+ "q" => "Who layed the smack down on Leibniz's Law?",
325
+ "a" => "Willard Van Orman Quine"
326
+ }
327
+ ]
328
+ }
329
+ r = Course.database.save_doc course_doc
330
+ @course = Course.get r['id']
331
+ end
332
+ it "should load the course" do
333
+ @course.title.should == "Metaphysics 200"
334
+ end
335
+ it "should instantiate them as such" do
336
+ @course["questions"][0].a[0].should == "beast"
337
+ end
338
+ end
339
+
340
+ describe "callbacks" do
341
+
342
+ before(:each) do
343
+ @doc = WithCallBacks.new
344
+ end
345
+
346
+ describe "validation" do
347
+ it "should run before_validation before validating" do
348
+ @doc.run_before_validation.should be_nil
349
+ @doc.should be_valid
350
+ @doc.run_before_validation.should be_true
351
+ end
352
+ it "should run after_validation after validating" do
353
+ @doc.run_after_validation.should be_nil
354
+ @doc.should be_valid
355
+ @doc.run_after_validation.should be_true
356
+ end
357
+ end
358
+
359
+ describe "with contextual validation on ”create”" do
360
+ it "should validate only within ”create” context" do
361
+ doc = WithContextualValidationOnCreate.new
362
+ doc.save.should be_false
363
+ doc.name = "Alice"
364
+ doc.save.should be_true
365
+
366
+ doc.update_attributes(:name => nil).should be_true
367
+ end
368
+ end
369
+
370
+ describe "with contextual validation on ”update”" do
371
+ it "should validate only within ”update” context" do
372
+ doc = WithContextualValidationOnUpdate.new
373
+ doc.save.should be_true
374
+
375
+ doc.update_attributes(:name => nil).should be_false
376
+ doc.update_attributes(:name => "Bob").should be_true
377
+ end
378
+ end
379
+
380
+ describe "save" do
381
+ it "should run the after filter after saving" do
382
+ @doc.run_after_save.should be_nil
383
+ @doc.save.should be_true
384
+ @doc.run_after_save.should be_true
385
+ end
386
+ it "should run the grouped callbacks before saving" do
387
+ @doc.run_one.should be_nil
388
+ @doc.run_two.should be_nil
389
+ @doc.run_three.should be_nil
390
+ @doc.save.should be_true
391
+ @doc.run_one.should be_true
392
+ @doc.run_two.should be_true
393
+ @doc.run_three.should be_true
394
+ end
395
+ it "should not run conditional callbacks" do
396
+ @doc.run_it = false
397
+ @doc.save.should be_true
398
+ @doc.conditional_one.should be_nil
399
+ @doc.conditional_two.should be_nil
400
+ end
401
+ it "should run conditional callbacks" do
402
+ @doc.run_it = true
403
+ @doc.save.should be_true
404
+ @doc.conditional_one.should be_true
405
+ @doc.conditional_two.should be_true
406
+ end
407
+ end
408
+ describe "create" do
409
+ it "should run the before save filter when creating" do
410
+ @doc.run_before_save.should be_nil
411
+ @doc.create.should_not be_nil
412
+ @doc.run_before_save.should be_true
413
+ end
414
+ it "should run the before create filter" do
415
+ @doc.run_before_create.should be_nil
416
+ @doc.create.should_not be_nil
417
+ @doc.create
418
+ @doc.run_before_create.should be_true
419
+ end
420
+ it "should run the after create filter" do
421
+ @doc.run_after_create.should be_nil
422
+ @doc.create.should_not be_nil
423
+ @doc.create
424
+ @doc.run_after_create.should be_true
425
+ end
426
+ end
427
+ describe "update" do
428
+
429
+ before(:each) do
430
+ @doc.save
431
+ end
432
+ it "should run the before update filter when updating an existing document" do
433
+ @doc.run_before_update.should be_nil
434
+ @doc.update
435
+ @doc.run_before_update.should be_true
436
+ end
437
+ it "should run the after update filter when updating an existing document" do
438
+ @doc.run_after_update.should be_nil
439
+ @doc.update
440
+ @doc.run_after_update.should be_true
441
+ end
442
+ it "should run the before update filter when saving an existing document" do
443
+ @doc.run_before_update.should be_nil
444
+ @doc.save
445
+ @doc.run_before_update.should be_true
446
+ end
447
+
448
+ end
449
+ end
450
+
451
+
452
+ describe "#reload" do
453
+ it "reloads defined attributes" do
454
+ i = Article.create!(:title => "Reload when changed")
455
+ i.title.should == "Reload when changed"
456
+
457
+ i.title = "..."
458
+ i.title.should == "..."
459
+
460
+ i.reload
461
+ i.title.should == "Reload when changed"
462
+ end
463
+
464
+ it "reloads defined attributes set to nil" do
465
+ i = Article.create!(:title => "Reload when nil")
466
+ i.title.should == "Reload when nil"
467
+
468
+ i.title = nil
469
+ i.title.should be_nil
470
+
471
+ i.reload
472
+ i.title.should == "Reload when nil"
473
+ end
474
+
475
+ it "returns self" do
476
+ i = Article.create!(:title => "Reload return self")
477
+ i.reload.should be(i)
478
+ end
479
+ end
480
+
481
+ end