couch_tomato 0.1.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 (52) hide show
  1. data/MIT-LICENSE.txt +19 -0
  2. data/README.md +96 -0
  3. data/init.rb +3 -0
  4. data/lib/core_ext/date.rb +10 -0
  5. data/lib/core_ext/duplicable.rb +43 -0
  6. data/lib/core_ext/extract_options.rb +14 -0
  7. data/lib/core_ext/inheritable_attributes.rb +222 -0
  8. data/lib/core_ext/object.rb +5 -0
  9. data/lib/core_ext/string.rb +19 -0
  10. data/lib/core_ext/symbol.rb +15 -0
  11. data/lib/core_ext/time.rb +12 -0
  12. data/lib/couch_tomato/database.rb +279 -0
  13. data/lib/couch_tomato/js_view_source.rb +182 -0
  14. data/lib/couch_tomato/migration.rb +52 -0
  15. data/lib/couch_tomato/migrator.rb +235 -0
  16. data/lib/couch_tomato/persistence/base.rb +62 -0
  17. data/lib/couch_tomato/persistence/belongs_to_property.rb +58 -0
  18. data/lib/couch_tomato/persistence/callbacks.rb +60 -0
  19. data/lib/couch_tomato/persistence/dirty_attributes.rb +27 -0
  20. data/lib/couch_tomato/persistence/json.rb +48 -0
  21. data/lib/couch_tomato/persistence/magic_timestamps.rb +15 -0
  22. data/lib/couch_tomato/persistence/properties.rb +58 -0
  23. data/lib/couch_tomato/persistence/simple_property.rb +97 -0
  24. data/lib/couch_tomato/persistence/validation.rb +18 -0
  25. data/lib/couch_tomato/persistence.rb +85 -0
  26. data/lib/couch_tomato/replicator.rb +50 -0
  27. data/lib/couch_tomato.rb +46 -0
  28. data/lib/tasks/couch_tomato.rake +128 -0
  29. data/rails/init.rb +7 -0
  30. data/spec/callbacks_spec.rb +271 -0
  31. data/spec/comment.rb +8 -0
  32. data/spec/create_spec.rb +22 -0
  33. data/spec/custom_view_spec.rb +134 -0
  34. data/spec/destroy_spec.rb +29 -0
  35. data/spec/fixtures/address.rb +9 -0
  36. data/spec/fixtures/person.rb +6 -0
  37. data/spec/property_spec.rb +103 -0
  38. data/spec/spec_helper.rb +40 -0
  39. data/spec/unit/attributes_spec.rb +26 -0
  40. data/spec/unit/callbacks_spec.rb +33 -0
  41. data/spec/unit/create_spec.rb +58 -0
  42. data/spec/unit/customs_views_spec.rb +15 -0
  43. data/spec/unit/database_spec.rb +38 -0
  44. data/spec/unit/dirty_attributes_spec.rb +113 -0
  45. data/spec/unit/string_spec.rb +13 -0
  46. data/spec/unit/view_query_spec.rb +9 -0
  47. data/spec/update_spec.rb +40 -0
  48. data/test/test_helper.rb +63 -0
  49. data/test/unit/database_test.rb +285 -0
  50. data/test/unit/js_view_test.rb +362 -0
  51. data/test/unit/property_test.rb +193 -0
  52. metadata +133 -0
@@ -0,0 +1,85 @@
1
+ require 'digest/md5'
2
+ require File.dirname(__FILE__) + '/database'
3
+ require File.dirname(__FILE__) + '/persistence/properties'
4
+ require File.dirname(__FILE__) + '/persistence/base'
5
+ require File.dirname(__FILE__) + '/persistence/magic_timestamps'
6
+ require File.dirname(__FILE__) + '/persistence/callbacks'
7
+ require File.dirname(__FILE__) + '/persistence/json'
8
+ require File.dirname(__FILE__) + '/persistence/dirty_attributes'
9
+ require File.dirname(__FILE__) + '/persistence/validation'
10
+
11
+
12
+
13
+ module CouchTomato
14
+ module Persistence
15
+ module Nested
16
+ include CouchTomato::Persistence::Base
17
+
18
+ def self.included(base)
19
+ base.send :include, Properties, Callbacks, Validation#, Json#, CouchTomato::View::CustomViews
20
+ # base.send :include, DirtyAttributes
21
+ # base.send :include, MagicTimestamps
22
+
23
+ base.extend ClassMethods
24
+ end
25
+
26
+ def to_json(*args)
27
+ to_hash.to_json(*args)
28
+ # to_json(*args)
29
+ end
30
+
31
+ # returns all the attributes, the ruby class and the _id and _rev of a model as a Hash
32
+ def to_hash
33
+ (self.class.properties).inject({}) do |props, property|
34
+ property.serialize(props, self)
35
+ props
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ module ClassMethods
42
+ # creates a model instance from JSON
43
+ def json_create(json, meta={})
44
+ return if json.nil?
45
+ instance = self.new
46
+ # instance._id = json[:_id] || json['_id']
47
+ # instance._rev = json[:_rev] || json['_rev']
48
+ properties.each do |property|
49
+ property.build(instance, json)
50
+ end
51
+ instance
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ include CouchTomato::Persistence::Base
58
+
59
+ def self.included(base)
60
+ base.send :include, Properties, Callbacks, Validation, Json#, CouchTomato::View::CustomViews
61
+ # base.send :include, DirtyAttributes
62
+ base.send :include, MagicTimestamps
63
+ base.class_eval do
64
+ attr_accessor :_id, :_rev, :_attachments, :_deleted
65
+ attr_accessor :metadata
66
+ alias_method :id, :_id
67
+ end
68
+ end
69
+
70
+ # returns true if a model hasn't been saved yet, false otherwise
71
+ def new?
72
+ _rev.nil?
73
+ end
74
+ alias_method :new_record?, :new?
75
+
76
+ # returns the document id
77
+ # this is used by rails to construct URLs
78
+ # can be overridden to for example use slugs for URLs instead if ids
79
+ def to_param
80
+ _id
81
+ end
82
+
83
+ end
84
+
85
+ end
@@ -0,0 +1,50 @@
1
+ module CouchTomato
2
+ class Replicator
3
+ # Timeout for a single database replication.
4
+ READ_TIMEOUT = 24 * 60 * 60 # 24 hours in seconds
5
+
6
+ def initialize(src_server, dst_server = nil)
7
+ @src_server = CouchRest::Server.new(src_server)
8
+ @dst_server = dst_server ? CouchRest::Server.new(dst_server) : @src_server
9
+
10
+ @db_names = @src_server.databases
11
+ end
12
+
13
+ def replicate(src_db_name, dst_db_name)
14
+ raise "Source database '#{src_db_name}' does not exist" unless @db_names.include?(src_db_name)
15
+
16
+ @dst_server.database!(dst_db_name)
17
+
18
+ src_uri = URI.parse(@src_server.uri)
19
+ dst_uri = URI.parse(@dst_server.uri)
20
+
21
+ http = Net::HTTP.new(dst_uri.host, dst_uri.port)
22
+ http.read_timeout = READ_TIMEOUT
23
+ http.post('/_replicate', "{\"source\": \"#{src_uri}/#{src_db_name}\", \"target\": \"#{dst_uri}/#{dst_db_name}\"}")
24
+ end
25
+
26
+ def replicate_all(suffix = nil)
27
+ @db_names.each do |db_name|
28
+ replicate(db_name, "#{db_name}#{suffix}")
29
+ end
30
+ end
31
+
32
+ def replicate_env!(from_env, to_env, prefix=nil)
33
+ source_dbs = @db_names.select do |e|
34
+ if prefix
35
+ e =~ /^#{prefix}_/ && e =~ /_#{from_env}$/
36
+ else
37
+ e =~ /_#{from_env}$/
38
+ end
39
+ end
40
+
41
+ source_dbs.each do |source_db|
42
+ target_db = source_db.gsub(/_#{from_env}$/, "_#{to_env}")
43
+
44
+ puts "Recreating #{target_db}"
45
+ CouchRest::Database.new(@dst_server, target_db).recreate!
46
+ replicate(source_db, target_db)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,46 @@
1
+ require 'couchrest'
2
+ require 'json'
3
+ require 'json/add/core'
4
+ require 'json/add/rails'
5
+
6
+ # require 'ostruct'
7
+
8
+
9
+ module CouchTomato
10
+ # Config = OpenStruct.new
11
+
12
+ # Returns a database instance which you can then use to create objects and query views.
13
+ # You have to set the CouchTomato::Config.database_name before this works.
14
+
15
+ # def self.database
16
+ # @@__database ||= Database.new(self.couchrest_database)
17
+ # end
18
+
19
+ # Returns the underlying CouchRest database object if you want low level access to your CouchDB.
20
+ # You have to set the CouchTomato::Config.database_name before this works.
21
+ # def self.couchrest_database
22
+ # @@__couchrest_database ||= CouchRest.database(full_url_to_database)
23
+ # end
24
+
25
+ # private
26
+
27
+ # def self.full_url_to_database
28
+ # raise('No Database configured. Set CouchTomato::Config.database_name') unless CouchTomato::Config.database_name
29
+ # if CouchTomato::Config.database_server
30
+ # return "#{CouchTomato::Config.database_server}#{CouchTomato::Config.database_name}"
31
+ # else
32
+ # return "http://127.0.0.1:5984/#{CouchTomato::Config.database_name}"
33
+ # end
34
+ # end
35
+ end
36
+
37
+ require File.dirname(__FILE__) + '/core_ext/object'
38
+ require File.dirname(__FILE__) + '/core_ext/time'
39
+ require File.dirname(__FILE__) + '/core_ext/date'
40
+ require File.dirname(__FILE__) + '/core_ext/string'
41
+ require File.dirname(__FILE__) + '/core_ext/symbol'
42
+ require File.dirname(__FILE__) + '/core_ext/extract_options'
43
+ require File.dirname(__FILE__) + '/core_ext/duplicable'
44
+ require File.dirname(__FILE__) + '/core_ext/inheritable_attributes'
45
+ require File.dirname(__FILE__) + '/couch_tomato/persistence'
46
+ require File.dirname(__FILE__) + '/couch_tomato/js_view_source'
@@ -0,0 +1,128 @@
1
+ namespace :couch_tomato do
2
+ desc 'Inserts the views into CouchDB'
3
+ task :push => :environment do
4
+ CouchTomato::JsViewSource.push
5
+ end
6
+
7
+ desc 'Compares views in DB and the File System'
8
+ task :diff => :environment do
9
+ CouchTomato::JsViewSource.diff
10
+ end
11
+
12
+ desc 'Drops databases for the current RAILS_ENV'
13
+ task :drop => :environment do
14
+ databases do |db, dir|
15
+ db.delete!
16
+ end
17
+ end
18
+
19
+ desc 'Runs migrations'
20
+ task :migrate => :environment do
21
+ databases do |db, dir|
22
+ CouchTomato::Migrator.migrate(db, dir, ENV['VERSION'] ? ENV['VERSION'].to_i : nil)
23
+ end
24
+ end
25
+
26
+ namespace :migrate do
27
+ desc 'Rollbacks the database one migration and re migrate up. If you want to rollback more than one step, define STEP=x. Target specific version with VERSION=x.'
28
+ task :redo => :environment do
29
+ if ENV['VERSION']
30
+ Rake::Task['couch_tomato:migrate:down'].invoke
31
+ Rake::Task['couch_tomato:migrate:up'].invoke
32
+ else
33
+ Rake::Task['couch_tomato:rollback'].invoke
34
+ Rake::Task['couch_tomato:migrate'].invoke
35
+ end
36
+ end
37
+
38
+ desc 'Resets your database using your migrations for the current environment'
39
+ task :reset => ['couch_tomato:drop', 'couch_tomato:push', 'couch_tomato:migrate']
40
+
41
+ desc 'Runs the "up" for a given migration VERSION.'
42
+ task :up => :environment do
43
+ version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
44
+ raise 'VERSION is required' unless version
45
+
46
+ databases do |db, dir|
47
+ CouchTomato::Migrator.run(:up, db, dir, version)
48
+ end
49
+ end
50
+
51
+ desc 'Runs the "down" for a given migration VERSION.'
52
+ task :down => :environment do
53
+ version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
54
+ raise 'VERSION is required' unless version
55
+
56
+ databases do |db, dir|
57
+ CouchTomato::Migrator.run(:down, db, dir, version)
58
+ end
59
+ end
60
+ end
61
+
62
+ desc 'Rolls back to the previous version. Specify the number of steps with STEP=n'
63
+ task :rollback => :environment do
64
+ databases do |db, dir|
65
+ CouchTomato::Migrator.rollback(db, dir, ENV['STEP'] ? ENV['STEP'].to_i : 1)
66
+ end
67
+ end
68
+
69
+ desc 'Rolls forward to the next version. Specify the number of steps with STEP=n'
70
+ task :forward => :environment do
71
+ databases do |db, dir|
72
+ CouchTomato::Migrator.forward(db, dir, ENV['STEP'] ? ENV['STEP'].to_i : 1)
73
+ end
74
+ end
75
+
76
+ desc 'Replicates couch databases'
77
+ task :replicate => :environment do
78
+ src_server, dst_server = servers
79
+
80
+ src_db = ENV['DB']
81
+ dst_db = ENV['DST_DB'] || (src_server == dst_server ? "#{src_db}_bak" : src_db)
82
+
83
+ replicator = CouchTomato::Replicator.new(src_server, dst_server)
84
+
85
+ if src_db
86
+ puts "== Replicating '#{src_server}/#{src_db}' to '#{dst_server}/#{dst_db}'"
87
+ replicator.replicate(src_db, dst_db)
88
+ elsif src_server == dst_server
89
+ puts "== Replicating all databases at '#{src_server}' using '_bak' suffix for replicated database names"
90
+ replicator.replicate_all('_bak')
91
+ else
92
+ puts "== Replicating all databases from '#{src_server}' to '#{dst_server}'"
93
+ replicator.replicate_all
94
+ end
95
+ end
96
+
97
+ namespace :replicate do
98
+ desc 'Replicate databases between app environments'
99
+ task :env => :environment do
100
+ src_server, dst_server = servers
101
+
102
+ src_env = ENV['SRC_ENV'] || 'production'
103
+ dst_env = ENV['DST_ENV'] || 'development'
104
+
105
+ replicator = CouchTomato::Replicator.new(src_server, dst_server)
106
+ replicator.replicate_env(src_env, dst_env, ENV['PREFIX'])
107
+ end
108
+ end
109
+
110
+ private
111
+
112
+ def servers
113
+ local_server = "http://#{APP_CONFIG['couchdb_address']}:#{APP_CONFIG['couchdb_port']}"
114
+ src_server = (ENV['SRC_SERVER'] || local_server).gsub(/\s*\/\s*$/, '')
115
+ dst_server = (ENV['DST_SERVER'] || local_server).gsub(/\s*\/\s*$/, '')
116
+
117
+ return src_server, dst_server
118
+ end
119
+
120
+ def databases
121
+ dirs = ENV['DB'] ? ["couchdb/migrate/#{ENV['DB']}"] : Dir['couchdb/migrate/*']
122
+ dirs.each do |dir|
123
+ db_name = File.basename(dir)
124
+ db = CouchTomato::JsViewSource.database!(db_name)
125
+ yield db, dir
126
+ end
127
+ end
128
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,7 @@
1
+ # this is for rails only
2
+
3
+ require File.dirname(__FILE__) + '/../lib/couch_tomato'
4
+
5
+ # CouchTomato::Config.database_name = YAML::load(File.read(Rails.root.to_s + '/config/couchdb.yml'))[RAILS_ENV]
6
+
7
+ RAILS_DEFAULT_LOGGER.info "** couch_tomato: initialized from #{__FILE__}"
@@ -0,0 +1,271 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class CallbackRecorder
4
+ include CouchTomato::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 CouchTomato::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
+ it "should run all callback methods given to the callback method call" do
59
+ monkey = Monkey.new
60
+ CouchTomato.database.save_document! monkey
61
+ monkey.eaten_banana.should be_true
62
+ monkey.eaten_apple.should be_true
63
+ end
64
+ end
65
+
66
+ describe 'create callbacks' do
67
+
68
+ before(:each) do
69
+ @recorder = CallbackRecorder.new
70
+ couchrest_database = stub 'couchrest_database', :save_doc => {'id' => '1', 'rev' => '2'}, :view => {'rows' => []}, :info => nil
71
+ @db = CouchTomato::Database.new(couchrest_database)
72
+ end
73
+
74
+ describe "successful create" do
75
+ before(:each) do
76
+ @recorder.required_property = 1
77
+ end
78
+
79
+ it "should call before_validation" do
80
+ @recorder.valid?
81
+ @recorder.callbacks.should include(:before_validation)
82
+ end
83
+
84
+ it "should call before_validation_on_create" do
85
+ @db.save_document! @recorder
86
+ @recorder.callbacks.should include(:before_validation_on_create)
87
+ end
88
+
89
+ it "should call before_validation_on_save" do
90
+ @db.save_document! @recorder
91
+ @recorder.callbacks.should include(:before_validation_on_save)
92
+ end
93
+
94
+ it "should call before_save" do
95
+ @db.save_document! @recorder
96
+ @recorder.callbacks.should include(:before_save)
97
+ end
98
+
99
+ it "should call after_save" do
100
+ @db.save_document! @recorder
101
+ @recorder.callbacks.should include(:after_save)
102
+ end
103
+
104
+ it "should call before_create" do
105
+ @db.save_document! @recorder
106
+ @recorder.callbacks.should include(:before_create)
107
+ end
108
+
109
+ it "should call after_create" do
110
+ @db.save_document! @recorder
111
+ @recorder.callbacks.should include(:after_create)
112
+ end
113
+
114
+ end
115
+
116
+ describe "failed create" do
117
+
118
+ it "should call before_validation" do
119
+ @recorder.valid?
120
+ @recorder.callbacks.should include(:before_validation)
121
+ end
122
+
123
+ it "should call before_validation_on_create" do
124
+ @db.save_document @recorder
125
+ @recorder.callbacks.should include(:before_validation_on_create)
126
+ end
127
+
128
+ it "should call before_validation_on_save" do
129
+ @db.save_document @recorder
130
+ @recorder.callbacks.should include(:before_validation_on_save)
131
+ end
132
+
133
+ it "should not call before_save" do
134
+ @db.save_document @recorder
135
+ @recorder.callbacks.should_not include(:before_save)
136
+ end
137
+
138
+ it "should not call after_save" do
139
+ @db.save_document @recorder
140
+ @recorder.callbacks.should_not include(:after_save)
141
+ end
142
+
143
+ it "should not call before_create" do
144
+ @db.save_document @recorder
145
+ @recorder.callbacks.should_not include(:before_create)
146
+ end
147
+
148
+ it "should not call after_create" do
149
+ @db.save_document @recorder
150
+ @recorder.callbacks.should_not include(:after_create)
151
+ end
152
+ end
153
+ end
154
+
155
+ describe "update callbacks" do
156
+
157
+ before(:each) do
158
+ @recorder = CallbackRecorder.new :required_property => 1
159
+
160
+ couchrest_database = stub 'couchrest_database', :save_doc => {'id' => '1', 'rev' => '2'}, :view => {'rows' => []}, :info => nil
161
+ @db = CouchTomato::Database.new(couchrest_database)
162
+ @db.save_document! @recorder
163
+
164
+ @recorder.required_property = 2
165
+ @recorder.callbacks.clear
166
+ end
167
+
168
+ describe "successful update" do
169
+
170
+ before(:each) do
171
+ @db.save_document! @recorder
172
+ end
173
+
174
+ it "should call before_validation" do
175
+ @recorder.callbacks.should include(:before_validation)
176
+ end
177
+
178
+ it "should call before_validation_on_update" do
179
+ @recorder.callbacks.should include(:before_validation_on_update)
180
+ end
181
+
182
+ it "should call before_validation_on_save" do
183
+ @recorder.callbacks.should include(:before_validation_on_save)
184
+ end
185
+
186
+ it "should call before_save" do
187
+ @recorder.callbacks.should include(:before_save)
188
+ end
189
+
190
+ it "should call after_save" do
191
+ @recorder.callbacks.should include(:after_save)
192
+ end
193
+
194
+ it "should call before_update" do
195
+ @recorder.callbacks.should include(:before_update)
196
+ end
197
+
198
+ it "should call after_update" do
199
+ @recorder.callbacks.should include(:after_update)
200
+ end
201
+
202
+ end
203
+
204
+ describe "failed update" do
205
+
206
+ before(:each) do
207
+ @recorder.required_property = nil
208
+ @db.save_document @recorder
209
+ end
210
+
211
+ it "should call before_validation" do
212
+ @recorder.callbacks.should include(:before_validation)
213
+ end
214
+
215
+ it "should call before_validation_on_update" do
216
+ @recorder.callbacks.should include(:before_validation_on_update)
217
+ end
218
+
219
+ it "should call before_validation_on_save" do
220
+ @recorder.callbacks.should include(:before_validation_on_save)
221
+ end
222
+
223
+ it "should not call before_save" do
224
+ @recorder.callbacks.should_not include(:before_save)
225
+ end
226
+
227
+ it "should not call after_save" do
228
+ @recorder.callbacks.should_not include(:after_save)
229
+ end
230
+
231
+ it "should not call before_update" do
232
+ @recorder.callbacks.should_not include(:before_update)
233
+ end
234
+
235
+ it "should not call after_update" do
236
+ @recorder.callbacks.should_not include(:after_update)
237
+ end
238
+
239
+ end
240
+
241
+ end
242
+
243
+ describe "destroy callbacks" do
244
+
245
+ before(:each) do
246
+ @recorder = CallbackRecorder.new :required_property => 1
247
+ couchrest_database = stub 'couchrest_database', :save_doc => {'id' => '1', 'rev' => '2'}, :delete_doc => nil, :view => {'rows' => []}, :info => nil
248
+ @db = CouchTomato::Database.new(couchrest_database)
249
+ @db.save_document! @recorder
250
+
251
+ @recorder.callbacks.clear
252
+ end
253
+
254
+ it "should call before_destroy" do
255
+ @db.destroy_document @recorder
256
+ @recorder.callbacks.should include(:before_destroy)
257
+ end
258
+
259
+ it "should call after_destroy" do
260
+ @db.destroy_document @recorder
261
+ @recorder.callbacks.should include(:after_destroy)
262
+ end
263
+ end
264
+
265
+ describe "lambda callbacks" do
266
+ it "should run the lambda" do
267
+ recorder = CallbackRecorder.new
268
+ recorder.run_callbacks :before_create
269
+ recorder.lambda_works.should be_true
270
+ end
271
+ end
data/spec/comment.rb ADDED
@@ -0,0 +1,8 @@
1
+ class Comment
2
+ include CouchTomato::Persistence
3
+
4
+ validates_presence_of :title
5
+
6
+ property :title
7
+ belongs_to :commenter
8
+ end
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + '/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
+ CouchTomato.database.save_document! @comment
11
+ CouchTomato.couchrest_database.get(@comment.id)['ruby_class'].should == 'Comment'
12
+ end
13
+ end
14
+ describe "fails" do
15
+ it "should not store anything" do
16
+ @comment = Comment.new
17
+ CouchTomato.database.save_document @comment
18
+ CouchTomato.couchrest_database.documents['rows'].should be_empty
19
+ end
20
+ end
21
+ end
22
+