openlogic-couchrest_model 1.0.0

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 (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