couch_potato-rails2 0.5.6

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 (88) hide show
  1. data/.gitignore +7 -0
  2. data/.travis.yml +5 -0
  3. data/CHANGES.md +148 -0
  4. data/CREDITS +6 -0
  5. data/Gemfile +4 -0
  6. data/MIT-LICENSE.txt +19 -0
  7. data/README.md +450 -0
  8. data/Rakefile +82 -0
  9. data/couch_potato.gemspec +27 -0
  10. data/init.rb +3 -0
  11. data/lib/core_ext/date.rb +14 -0
  12. data/lib/core_ext/object.rb +5 -0
  13. data/lib/core_ext/string.rb +12 -0
  14. data/lib/core_ext/symbol.rb +15 -0
  15. data/lib/core_ext/time.rb +23 -0
  16. data/lib/couch_potato.rb +48 -0
  17. data/lib/couch_potato/database.rb +179 -0
  18. data/lib/couch_potato/persistence.rb +124 -0
  19. data/lib/couch_potato/persistence/active_model_compliance.rb +44 -0
  20. data/lib/couch_potato/persistence/attachments.rb +31 -0
  21. data/lib/couch_potato/persistence/callbacks.rb +29 -0
  22. data/lib/couch_potato/persistence/dirty_attributes.rb +56 -0
  23. data/lib/couch_potato/persistence/ghost_attributes.rb +12 -0
  24. data/lib/couch_potato/persistence/json.rb +47 -0
  25. data/lib/couch_potato/persistence/magic_timestamps.rb +23 -0
  26. data/lib/couch_potato/persistence/properties.rb +79 -0
  27. data/lib/couch_potato/persistence/simple_property.rb +82 -0
  28. data/lib/couch_potato/persistence/type_caster.rb +40 -0
  29. data/lib/couch_potato/railtie.rb +25 -0
  30. data/lib/couch_potato/rspec.rb +2 -0
  31. data/lib/couch_potato/rspec/matchers.rb +39 -0
  32. data/lib/couch_potato/rspec/matchers/json2.js +482 -0
  33. data/lib/couch_potato/rspec/matchers/list_as_matcher.rb +54 -0
  34. data/lib/couch_potato/rspec/matchers/map_to_matcher.rb +49 -0
  35. data/lib/couch_potato/rspec/matchers/print_r.js +60 -0
  36. data/lib/couch_potato/rspec/matchers/reduce_to_matcher.rb +50 -0
  37. data/lib/couch_potato/rspec/stub_db.rb +46 -0
  38. data/lib/couch_potato/validation.rb +16 -0
  39. data/lib/couch_potato/validation/with_active_model.rb +27 -0
  40. data/lib/couch_potato/validation/with_validatable.rb +41 -0
  41. data/lib/couch_potato/version.rb +3 -0
  42. data/lib/couch_potato/view/base_view_spec.rb +84 -0
  43. data/lib/couch_potato/view/custom_view_spec.rb +42 -0
  44. data/lib/couch_potato/view/custom_views.rb +52 -0
  45. data/lib/couch_potato/view/lists.rb +23 -0
  46. data/lib/couch_potato/view/model_view_spec.rb +75 -0
  47. data/lib/couch_potato/view/properties_view_spec.rb +47 -0
  48. data/lib/couch_potato/view/raw_view_spec.rb +25 -0
  49. data/lib/couch_potato/view/view_query.rb +82 -0
  50. data/rails/init.rb +4 -0
  51. data/rails/reload_classes.rb +47 -0
  52. data/spec/attachments_spec.rb +23 -0
  53. data/spec/callbacks_spec.rb +297 -0
  54. data/spec/create_spec.rb +35 -0
  55. data/spec/custom_view_spec.rb +239 -0
  56. data/spec/default_property_spec.rb +38 -0
  57. data/spec/destroy_spec.rb +29 -0
  58. data/spec/fixtures/address.rb +10 -0
  59. data/spec/fixtures/person.rb +6 -0
  60. data/spec/property_spec.rb +323 -0
  61. data/spec/rails_spec.rb +50 -0
  62. data/spec/railtie_spec.rb +65 -0
  63. data/spec/spec.opts +2 -0
  64. data/spec/spec_helper.rb +44 -0
  65. data/spec/unit/active_model_compliance_spec.rb +98 -0
  66. data/spec/unit/attributes_spec.rb +135 -0
  67. data/spec/unit/base_view_spec_spec.rb +106 -0
  68. data/spec/unit/callbacks_spec.rb +46 -0
  69. data/spec/unit/couch_potato_spec.rb +39 -0
  70. data/spec/unit/create_spec.rb +69 -0
  71. data/spec/unit/custom_views_spec.rb +15 -0
  72. data/spec/unit/database_spec.rb +317 -0
  73. data/spec/unit/date_spec.rb +22 -0
  74. data/spec/unit/dirty_attributes_spec.rb +136 -0
  75. data/spec/unit/initialize_spec.rb +38 -0
  76. data/spec/unit/json_spec.rb +30 -0
  77. data/spec/unit/lists_spec.rb +20 -0
  78. data/spec/unit/model_view_spec_spec.rb +13 -0
  79. data/spec/unit/properties_view_spec_spec.rb +31 -0
  80. data/spec/unit/rspec_matchers_spec.rb +124 -0
  81. data/spec/unit/rspec_stub_db_spec.rb +35 -0
  82. data/spec/unit/string_spec.rb +7 -0
  83. data/spec/unit/time_spec.rb +15 -0
  84. data/spec/unit/validation_spec.rb +67 -0
  85. data/spec/unit/view_query_spec.rb +86 -0
  86. data/spec/update_spec.rb +40 -0
  87. data/spec/view_updates_spec.rb +28 -0
  88. metadata +243 -0
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'callbacks' do
4
+ class Tree
5
+ include CouchPotato::Persistence
6
+
7
+ before_validation :grow_leaf
8
+
9
+ property :leaf_count
10
+ property :watered
11
+
12
+ def grow_leaf
13
+ self.leaf_count ||= 0
14
+ self.leaf_count += 1
15
+ end
16
+ end
17
+
18
+ class AppleTree < Tree
19
+ attr_accessor :watered
20
+
21
+ before_validation :water
22
+
23
+ def water
24
+ self.watered = true
25
+ end
26
+
27
+ def watered?
28
+ watered
29
+ end
30
+ end
31
+
32
+ context 'inheritance' do
33
+ it "should call the callbacks of the super class" do
34
+ tree = AppleTree.new :leaf_count => 1
35
+ tree.valid?
36
+ tree.leaf_count.should == 2
37
+ end
38
+
39
+ it "should call the callbacks of the child class" do
40
+ tree = AppleTree.new :leaf_count => 1
41
+ tree.valid?
42
+ tree.should be_watered
43
+ end
44
+ end
45
+
46
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe CouchPotato, 'full_url_to_database' do
4
+ before(:each) do
5
+ @original_database_name = CouchPotato::Config.database_name
6
+ end
7
+ after(:each) do
8
+ CouchPotato::Config.database_name = @original_database_name
9
+ end
10
+
11
+ it "should add the default localhost and port if only a name is set" do
12
+ CouchPotato::Config.database_name = 'test'
13
+ CouchPotato.full_url_to_database.should == 'http://127.0.0.1:5984/test'
14
+ end
15
+
16
+ it "should return the set url" do
17
+ CouchPotato::Config.database_name = 'http://db.local/test'
18
+ CouchPotato.full_url_to_database.should == 'http://db.local/test'
19
+ end
20
+ end
21
+
22
+ describe CouchPotato, 'validation_framework' do
23
+ before(:each) do
24
+ @original_validation_framework = CouchPotato::Config.validation_framework
25
+ end
26
+ after(:each) do
27
+ CouchPotato::Config.validation_framework = @original_validation_framework
28
+ end
29
+
30
+ it "should allow setting the validation_framework to :active_model" do
31
+ CouchPotato::Config.validation_framework = :active_model
32
+ CouchPotato::Config.validation_framework.should == :active_model
33
+ end
34
+
35
+ it "should allow setting the validation_framework to :validatable" do
36
+ CouchPotato::Config.validation_framework = :validatable
37
+ CouchPotato::Config.validation_framework.should == :validatable
38
+ end
39
+ end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ describe "create" do
4
+
5
+ describe "succeeds" do
6
+ before(:each) do
7
+ Time.zone = nil
8
+ end
9
+
10
+ def create_comment
11
+ comment = Comment.new :title => 'my_title'
12
+ CouchPotato::Database.new(stub('database', :save_doc => {'rev' => '123', 'id' => '456'}, :info => nil)).save_document!(comment)
13
+ comment
14
+ end
15
+
16
+ it "should assign the id" do
17
+ create_comment._id.should == '456'
18
+ end
19
+
20
+ it "should assign the revision" do
21
+ create_comment._rev.should == '123'
22
+ end
23
+
24
+ it "should set created at in the current time zone" do
25
+ Time.zone = 'Europe/Berlin'
26
+ Timecop.travel 2010, 1, 1, 12 do
27
+ create_comment.created_at.to_s.should == '2010-01-01 12:00:00 +0100'
28
+ end
29
+ end
30
+
31
+ it "should set updated at in the current time zone" do
32
+ Time.zone = 'Europe/Berlin'
33
+ Timecop.travel 2010, 1, 1, 12 do
34
+ create_comment.updated_at.to_s.should == '2010-01-01 12:00:00 +0100'
35
+ end
36
+ end
37
+ end
38
+
39
+ describe "fails" do
40
+ before(:each) do
41
+ @comment = Comment.new
42
+ CouchPotato::Database.new(stub('database', :info => nil)).save_document(@comment)
43
+ end
44
+
45
+ it "should not assign an id" do
46
+ @comment._id.should be_nil
47
+ end
48
+
49
+ it "should not assign a revision" do
50
+ @comment._rev.should be_nil
51
+ end
52
+
53
+ it "should not set created at" do
54
+ @comment.created_at.should be_nil
55
+ end
56
+
57
+ it "should set updated at" do
58
+ @comment.updated_at.should be_nil
59
+ end
60
+
61
+ describe "with bank" do
62
+ it "should raise an exception" do
63
+ lambda {
64
+ @comment.save!
65
+ }.should raise_error
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe CouchPotato::View::CustomViews do
4
+
5
+ class MyViewSpec; end
6
+ class ModelWithView
7
+ include CouchPotato::Persistence
8
+ view :all, :type => MyViewSpec
9
+ end
10
+
11
+ it "should use a custom viewspec class" do
12
+ MyViewSpec.should_receive(:new)
13
+ ModelWithView.all
14
+ end
15
+ end
@@ -0,0 +1,317 @@
1
+ require 'spec_helper'
2
+
3
+ class DbTestUser
4
+ include CouchPotato::Persistence
5
+ end
6
+
7
+ # namespaced model
8
+ module Parent
9
+ class Child
10
+ include CouchPotato::Persistence
11
+ end
12
+ end
13
+
14
+ describe CouchPotato::Database, 'new' do
15
+ it "should raise an exception if the database doesn't exist" do
16
+ lambda {
17
+ CouchPotato::Database.new CouchRest.database('couch_potato_invalid')
18
+ }.should raise_error('Database \'couch_potato_invalid\' does not exist.')
19
+ end
20
+ end
21
+
22
+ describe CouchPotato::Database, 'full_url_to_database' do
23
+ before(:all) do
24
+ @database_url = CouchPotato::Config.database_name
25
+ end
26
+
27
+ after(:all) do
28
+ CouchPotato::Config.database_name = @database_url
29
+ end
30
+
31
+ it "should return the full URL when it starts with https" do
32
+ CouchPotato::Config.database_name = "https://example.com/database"
33
+ CouchPotato.full_url_to_database.should == 'https://example.com/database'
34
+ end
35
+
36
+ it "should return the full URL when it starts with http" do
37
+ CouchPotato::Config.database_name = "http://example.com/database"
38
+ CouchPotato.full_url_to_database.should == 'http://example.com/database'
39
+ end
40
+
41
+ it "should use localhost when no protocol was specified" do
42
+ CouchPotato::Config.database_name = "database"
43
+ CouchPotato.full_url_to_database.should == 'http://127.0.0.1:5984/database'
44
+ end
45
+ end
46
+
47
+ describe CouchPotato::Database, 'load' do
48
+ it "should raise an exception if nil given" do
49
+ db = CouchPotato::Database.new(stub('couchrest db', :info => nil))
50
+ lambda {
51
+ db.load nil
52
+ }.should raise_error("Can't load a document without an id (got nil)")
53
+ end
54
+
55
+ it "should set itself on the model" do
56
+ user = mock('user').as_null_object
57
+ DbTestUser.stub!(:new).and_return(user)
58
+ db = CouchPotato::Database.new(stub('couchrest db', :info => nil, :get => DbTestUser.json_create({JSON.create_id => 'DbTestUser'})))
59
+ user.should_receive(:database=).with(db)
60
+ db.load '1'
61
+ end
62
+
63
+ it "should load namespaced models" do
64
+ db = CouchPotato::Database.new(stub('couchrest db', :info => nil, :get => Parent::Child.json_create({JSON.create_id => 'Parent::Child'})))
65
+ db.load('1').class.should == Parent::Child
66
+ end
67
+ end
68
+
69
+ describe CouchPotato::Database, 'load!' do
70
+ it "should raise an error if no document found" do
71
+ couchrest_db = stub('couchrest db', :info => nil)
72
+ couchrest_db.stub(:get).and_raise(RestClient::ResourceNotFound)
73
+ db = CouchPotato::Database.new(couchrest_db)
74
+ lambda {
75
+ db.load! '1'
76
+ }.should raise_error(CouchPotato::NotFound)
77
+ end
78
+ end
79
+
80
+ describe CouchPotato::Database, 'save_document' do
81
+ before(:each) do
82
+ @db = CouchPotato::Database.new(stub('couchrest db').as_null_object)
83
+ end
84
+
85
+ it "should set itself on the model for a new object before doing anything else" do
86
+ @db.stub(:valid_document?).and_return false
87
+ user = stub('user', :new? => true).as_null_object
88
+ user.should_receive(:database=).with(@db)
89
+ @db.save_document user
90
+ end
91
+
92
+ class Category
93
+ include CouchPotato::Persistence
94
+ property :name
95
+ validates_presence_of :name
96
+ end
97
+
98
+ it "should return false when creating a new document and the validations failed" do
99
+ CouchPotato.database.save_document(Category.new).should == false
100
+ end
101
+
102
+ it "should return false when saving an existing document and the validations failed" do
103
+ category = Category.new(:name => "pizza")
104
+ CouchPotato.database.save_document(category).should == true
105
+ category.name = nil
106
+ CouchPotato.database.save_document(category).should == false
107
+ end
108
+
109
+ describe "when creating with validate options" do
110
+ it "should not run the validations when saved with false" do
111
+ category = Category.new
112
+ @db.save_document(category, false)
113
+ category.new?.should == false
114
+ end
115
+
116
+ it "should run the validations when saved with true" do
117
+ category = Category.new
118
+ @db.save_document(category, true)
119
+ category.new?.should == true
120
+ end
121
+
122
+ it "should run the validations when saved with default" do
123
+ category = Category.new
124
+ @db.save_document(category)
125
+ category.new?.should == true
126
+ end
127
+ end
128
+
129
+ describe "when updating with validate options" do
130
+ it "should not run the validations when saved with false" do
131
+ category = Category.new(:name => 'food')
132
+ @db.save_document(category)
133
+ category.new?.should be_false
134
+ category.name = nil
135
+ @db.save_document(category, false)
136
+ category.dirty?.should be_false
137
+ end
138
+
139
+ it "should run the validations when saved with true" do
140
+ category = Category.new(:name => "food")
141
+ @db.save_document(category)
142
+ category.new?.should == false
143
+ category.name = nil
144
+ @db.save_document(category, true)
145
+ category.dirty?.should == true
146
+ category.valid?.should == false
147
+ end
148
+
149
+ it "should run the validations when saved with default" do
150
+ category = Category.new(:name => "food")
151
+ @db.save_document(category)
152
+ category.new?.should == false
153
+ category.name = nil
154
+ @db.save_document(category)
155
+ category.dirty?.should == true
156
+ end
157
+ end
158
+
159
+ describe "when saving documents with errors set in callbacks" do
160
+ class Vulcan
161
+ include CouchPotato::Persistence
162
+ before_validation_on_create :set_errors
163
+ before_validation_on_update :set_errors
164
+
165
+ property :name
166
+ validates_presence_of :name
167
+
168
+ def set_errors
169
+ errors.add(:validation, "failed")
170
+ end
171
+ end
172
+
173
+ it "should keep errors added in before_validation_on_* callbacks when creating a new object" do
174
+ spock = Vulcan.new(:name => 'spock')
175
+ @db.save_document(spock)
176
+ spock.errors.on(:validation).should == 'failed'
177
+ end
178
+
179
+ it "should keep errors added in before_validation_on_* callbacks when creating a new object" do
180
+ spock = Vulcan.new(:name => 'spock')
181
+ @db.save_document(spock, false)
182
+ spock.new?.should == false
183
+ spock.name = "spock's father"
184
+ @db.save_document(spock)
185
+ spock.errors.on(:validation).should == 'failed'
186
+ end
187
+
188
+ it "should keep errors generated from normal validations together with errors set in normal validations" do
189
+ spock = Vulcan.new
190
+ @db.save_document(spock)
191
+ spock.errors.on(:validation).should == 'failed'
192
+ spock.errors.on(:name).should =~ /can't be (empty|blank)/
193
+ end
194
+
195
+ it "should clear errors on subsequent, valid saves when creating" do
196
+ spock = Vulcan.new
197
+ @db.save_document(spock)
198
+
199
+ spock.name = 'Spock'
200
+ @db.save_document(spock)
201
+ spock.errors.on(:name).should == nil
202
+ end
203
+
204
+ it "should clear errors on subsequent, valid saves when updating" do
205
+ spock = Vulcan.new(:name => 'spock')
206
+ @db.save_document(spock, false)
207
+
208
+ spock.name = nil
209
+ @db.save_document(spock)
210
+ spock.errors.on(:name).should =~ /can't be (empty|blank)/
211
+
212
+ spock.name = 'Spock'
213
+ @db.save_document(spock)
214
+ spock.errors.on(:name).should == nil
215
+ end
216
+
217
+ end
218
+ end
219
+
220
+ describe CouchPotato::Database, 'first' do
221
+ before(:each) do
222
+ @couchrest_db = stub('couchrest db').as_null_object
223
+ @db = CouchPotato::Database.new(@couchrest_db)
224
+ @result = stub('result')
225
+ @spec = stub('view spec', :process_results => [@result]).as_null_object
226
+ CouchPotato::View::ViewQuery.stub(:new => stub('view query', :query_view! => {'rows' => [@result]}))
227
+ end
228
+
229
+ it "should return the first result from a view query" do
230
+ @db.first(@spec).should == @result
231
+ end
232
+
233
+ it "should return nil if there are no results" do
234
+ @spec.stub(:process_results => [])
235
+ @db.first(@spec).should be_nil
236
+ end
237
+ end
238
+
239
+ describe CouchPotato::Database, 'first!' do
240
+ before(:each) do
241
+ @couchrest_db = stub('couchrest db').as_null_object
242
+ @db = CouchPotato::Database.new(@couchrest_db)
243
+ @result = stub('result')
244
+ @spec = stub('view spec', :process_results => [@result]).as_null_object
245
+ CouchPotato::View::ViewQuery.stub(:new => stub('view query', :query_view! => {'rows' => [@result]}))
246
+ end
247
+
248
+ it "should return the first result from a view query" do
249
+ @db.first!(@spec).should == @result
250
+ end
251
+
252
+ it "should raise an error if there are no results" do
253
+ @spec.stub(:process_results => [])
254
+ lambda {
255
+ @db.first!(@spec)
256
+ }.should raise_error(CouchPotato::NotFound)
257
+ end
258
+ end
259
+
260
+ describe CouchPotato::Database, 'view' do
261
+ before(:each) do
262
+ @couchrest_db = stub('couchrest db').as_null_object
263
+ @db = CouchPotato::Database.new(@couchrest_db)
264
+ @result = stub('result')
265
+ @spec = stub('view spec', :process_results => [@result]).as_null_object
266
+ CouchPotato::View::ViewQuery.stub(:new => stub('view query', :query_view! => {'rows' => [@result]}))
267
+ end
268
+
269
+ it "should initialze a view query with map/reduce/list funtions" do
270
+ @spec.stub(:design_document => 'design_doc', :view_name => 'my_view',
271
+ :map_function => '<map_code>', :reduce_function => '<reduce_code>',
272
+ :list_name => 'my_list', :list_function => '<list_code>')
273
+ CouchPotato::View::ViewQuery.should_receive(:new).with(
274
+ @couchrest_db,
275
+ 'design_doc',
276
+ {'my_view' => {
277
+ :map => '<map_code>',
278
+ :reduce => '<reduce_code>'
279
+ }},
280
+ {'my_list' => '<list_code>'})
281
+ @db.view(@spec)
282
+ end
283
+
284
+ it "should initialze a view query with only map/reduce functions" do
285
+ @spec.stub(:design_document => 'design_doc', :view_name => 'my_view',
286
+ :map_function => '<map_code>', :reduce_function => '<reduce_code>',
287
+ :list_name => nil, :list_function => nil)
288
+ CouchPotato::View::ViewQuery.should_receive(:new).with(
289
+ @couchrest_db,
290
+ 'design_doc',
291
+ {'my_view' => {
292
+ :map => '<map_code>',
293
+ :reduce => '<reduce_code>'
294
+ }}, nil)
295
+ @db.view(@spec)
296
+ end
297
+
298
+ it "should set itself on returned results that have an accessor" do
299
+ @result.stub(:respond_to?).with(:database=).and_return(true)
300
+ @result.should_receive(:database=).with(@db)
301
+ @db.view(@spec)
302
+ end
303
+
304
+ it "should not set itself on returned results that don't have an accessor" do
305
+ @result.stub(:respond_to?).with(:database=).and_return(false)
306
+ @result.should_not_receive(:database=).with(@db)
307
+ @db.view(@spec)
308
+ end
309
+
310
+ it "should not try to set itself on result sets that are not collections" do
311
+ lambda {
312
+ @spec.stub(:process_results => 1)
313
+ }.should_not raise_error
314
+
315
+ @db.view(@spec)
316
+ end
317
+ end