dpla-couchrest 1.2.1.pre.dpla

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +2 -0
  5. data/LICENSE +176 -0
  6. data/README.md +66 -0
  7. data/Rakefile +23 -0
  8. data/THANKS.md +21 -0
  9. data/VERSION +1 -0
  10. data/couchrest.gemspec +36 -0
  11. data/examples/word_count/markov +38 -0
  12. data/examples/word_count/views/books/chunked-map.js +3 -0
  13. data/examples/word_count/views/books/united-map.js +1 -0
  14. data/examples/word_count/views/markov/chain-map.js +6 -0
  15. data/examples/word_count/views/markov/chain-reduce.js +7 -0
  16. data/examples/word_count/views/word_count/count-map.js +6 -0
  17. data/examples/word_count/views/word_count/count-reduce.js +3 -0
  18. data/examples/word_count/word_count.rb +46 -0
  19. data/examples/word_count/word_count_query.rb +40 -0
  20. data/examples/word_count/word_count_views.rb +26 -0
  21. data/history.txt +214 -0
  22. data/init.rb +1 -0
  23. data/lib/couchrest.rb +146 -0
  24. data/lib/couchrest/attributes.rb +89 -0
  25. data/lib/couchrest/commands/generate.rb +71 -0
  26. data/lib/couchrest/commands/push.rb +103 -0
  27. data/lib/couchrest/database.rb +402 -0
  28. data/lib/couchrest/design.rb +91 -0
  29. data/lib/couchrest/document.rb +105 -0
  30. data/lib/couchrest/helper/attachments.rb +29 -0
  31. data/lib/couchrest/helper/pager.rb +103 -0
  32. data/lib/couchrest/helper/streamer.rb +60 -0
  33. data/lib/couchrest/helper/upgrade.rb +51 -0
  34. data/lib/couchrest/middlewares/logger.rb +263 -0
  35. data/lib/couchrest/monkeypatches.rb +25 -0
  36. data/lib/couchrest/rest_api.rb +166 -0
  37. data/lib/couchrest/server.rb +92 -0
  38. data/lib/couchrest/support/inheritable_attributes.rb +107 -0
  39. data/spec/.gitignore +1 -0
  40. data/spec/couchrest/couchrest_spec.rb +197 -0
  41. data/spec/couchrest/database_spec.rb +914 -0
  42. data/spec/couchrest/design_spec.rb +206 -0
  43. data/spec/couchrest/document_spec.rb +400 -0
  44. data/spec/couchrest/helpers/pager_spec.rb +115 -0
  45. data/spec/couchrest/helpers/streamer_spec.rb +134 -0
  46. data/spec/couchrest/rest_api_spec.rb +241 -0
  47. data/spec/couchrest/server_spec.rb +35 -0
  48. data/spec/fixtures/attachments/README +3 -0
  49. data/spec/fixtures/attachments/couchdb.png +0 -0
  50. data/spec/fixtures/attachments/test.html +11 -0
  51. data/spec/fixtures/views/lib.js +3 -0
  52. data/spec/fixtures/views/test_view/lib.js +3 -0
  53. data/spec/fixtures/views/test_view/only-map.js +4 -0
  54. data/spec/fixtures/views/test_view/test-map.js +3 -0
  55. data/spec/fixtures/views/test_view/test-reduce.js +3 -0
  56. data/spec/spec.opts +5 -0
  57. data/spec/spec_helper.rb +46 -0
  58. data/utils/remap.rb +27 -0
  59. data/utils/subset.rb +30 -0
  60. metadata +212 -0
@@ -0,0 +1,206 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe CouchRest::Design do
4
+
5
+ describe "defining a view" do
6
+ it "should add a view to the design doc" do
7
+ @des = CouchRest::Design.new
8
+ method = @des.view_by :name
9
+ method.should == "by_name"
10
+ @des["views"]["by_name"].should_not be_nil
11
+ end
12
+ end
13
+
14
+ describe "with an unsaved view" do
15
+ before(:each) do
16
+ @des = CouchRest::Design.new
17
+ @des.view_by :name
18
+ end
19
+ it "should accept a name" do
20
+ @des.name = "mytest"
21
+ @des.name.should == "mytest"
22
+ end
23
+ it "should not save on view definition" do
24
+ @des.rev.should be_nil
25
+ end
26
+ it "should freak out on view access" do
27
+ lambda{@des.view :by_name}.should raise_error
28
+ end
29
+ end
30
+
31
+ describe "saving" do
32
+ before(:each) do
33
+ @des = CouchRest::Design.new
34
+ @des.view_by :name
35
+ @des.database = reset_test_db!
36
+ end
37
+ it "should fail without a name" do
38
+ lambda{@des.save}.should raise_error(ArgumentError)
39
+ end
40
+ it "should work with a name" do
41
+ @des.name = "myview"
42
+ @des.save
43
+ end
44
+ end
45
+
46
+ describe "when it's saved" do
47
+ before(:each) do
48
+ @db = reset_test_db!
49
+ @db.bulk_save([{"name" => "x"},{"name" => "y"}])
50
+ @des = CouchRest::Design.new
51
+ @des.database = @db
52
+ @des.view_by :name
53
+ end
54
+ it "should by queryable when it's saved" do
55
+ @des.name = "mydesign"
56
+ @des.save
57
+ res = @des.view :by_name
58
+ res["rows"][0]["key"].should == "x"
59
+ end
60
+ it "should be queryable on specified database" do
61
+ @des.name = "mydesign"
62
+ @des.save
63
+ @des.database = nil
64
+ res = @des.view_on @db, :by_name
65
+ res["rows"][0]["key"].should == "x"
66
+ end
67
+ end
68
+
69
+ describe "from a saved document" do
70
+ before(:each) do
71
+ @db = reset_test_db!
72
+ @db.save_doc({
73
+ "_id" => "_design/test",
74
+ "views" => {
75
+ "by_name" => {
76
+ "map" => "function(doc){if (doc.name) emit(doc.name, null)}"
77
+ }
78
+ }
79
+ })
80
+ @db.bulk_save([{"name" => "a"},{"name" => "b"}])
81
+ @des = @db.get "_design/test"
82
+ end
83
+ it "should be a Design" do
84
+ @des.should be_an_instance_of(CouchRest::Design)
85
+ end
86
+ it "should have a modifiable name" do
87
+ @des.name.should == "test"
88
+ @des.name = "supertest"
89
+ @des.id.should == "_design/supertest"
90
+ end
91
+ it "should by queryable" do
92
+ res = @des.view :by_name
93
+ res["rows"][0]["key"].should == "a"
94
+ end
95
+ end
96
+
97
+ describe "a view with default options" do
98
+ before(:all) do
99
+ @db = reset_test_db!
100
+ @des = CouchRest::Design.new
101
+ @des.name = "test"
102
+ @des.view_by :name, :descending => true
103
+ @des.database = @db
104
+ @des.save
105
+ @db.bulk_save([{"name" => "a"},{"name" => "z"}])
106
+ end
107
+ it "should save them" do
108
+ @d2 = @db.get(@des.id)
109
+ @d2["views"]["by_name"]["couchrest-defaults"].should == {"descending"=>true}
110
+ end
111
+ it "should use them" do
112
+ res = @des.view :by_name
113
+ res["rows"].first["key"].should == "z"
114
+ end
115
+ it "should override them" do
116
+ res = @des.view :by_name, :descending => false
117
+ res["rows"].first["key"].should == "a"
118
+ end
119
+ end
120
+
121
+ describe "a view with multiple keys" do
122
+ before(:all) do
123
+ @db = reset_test_db!
124
+ @des = CouchRest::Design.new
125
+ @des.name = "test"
126
+ @des.view_by :name, :age
127
+ @des.database = @db
128
+ @des.save
129
+ @db.bulk_save([{"name" => "a", "age" => 2},
130
+ {"name" => "a", "age" => 4},{"name" => "z", "age" => 9}])
131
+ end
132
+ it "should work" do
133
+ res = @des.view :by_name_and_age
134
+ res["rows"].first["key"].should == ["a",2]
135
+ end
136
+ end
137
+
138
+ describe "a view with nil and 0 values" do
139
+ before(:all) do
140
+ @db = reset_test_db!
141
+ @des = CouchRest::Design.new
142
+ @des.name = "test"
143
+ @des.view_by :code
144
+ @des.database = @db
145
+ @des.save
146
+ @db.bulk_save([{"code" => "a", "age" => 2},
147
+ {"code" => nil, "age" => 4},{"code" => 0, "age" => 9}])
148
+ end
149
+ it "should work" do
150
+ res = @des.view :by_code
151
+ res["rows"][0]["key"].should == 0
152
+ res["rows"][1]["key"].should == "a"
153
+ res["rows"][2].should be_nil
154
+ end
155
+ end
156
+
157
+ describe "a view with nil and 0 values and :allow_nil" do
158
+ before(:all) do
159
+ @db = reset_test_db!
160
+ @des = CouchRest::Design.new
161
+ @des.name = "test"
162
+ @des.view_by :code, :allow_nil => true
163
+ @des.database = @db
164
+ @des.save
165
+ @db.bulk_save([{"code" => "a", "age" => 2},
166
+ {"code" => nil, "age" => 4},{"code" => 0, "age" => 9}])
167
+ end
168
+ it "should work" do
169
+ res = @des.view :by_code
170
+ res["rows"][0]["key"].should == nil
171
+ res["rows"][1]["key"].should == 0
172
+ res["rows"][2]["key"].should == "a"
173
+ end
174
+ end
175
+
176
+
177
+ describe "a view with a reduce function" do
178
+ before(:all) do
179
+ @db = reset_test_db!
180
+ @des = CouchRest::Design.new
181
+ @des.name = "test"
182
+ @des.view_by :code, :map => "function(d){ if(d['code']) { emit(d['code'], 1); } }", :reduce => "function(k,v,r){ return sum(v); }"
183
+ @des.database = @db
184
+ @des.save
185
+ @db.bulk_save([{"code" => "a", "age" => 2},
186
+ {"code" => 'b', "age" => 4},{"code" => 'c', "age" => 9}])
187
+ end
188
+ it "should not set a default parameter" do
189
+ @des['views']['by_code']['couchrest-defaults'].should be_nil
190
+ end
191
+ it "should include reduce parameter in query" do
192
+ # this would fail without it
193
+ res = @des.view :by_code
194
+ res["rows"][0]["key"].should == 'a'
195
+ end
196
+ it "should allow reduce to be performed" do
197
+ res = @des.view :by_code, :reduce => true
198
+ res["rows"][0]["value"].should eql(3)
199
+ end
200
+ it "does not allow string keys to be passed to view as options" do
201
+ lambda{ @des.view :by_code, 'reduce' => true }.should raise_error(ArgumentError, /set as symbols/)
202
+ end
203
+ end
204
+
205
+
206
+ end
@@ -0,0 +1,400 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ class Video < CouchRest::Document; end
4
+
5
+ describe CouchRest::Document do
6
+
7
+ before(:all) do
8
+ @couch = CouchRest.new
9
+ @db = @couch.database!(TESTDB)
10
+ end
11
+
12
+ describe "#new" do
13
+ it "should not be a Hash" do
14
+ @doc = CouchRest::Document.new
15
+ @doc.class.should eql(CouchRest::Document)
16
+ @doc.is_a?(Hash).should be_false
17
+ end
18
+
19
+ it "should be possible to initialize a new Document with attributes" do
20
+ @doc = CouchRest::Document.new('foo' => 'bar', :test => 'foo')
21
+ @doc['foo'].should eql('bar')
22
+ @doc['test'].should eql('foo')
23
+ end
24
+
25
+ it "should accept new with _id" do
26
+ @doc = CouchRest::Document.new('_id' => 'sample', 'foo' => 'bar')
27
+ @doc['_id'].should eql('sample')
28
+ @doc['foo'].should eql('bar')
29
+ end
30
+
31
+ context "replacing initalize" do
32
+ it "should not raise error" do
33
+ klass = Class.new(CouchRest::Document)
34
+ klass.class_eval do
35
+ def initialize; end # don't do anything, just overwrite
36
+ end
37
+ expect {
38
+ @doc = klass.new
39
+ @doc['test'] = 'sample'
40
+ }.to_not raise_error
41
+ end
42
+ end
43
+ end
44
+
45
+
46
+ describe "hash methods" do
47
+ it "should respond to forwarded hash methods" do
48
+ @doc = CouchRest::Document.new(:foo => 'bar')
49
+ [:to_a, :==, :eql?, :keys, :values, :each, :reject, :reject!, :empty?,
50
+ :clear, :merge, :merge!, :encode_json, :as_json, :to_json, :frozen?].each do |call|
51
+ @doc.should respond_to(call)
52
+ end
53
+ end
54
+ end
55
+
56
+ describe "[]=" do
57
+ before(:each) do
58
+ @doc = CouchRest::Document.new
59
+ end
60
+ it "should work" do
61
+ @doc["enamel"].should == nil
62
+ @doc["enamel"] = "Strong"
63
+ @doc["enamel"].should == "Strong"
64
+ end
65
+ it "[]= should convert to string" do
66
+ @doc["enamel"].should == nil
67
+ @doc[:enamel] = "Strong"
68
+ @doc["enamel"].should == "Strong"
69
+ end
70
+ it "should read as a string" do
71
+ @doc[:enamel] = "Strong"
72
+ @doc[:enamel].should == "Strong"
73
+ end
74
+ end
75
+
76
+ describe "#has_key?" do
77
+ before :each do
78
+ @doc = CouchRest::Document.new
79
+ end
80
+ it "should confirm existance of key" do
81
+ @doc[:test] = 'example'
82
+ @doc.has_key?('test').should be_true
83
+ @doc.has_key?(:test).should be_true
84
+ end
85
+ it "should deny existance of key" do
86
+ @doc.has_key?(:bardom).should be_false
87
+ @doc.has_key?('bardom').should be_false
88
+ end
89
+ end
90
+
91
+ describe "#dup" do
92
+ it "should also clone the attributes" do
93
+ @doc = CouchRest::Document.new('foo' => 'bar')
94
+ @doc2 = @doc.dup
95
+ @doc2.delete('foo')
96
+ @doc2['foo'].should be_nil
97
+ @doc['foo'].should eql('bar')
98
+ end
99
+ end
100
+
101
+ describe "#clone" do
102
+ it "should also clone the attributes" do
103
+ @doc = CouchRest::Document.new('foo' => 'bar')
104
+ @doc2 = @doc.clone
105
+ @doc2.delete('foo')
106
+ @doc2['foo'].should be_nil
107
+ @doc['foo'].should eql('bar')
108
+ end
109
+ end
110
+
111
+ describe "#freeze" do
112
+ it "should freeze the attributes, but not actual model" do
113
+ klass = Class.new(CouchRest::Document)
114
+ klass.class_eval { attr_accessor :test_attr }
115
+ @doc = klass.new('foo' => 'bar')
116
+ @doc.freeze
117
+ lambda { @doc['foo'] = 'bar2' }.should raise_error(/frozen/)
118
+ lambda { @doc.test_attr = "bar3" }.should_not raise_error
119
+ end
120
+ end
121
+
122
+ describe "#as_couch_json" do
123
+ it "should provide a hash of data from normal document" do
124
+ @doc = CouchRest::Document.new('foo' => 'bar')
125
+ h = @doc.as_couch_json
126
+ h.should be_a(Hash)
127
+ h['foo'].should eql('bar')
128
+ end
129
+
130
+ it "should handle nested documents" do
131
+ @doc = CouchRest::Document.new('foo' => 'bar', 'doc' => CouchRest::Document.new('foo2' => 'bar2'))
132
+ h = @doc.as_couch_json
133
+ h['doc'].should be_a(Hash)
134
+ h['doc']['foo2'].should eql('bar2')
135
+ end
136
+ end
137
+
138
+ describe "#inspect" do
139
+ it "should provide a string of keys and values of the Response" do
140
+ @doc = CouchRest::Document.new('foo' => 'bar')
141
+ @doc.inspect.should eql("#<CouchRest::Document foo: \"bar\">")
142
+ end
143
+ end
144
+
145
+ describe "responding to Hash methods" do
146
+ it "should delegate requests" do
147
+ @doc = CouchRest::Document.new('foo' => 'bar')
148
+ @doc.keys.should eql(['foo'])
149
+ @doc.values.should eql(['bar'])
150
+ end
151
+ end
152
+
153
+ describe "default database" do
154
+ before(:each) do
155
+ Video.use_database nil
156
+ end
157
+ it "should be set using use_database on the model" do
158
+ Video.new.database.should be_nil
159
+ Video.use_database @db
160
+ Video.new.database.should == @db
161
+ Video.use_database nil
162
+ end
163
+
164
+ it "should be overwritten by instance" do
165
+ db = @couch.database('test')
166
+ article = Video.new
167
+ article.database.should be_nil
168
+ article.database = db
169
+ article.database.should_not be_nil
170
+ article.database.should == db
171
+ end
172
+ end
173
+
174
+ describe "new" do
175
+ before(:each) do
176
+ @doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
177
+ end
178
+ it "should create itself from a Hash" do
179
+ @doc["key"].should == [1,2,3]
180
+ @doc["more"].should == "values"
181
+ end
182
+ it "should not have rev and id" do
183
+ @doc.rev.should be_nil
184
+ @doc.id.should be_nil
185
+ end
186
+ it "should be possible to set id" do
187
+ @doc.id = 1
188
+ @doc.id.should eql(1)
189
+ end
190
+
191
+ it "should freak out when saving without a database" do
192
+ lambda{@doc.save}.should raise_error(ArgumentError)
193
+ end
194
+
195
+ end
196
+
197
+ # move to database spec
198
+ describe "saving using a database" do
199
+ before(:all) do
200
+ @doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
201
+ @db = reset_test_db!
202
+ @resp = @db.save_doc(@doc)
203
+ end
204
+ it "should apply the database" do
205
+ @doc.database.should == @db
206
+ end
207
+ it "should get id and rev" do
208
+ @doc.id.should == @resp["id"]
209
+ @doc.rev.should == @resp["rev"]
210
+ end
211
+ it "should generate a correct URI" do
212
+ @doc.uri.should == "#{@db.root}/#{@doc.id}"
213
+ URI.parse(@doc.uri).to_s.should == @doc.uri
214
+ end
215
+ it "should generate a correct URI with revision" do
216
+ @doc.uri(true).should == "#{@db.root}/#{@doc.id}?rev=#{@doc.rev}"
217
+ URI.parse(@doc.uri(true)).to_s.should == @doc.uri(true)
218
+ end
219
+ end
220
+
221
+ describe "bulk saving" do
222
+ before :all do
223
+ @db = reset_test_db!
224
+ end
225
+
226
+ it "should use the document bulk save cache" do
227
+ doc = CouchRest::Document.new({"_id" => "bulkdoc", "val" => 3})
228
+ doc.database = @db
229
+ doc.save(true)
230
+ lambda { doc.database.get(doc["_id"]) }.should raise_error(RestClient::ResourceNotFound)
231
+ doc.database.bulk_save
232
+ doc.database.get(doc["_id"])["val"].should == doc["val"]
233
+ end
234
+ end
235
+
236
+ describe "getting from a database" do
237
+ before(:all) do
238
+ @db = reset_test_db!
239
+ @resp = @db.save_doc({
240
+ "key" => "value"
241
+ })
242
+ @doc = @db.get @resp['id']
243
+ end
244
+ it "should return a document" do
245
+ @doc.should be_an_instance_of(CouchRest::Document)
246
+ end
247
+ it "should have a database" do
248
+ @doc.database.should == @db
249
+ end
250
+ it "should be saveable and resavable" do
251
+ @doc["more"] = "keys"
252
+ @doc.save
253
+ @db.get(@resp['id'])["more"].should == "keys"
254
+ @doc["more"] = "these keys"
255
+ @doc.save
256
+ @db.get(@resp['id'])["more"].should == "these keys"
257
+ end
258
+ end
259
+
260
+ describe "destroying a document from a db" do
261
+ before(:all) do
262
+ @db = reset_test_db!
263
+ @resp = @db.save_doc({
264
+ "key" => "value"
265
+ })
266
+ @doc = @db.get @resp['id']
267
+ end
268
+ it "should make it disappear" do
269
+ @doc.destroy
270
+ lambda{@db.get @resp['id']}.should raise_error
271
+ end
272
+ it "should error when there's no db" do
273
+ @doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
274
+ lambda{@doc.destroy}.should raise_error(ArgumentError)
275
+ end
276
+ end
277
+
278
+
279
+ describe "destroying a document from a db using bulk save" do
280
+ before(:all) do
281
+ @db = reset_test_db!
282
+ @resp = @db.save_doc({
283
+ "key" => "value"
284
+ })
285
+ @doc = @db.get @resp['id']
286
+ end
287
+ it "should defer actual deletion" do
288
+ @doc.destroy(true)
289
+ @doc['_id'].should == nil
290
+ @doc['_rev'].should == nil
291
+ lambda{@db.get @resp['id']}.should_not raise_error
292
+ @db.bulk_save
293
+ lambda{@db.get @resp['id']}.should raise_error
294
+ end
295
+ end
296
+
297
+ describe "copying a document" do
298
+ before :each do
299
+ @db = reset_test_db!
300
+ @resp = @db.save_doc({'key' => 'value'})
301
+ @docid = 'new-location'
302
+ @doc = @db.get(@resp['id'])
303
+ end
304
+ describe "to a new location" do
305
+ it "should work" do
306
+ @doc.copy @docid
307
+ newdoc = @db.get(@docid)
308
+ newdoc['key'].should == 'value'
309
+ end
310
+ it "should fail without a database" do
311
+ lambda{CouchRest::Document.new({"not"=>"a real doc"}).copy}.should raise_error(ArgumentError)
312
+ end
313
+ end
314
+ describe "to an existing location" do
315
+ before :each do
316
+ @db.save_doc({'_id' => @docid, 'will-exist' => 'here'})
317
+ end
318
+ it "should fail without a rev" do
319
+ lambda{@doc.copy @docid}.should raise_error(RestClient::RequestFailed)
320
+ end
321
+ it "should succeed with a rev" do
322
+ @to_be_overwritten = @db.get(@docid)
323
+ @doc.copy "#{@docid}?rev=#{@to_be_overwritten['_rev']}"
324
+ newdoc = @db.get(@docid)
325
+ newdoc['key'].should == 'value'
326
+ end
327
+ it "should succeed given the doc to overwrite" do
328
+ @to_be_overwritten = @db.get(@docid)
329
+ @doc.copy @to_be_overwritten
330
+ newdoc = @db.get(@docid)
331
+ newdoc['key'].should == 'value'
332
+ end
333
+ end
334
+ end
335
+ end
336
+
337
+ describe "dealing with attachments" do
338
+ before do
339
+ @db = reset_test_db!
340
+ @attach = "<html><head><title>My Doc</title></head><body><p>Has words.</p></body></html>"
341
+ response = @db.save_doc({'key' => 'value'})
342
+ @doc = @db.get(response['id'])
343
+ end
344
+
345
+ def append_attachment(name='test.html', attach=@attach)
346
+ @doc['_attachments'] ||= {}
347
+ @doc['_attachments'][name] = {
348
+ 'type' => 'text/html',
349
+ 'data' => attach
350
+ }
351
+ @doc.save
352
+ @rev = @doc['_rev']
353
+ end
354
+
355
+ describe "PUTing an attachment directly to the doc" do
356
+ before do
357
+ @doc.put_attachment('test.html', @attach)
358
+ end
359
+
360
+ it "is there" do
361
+ @db.fetch_attachment(@doc, 'test.html').should == @attach
362
+ end
363
+
364
+ it "updates the revision" do
365
+ @doc[:_rev].should_not == @rev
366
+ end
367
+
368
+ it "updates attachments" do
369
+ @attach2 = "<html><head><title>My Doc</title></head><body><p>Is Different.</p></body></html>"
370
+ @doc.put_attachment('test.html', @attach2)
371
+ @db.fetch_attachment(@doc, 'test.html').should == @attach2
372
+ end
373
+ end
374
+
375
+ describe "fetching an attachment from a doc directly" do
376
+ before do
377
+ append_attachment
378
+ end
379
+
380
+ it "pulls the attachment" do
381
+ @doc.fetch_attachment('test.html').should == @attach
382
+ end
383
+ end
384
+
385
+ describe "deleting an attachment from a doc directly" do
386
+ before do
387
+ append_attachment
388
+ @doc.delete_attachment('test.html')
389
+ end
390
+
391
+ it "removes it" do
392
+ lambda { @db.fetch_attachment(@doc, 'test.html').should }.should raise_error(RestClient::ResourceNotFound)
393
+ end
394
+
395
+ it "updates the revision" do
396
+ @doc[:_rev].should_not == @rev
397
+ end
398
+ end
399
+
400
+ end