davber_couch_potato 0.3.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 (80) hide show
  1. data/CHANGES.md +106 -0
  2. data/MIT-LICENSE.txt +19 -0
  3. data/README.md +409 -0
  4. data/VERSION.yml +5 -0
  5. data/init.rb +3 -0
  6. data/lib/core_ext/date.rb +21 -0
  7. data/lib/core_ext/object.rb +5 -0
  8. data/lib/core_ext/string.rb +8 -0
  9. data/lib/core_ext/symbol.rb +15 -0
  10. data/lib/core_ext/time.rb +21 -0
  11. data/lib/couch_potato/database.rb +161 -0
  12. data/lib/couch_potato/persistence/active_model_compliance.rb +44 -0
  13. data/lib/couch_potato/persistence/attachments.rb +31 -0
  14. data/lib/couch_potato/persistence/callbacks.rb +62 -0
  15. data/lib/couch_potato/persistence/dirty_attributes.rb +56 -0
  16. data/lib/couch_potato/persistence/ghost_attributes.rb +22 -0
  17. data/lib/couch_potato/persistence/json.rb +46 -0
  18. data/lib/couch_potato/persistence/magic_timestamps.rb +20 -0
  19. data/lib/couch_potato/persistence/properties.rb +86 -0
  20. data/lib/couch_potato/persistence/simple_property.rb +72 -0
  21. data/lib/couch_potato/persistence/type_caster.rb +40 -0
  22. data/lib/couch_potato/persistence.rb +105 -0
  23. data/lib/couch_potato/railtie.rb +18 -0
  24. data/lib/couch_potato/rspec/matchers/json2.js +482 -0
  25. data/lib/couch_potato/rspec/matchers/list_as_matcher.rb +54 -0
  26. data/lib/couch_potato/rspec/matchers/map_to_matcher.rb +49 -0
  27. data/lib/couch_potato/rspec/matchers/print_r.js +60 -0
  28. data/lib/couch_potato/rspec/matchers/reduce_to_matcher.rb +50 -0
  29. data/lib/couch_potato/rspec/matchers.rb +39 -0
  30. data/lib/couch_potato/rspec/stub_db.rb +46 -0
  31. data/lib/couch_potato/rspec.rb +2 -0
  32. data/lib/couch_potato/validation/with_active_model.rb +27 -0
  33. data/lib/couch_potato/validation/with_validatable.rb +37 -0
  34. data/lib/couch_potato/validation.rb +16 -0
  35. data/lib/couch_potato/view/base_view_spec.rb +67 -0
  36. data/lib/couch_potato/view/custom_view_spec.rb +42 -0
  37. data/lib/couch_potato/view/custom_views.rb +52 -0
  38. data/lib/couch_potato/view/lists.rb +23 -0
  39. data/lib/couch_potato/view/model_view_spec.rb +75 -0
  40. data/lib/couch_potato/view/properties_view_spec.rb +47 -0
  41. data/lib/couch_potato/view/raw_view_spec.rb +25 -0
  42. data/lib/couch_potato/view/view_query.rb +78 -0
  43. data/lib/couch_potato.rb +79 -0
  44. data/rails/init.rb +4 -0
  45. data/rails/reload_classes.rb +47 -0
  46. data/spec/attachments_spec.rb +23 -0
  47. data/spec/callbacks_spec.rb +308 -0
  48. data/spec/create_spec.rb +34 -0
  49. data/spec/custom_view_spec.rb +239 -0
  50. data/spec/default_property_spec.rb +38 -0
  51. data/spec/destroy_spec.rb +29 -0
  52. data/spec/fixtures/address.rb +10 -0
  53. data/spec/fixtures/person.rb +6 -0
  54. data/spec/property_spec.rb +315 -0
  55. data/spec/rails_spec.rb +51 -0
  56. data/spec/spec.opts +4 -0
  57. data/spec/spec_helper.rb +47 -0
  58. data/spec/unit/active_model_compliance_spec.rb +98 -0
  59. data/spec/unit/attributes_spec.rb +125 -0
  60. data/spec/unit/base_view_spec_spec.rb +73 -0
  61. data/spec/unit/callbacks_spec.rb +72 -0
  62. data/spec/unit/couch_potato_spec.rb +39 -0
  63. data/spec/unit/create_spec.rb +58 -0
  64. data/spec/unit/custom_views_spec.rb +15 -0
  65. data/spec/unit/database_spec.rb +266 -0
  66. data/spec/unit/date_spec.rb +22 -0
  67. data/spec/unit/dirty_attributes_spec.rb +166 -0
  68. data/spec/unit/json_create_id_spec.rb +14 -0
  69. data/spec/unit/lists_spec.rb +20 -0
  70. data/spec/unit/model_view_spec_spec.rb +13 -0
  71. data/spec/unit/properties_view_spec_spec.rb +31 -0
  72. data/spec/unit/rspec_matchers_spec.rb +124 -0
  73. data/spec/unit/rspec_stub_db_spec.rb +35 -0
  74. data/spec/unit/string_spec.rb +7 -0
  75. data/spec/unit/time_spec.rb +22 -0
  76. data/spec/unit/validation_spec.rb +67 -0
  77. data/spec/unit/view_query_spec.rb +78 -0
  78. data/spec/update_spec.rb +40 -0
  79. data/spec/view_updates_spec.rb +28 -0
  80. metadata +205 -0
@@ -0,0 +1,78 @@
1
+ module CouchPotato
2
+ module View
3
+ # Used to query views (and create them if they don't exist). Usually you won't have to use this class directly. Instead it is used internally by the CouchPotato::Database.view method.
4
+ class ViewQuery
5
+ def initialize(couchrest_database, design_document_name, view, list = nil)
6
+ @database = couchrest_database
7
+ @design_document_name = design_document_name
8
+ @view_name = view.keys[0]
9
+ @map_function = view.values[0][:map]
10
+ @reduce_function = view.values[0][:reduce]
11
+ if list
12
+ @list_function = list.values[0]
13
+ @list_name = list.keys[0]
14
+ end
15
+ end
16
+
17
+ def query_view!(parameters = {})
18
+ update_view unless view_has_been_updated?
19
+ begin
20
+ query_view parameters
21
+ rescue RestClient::ResourceNotFound
22
+ update_view
23
+ retry
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def update_view
30
+ design_doc = @database.get "_design/#{@design_document_name}" rescue nil
31
+ original_views = design_doc && design_doc['views'].dup
32
+ original_lists = design_doc && design_doc['lists'] && design_doc['lists'].dup
33
+ view_updated unless design_doc.nil?
34
+ design_doc ||= empty_design_document
35
+ design_doc['views'][@view_name.to_s] = view_functions
36
+ if @list_function
37
+ design_doc['lists'] ||= {}
38
+ design_doc['lists'][@list_name.to_s] = @list_function
39
+ end
40
+ @database.save_doc(design_doc) if original_views != design_doc['views'] || original_lists != design_doc['lists']
41
+ end
42
+
43
+ def view_functions
44
+ {'map' => @map_function, 'reduce' => @reduce_function}
45
+ end
46
+
47
+ def empty_design_document
48
+ {'views' => {}, 'lists' => {}, "_id" => "_design/#{@design_document_name}", "language" => "javascript"}
49
+ end
50
+
51
+ def view_has_been_updated?
52
+ updated_views[[@design_document_name, @view_name]]
53
+ end
54
+
55
+ def view_updated
56
+ updated_views[[@design_document_name, @view_name]] = true
57
+ end
58
+
59
+ def updated_views
60
+ @@updated_views ||= {}
61
+ @@updated_views
62
+ end
63
+
64
+ def query_view(parameters)
65
+ if @list_name
66
+ CouchRest.get CouchRest.paramify_url(CouchPotato.full_url_to_database + "/_design/#{@design_document_name}/_list/#{@list_name}/#{@view_name}", parameters)
67
+ else
68
+ @database.view view_url, parameters
69
+ end
70
+ end
71
+
72
+ def view_url
73
+ "#{@design_document_name}/#{@view_name}"
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,79 @@
1
+ require 'couchrest'
2
+ require 'json'
3
+ require 'json/add/core'
4
+ require 'json/add/rails'
5
+
6
+ require 'ostruct'
7
+
8
+ unless defined?(CouchPotato)
9
+ module CouchPotato
10
+ DEFAULT_TYPE_FIELD = 'ruby_class'
11
+
12
+ # The name of the type field of CouchDB documents
13
+ @@type_field = DEFAULT_TYPE_FIELD
14
+ # The function mapping classes to the corresponding CouchDB design document.
15
+ @@design_name_fun = lambda do |klass|
16
+ klass_name = klass.to_s
17
+ klass_name.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
18
+ klass_name.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
19
+ klass_name.tr!("-", "_")
20
+ klass_name.downcase
21
+ end
22
+
23
+ # Get the type field name to use.
24
+ # NOTE: this is universal, so will transcend individual databases
25
+ def self.type_field
26
+ @@type_field
27
+ end
28
+
29
+ def self.type_field= type_field
30
+ @@type_field = type_field
31
+ end
32
+
33
+ # Get the lambda to use for conversion from a class to the design document name
34
+ def self.design_name_fun
35
+ @@design_name_fun
36
+ end
37
+
38
+ def self.design_name_fun= fun
39
+ @@design_name_fun = fun
40
+ end
41
+
42
+ Config = Struct.new(:database_name, :validation_framework).new
43
+ Config.validation_framework = :validatable # default to the validatable gem for validations
44
+
45
+ # Returns a database instance which you can then use to create objects and query views. You have to set the CouchPotato::Config.database_name before this works.
46
+ def self.database
47
+ @@__database ||= Database.new(self.couchrest_database)
48
+ end
49
+
50
+ # Returns the underlying CouchRest database object if you want low level access to your CouchDB. You have to set the CouchPotato::Config.database_name before this works.
51
+ def self.couchrest_database
52
+ @@__couchrest_database ||= CouchRest.database(full_url_to_database)
53
+ end
54
+
55
+ private
56
+
57
+ def self.full_url_to_database
58
+ raise('No Database configured. Set CouchPotato::Config.database_name') unless CouchPotato::Config.database_name
59
+ if CouchPotato::Config.database_name.match(%r{https?://})
60
+ CouchPotato::Config.database_name
61
+ else
62
+ "http://127.0.0.1:5984/#{CouchPotato::Config.database_name}"
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ JSON.create_id = CouchPotato.type_field
69
+
70
+ $LOAD_PATH << File.dirname(__FILE__)
71
+
72
+ require 'core_ext/object'
73
+ require 'core_ext/time'
74
+ require 'core_ext/date'
75
+ require 'core_ext/string'
76
+ require 'core_ext/symbol'
77
+ require 'couch_potato/validation'
78
+ require 'couch_potato/persistence'
79
+ require 'couch_potato/railtie' if defined?(Rails)
data/rails/init.rb ADDED
@@ -0,0 +1,4 @@
1
+ # this is for rails only
2
+
3
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/couch_potato')
4
+ Rails.logger.info "** couch_potato: initialized from #{__FILE__}"
@@ -0,0 +1,47 @@
1
+ module CouchPotato
2
+
3
+ module ClassReloading
4
+ private
5
+
6
+ def with_class_reloading(&block)
7
+ begin
8
+ yield
9
+ rescue ArgumentError => e
10
+ if(name = e.message.scan(/(can't find const|undefined class\/module) ([\w\:]+)/).first[1])
11
+ eval name.gsub(/\:+$/, '')
12
+ retry
13
+ else
14
+ raise e
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ View::ViewQuery.class_eval do
21
+ include ClassReloading
22
+
23
+ def query_view_with_class_reloading(*args)
24
+ with_class_reloading do
25
+ query_view_without_class_reloading(*args)
26
+ end
27
+ end
28
+
29
+ alias_method :query_view_without_class_reloading, :query_view
30
+ alias_method :query_view, :query_view_with_class_reloading
31
+ end
32
+
33
+ Database.class_eval do
34
+ include ClassReloading
35
+
36
+ def load_document_with_class_reloading(*args)
37
+ with_class_reloading do
38
+ load_document_without_class_reloading *args
39
+ end
40
+ end
41
+
42
+ alias_method :load_document_without_class_reloading, :load_document
43
+ alias_method :load_document, :load_document_with_class_reloading
44
+ alias_method :load, :load_document
45
+ end
46
+ end
47
+
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe CouchPotato, 'attachments' do
4
+ it "should persist an attachment" do
5
+ comment = Comment.new :title => 'nil'
6
+ comment._attachments['body'] = {'data' => 'a useful comment', 'content_type' => 'text/plain'}
7
+ CouchPotato.database.save! comment
8
+ CouchPotato.couchrest_database.fetch_attachment(comment.to_hash, 'body').to_s.should == 'a useful comment'
9
+ end
10
+
11
+ it "should give me information about the attachments of a document" do
12
+ comment = Comment.new :title => 'nil'
13
+ comment._attachments = {'body' => {'data' => 'a useful comment', 'content_type' => 'text/plain'}}
14
+ CouchPotato.database.save! comment
15
+ comment_reloaded = CouchPotato.database.load comment.id
16
+ comment_reloaded._attachments["body"].should include({"content_type" => "text/plain", "stub" => true, "length" => 16})
17
+ end
18
+
19
+ it "should have an empty array for a new object" do
20
+ Comment.new._attachments.should == {}
21
+ end
22
+
23
+ end
@@ -0,0 +1,308 @@
1
+ require 'spec_helper'
2
+
3
+ class CallbackRecorder
4
+ include CouchPotato::Persistence
5
+
6
+ property :required_property
7
+
8
+ validates_presence_of :required_property
9
+
10
+ [:before_validation, :before_validation_on_create,
11
+ :before_validation_on_save, :before_validation_on_update,
12
+ :before_save, :before_create, :before_create,
13
+ :after_save, :after_create, :after_create,
14
+ :before_update, :after_update,
15
+ :before_destroy, :after_destroy
16
+ ].each do |callback|
17
+ define_method callback do
18
+ callbacks << callback
19
+ end
20
+ self.send callback, callback
21
+ end
22
+
23
+ view :all, :key => :required_property
24
+
25
+ attr_accessor :lambda_works
26
+ before_create lambda {|model| model.lambda_works = true }
27
+
28
+ def callbacks
29
+ @callbacks ||= []
30
+ end
31
+
32
+ private
33
+
34
+ def method_callback_with_argument(db)
35
+ db.view CallbackRecorder.all
36
+ end
37
+
38
+ end
39
+
40
+ describe "multiple callbacks at once" do
41
+
42
+ class Monkey
43
+ include CouchPotato::Persistence
44
+ attr_accessor :eaten_banana, :eaten_apple
45
+
46
+ before_create :eat_apple, :eat_banana
47
+
48
+ private
49
+
50
+ def eat_banana
51
+ self.eaten_banana = true
52
+ end
53
+
54
+ def eat_apple
55
+ self.eaten_apple = true
56
+ end
57
+ end
58
+
59
+ it "should run all callback methods given to the callback method call" do
60
+ monkey = Monkey.new
61
+ monkey.run_callbacks :before_create
62
+ monkey.eaten_banana.should be_true
63
+ monkey.eaten_apple.should be_true
64
+ end
65
+ end
66
+
67
+ describe 'create callbacks' do
68
+
69
+ before(:each) do
70
+ @recorder = CallbackRecorder.new
71
+ couchrest_database = stub 'couchrest_database', :save_doc => {'id' => '1', 'rev' => '2'}, :view => {'rows' => []}, :info => nil
72
+ @db = CouchPotato::Database.new(couchrest_database)
73
+ end
74
+
75
+ describe "successful create" do
76
+ before(:each) do
77
+ @recorder.required_property = 1
78
+ end
79
+
80
+ it "should call before_validation" do
81
+ @recorder.valid?
82
+ @recorder.callbacks.should include(:before_validation)
83
+ end
84
+
85
+ it "should call before_validation_on_create" do
86
+ @db.save_document! @recorder
87
+ @recorder.callbacks.should include(:before_validation_on_create)
88
+ end
89
+
90
+ it "should call before_validation_on_save" do
91
+ @db.save_document! @recorder
92
+ @recorder.callbacks.should include(:before_validation_on_save)
93
+ end
94
+
95
+ it "should call before_save" do
96
+ @db.save_document! @recorder
97
+ @recorder.callbacks.should include(:before_save)
98
+ end
99
+
100
+ it "should call after_save" do
101
+ @db.save_document! @recorder
102
+ @recorder.callbacks.should include(:after_save)
103
+ end
104
+
105
+ it "should call before_create" do
106
+ @db.save_document! @recorder
107
+ @recorder.callbacks.should include(:before_create)
108
+ end
109
+
110
+ it "should call after_create" do
111
+ @db.save_document! @recorder
112
+ @recorder.callbacks.should include(:after_create)
113
+ end
114
+
115
+ end
116
+
117
+ describe "failed create" do
118
+
119
+ it "should call before_validation" do
120
+ @recorder.valid?
121
+ @recorder.callbacks.should include(:before_validation)
122
+ end
123
+
124
+ it "should call before_validation_on_create" do
125
+ @db.save_document @recorder
126
+ @recorder.callbacks.should include(:before_validation_on_create)
127
+ end
128
+
129
+ it "should call before_validation_on_save" do
130
+ @db.save_document @recorder
131
+ @recorder.callbacks.should include(:before_validation_on_save)
132
+ end
133
+
134
+ it "should not call before_save" do
135
+ @db.save_document @recorder
136
+ @recorder.callbacks.should_not include(:before_save)
137
+ end
138
+
139
+ it "should not call after_save" do
140
+ @db.save_document @recorder
141
+ @recorder.callbacks.should_not include(:after_save)
142
+ end
143
+
144
+ it "should not call before_create" do
145
+ @db.save_document @recorder
146
+ @recorder.callbacks.should_not include(:before_create)
147
+ end
148
+
149
+ it "should not call after_create" do
150
+ @db.save_document @recorder
151
+ @recorder.callbacks.should_not include(:after_create)
152
+ end
153
+ end
154
+ end
155
+
156
+ describe "update callbacks" do
157
+
158
+ before(:each) do
159
+ @recorder = CallbackRecorder.new :required_property => 1
160
+
161
+ couchrest_database = stub 'couchrest_database', :save_doc => {'id' => '1', 'rev' => '2'}, :view => {'rows' => []}, :info => nil
162
+ @db = CouchPotato::Database.new(couchrest_database)
163
+ @db.save_document! @recorder
164
+
165
+ @recorder.required_property = 2
166
+ @recorder.callbacks.clear
167
+ end
168
+
169
+ describe "successful update" do
170
+
171
+ before(:each) do
172
+ @db.save_document! @recorder
173
+ end
174
+
175
+ it "should call before_validation" do
176
+ @recorder.callbacks.should include(:before_validation)
177
+ end
178
+
179
+ it "should call before_validation_on_update" do
180
+ @recorder.callbacks.should include(:before_validation_on_update)
181
+ end
182
+
183
+ it "should call before_validation_on_save" do
184
+ @recorder.callbacks.should include(:before_validation_on_save)
185
+ end
186
+
187
+ it "should call before_save" do
188
+ @recorder.callbacks.should include(:before_save)
189
+ end
190
+
191
+ it "should call after_save" do
192
+ @recorder.callbacks.should include(:after_save)
193
+ end
194
+
195
+ it "should call before_update" do
196
+ @recorder.callbacks.should include(:before_update)
197
+ end
198
+
199
+ it "should call after_update" do
200
+ @recorder.callbacks.should include(:after_update)
201
+ end
202
+
203
+ end
204
+
205
+ describe "failed update" do
206
+
207
+ before(:each) do
208
+ @recorder.required_property = nil
209
+ @db.save_document @recorder
210
+ end
211
+
212
+ it "should call before_validation" do
213
+ @recorder.callbacks.should include(:before_validation)
214
+ end
215
+
216
+ it "should call before_validation_on_update" do
217
+ @recorder.callbacks.should include(:before_validation_on_update)
218
+ end
219
+
220
+ it "should call before_validation_on_save" do
221
+ @recorder.callbacks.should include(:before_validation_on_save)
222
+ end
223
+
224
+ it "should not call before_save" do
225
+ @recorder.callbacks.should_not include(:before_save)
226
+ end
227
+
228
+ it "should not call after_save" do
229
+ @recorder.callbacks.should_not include(:after_save)
230
+ end
231
+
232
+ it "should not call before_update" do
233
+ @recorder.callbacks.should_not include(:before_update)
234
+ end
235
+
236
+ it "should not call after_update" do
237
+ @recorder.callbacks.should_not include(:after_update)
238
+ end
239
+
240
+ end
241
+
242
+ end
243
+
244
+ describe "destroy callbacks" do
245
+
246
+ before(:each) do
247
+ @recorder = CallbackRecorder.new :required_property => 1
248
+ couchrest_database = stub 'couchrest_database', :save_doc => {'id' => '1', 'rev' => '2'}, :delete_doc => nil, :view => {'rows' => []}, :info => nil
249
+ @db = CouchPotato::Database.new(couchrest_database)
250
+ @db.save_document! @recorder
251
+
252
+ @recorder.callbacks.clear
253
+ end
254
+
255
+ it "should call before_destroy" do
256
+ @db.destroy_document @recorder
257
+ @recorder.callbacks.should include(:before_destroy)
258
+ end
259
+
260
+ it "should call after_destroy" do
261
+ @db.destroy_document @recorder
262
+ @recorder.callbacks.should include(:after_destroy)
263
+ end
264
+ end
265
+
266
+ describe "lambda callbacks" do
267
+ it "should run the lambda" do
268
+ recorder = CallbackRecorder.new
269
+ recorder.run_callbacks :before_create
270
+ recorder.lambda_works.should be_true
271
+ end
272
+ end
273
+
274
+ describe "validation callbacks" do
275
+ class ValidatedUser
276
+ include CouchPotato::Persistence
277
+
278
+ property :name
279
+ before_validation :check_name
280
+ validates_presence_of :name
281
+
282
+ def check_name
283
+ errors.add(:name, 'should be Paul') unless name == "Paul"
284
+ end
285
+ end
286
+
287
+ it "should keep error messages set in custom before_validation filters" do
288
+ user = ValidatedUser.new(:name => "john")
289
+ user.valid?.should == false
290
+ user.errors.on(:name).should == "should be Paul"
291
+ end
292
+
293
+ it "should combine the errors from validations and callbacks" do
294
+ user = ValidatedUser.new(:name => nil)
295
+ user.valid?.should == false
296
+ user.errors.on(:name).any? {|msg| msg =~ /can't be (empty|blank)/ }.should == true
297
+ user.errors.on(:name).any? {|msg| msg == "should be Paul" }.should == true
298
+ user.errors.on(:name).size.should == 2
299
+ end
300
+
301
+ it "should clear the errors on subsequent calls to valid?" do
302
+ user = ValidatedUser.new(:name => nil)
303
+ user.valid?.should == false
304
+ user.name = 'Paul'
305
+ user.valid?.should == true
306
+ user.errors.on(:name).should == nil
307
+ end
308
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe "create" do
4
+ before(:all) do
5
+ recreate_db
6
+ end
7
+ describe "succeeds" do
8
+ it "should store the class" do
9
+ @comment = Comment.new :title => 'my_title'
10
+ CouchPotato.database.save_document! @comment
11
+ CouchPotato.couchrest_database.get(@comment.id).send(JSON.create_id).should == 'Comment'
12
+ end
13
+
14
+ it "should persist a given created_at" do
15
+ @comment = Comment.new :created_at => Time.parse('2010-01-02 12:34:48 +0000'), :title => '-'
16
+ CouchPotato.database.save_document! @comment
17
+ CouchPotato.couchrest_database.get(@comment.id).created_at.should == Time.parse('2010-01-02 12:34:48 +0000')
18
+ end
19
+
20
+ it "should persist a given updated_at" do
21
+ @comment = Comment.new :updated_at => Time.parse('2010-01-02 12:34:48 +0000'), :title => '-'
22
+ CouchPotato.database.save_document! @comment
23
+ CouchPotato.couchrest_database.get(@comment.id).updated_at.should == Time.parse('2010-01-02 12:34:48 +0000')
24
+ end
25
+ end
26
+ describe "fails" do
27
+ it "should not store anything" do
28
+ @comment = Comment.new
29
+ CouchPotato.database.save_document @comment
30
+ CouchPotato.couchrest_database.documents['rows'].should be_empty
31
+ end
32
+ end
33
+ end
34
+