couch_docs 1.2.1 → 1.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.
- data/.bnsignore +16 -0
- data/.gitignore +4 -2
- data/Gemfile +4 -0
- data/Gemfile.lock +27 -0
- data/History.txt +12 -0
- data/README.rdoc +56 -27
- data/Rakefile +15 -34
- data/VERSION +1 -0
- data/couch_docs.gemspec +19 -40
- data/fixtures/_design/a/e.json +1 -0
- data/fixtures/_design/j/q.json +1 -0
- data/fixtures/baz_with_attachments/spacer.gif +0 -0
- data/fixtures/baz_with_attachments.json +1 -0
- data/lib/couch_docs/command_line.rb +2 -0
- data/lib/couch_docs/design_directory.rb +44 -18
- data/lib/couch_docs/document_directory.rb +57 -2
- data/lib/couch_docs/version.rb +3 -0
- data/lib/couch_docs.rb +0 -1
- data/spec/couch_docs/command_line_spec.rb +170 -0
- data/spec/couch_docs/design_directory_spec.rb +197 -0
- data/spec/couch_docs/document_directory_spec.rb +212 -0
- data/spec/couch_docs/store_spec.rb +98 -0
- data/spec/couch_docs_spec.rb +9 -482
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +3 -5
- metadata +60 -50
- data/couch_docs-1.1.0.gem +0 -0
- data/couch_docs-1.1.1.gem +0 -0
- data/couch_docs-1.2.0.gem +0 -0
data/spec/couch_docs_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require File.join(File.dirname(__FILE__), %w[spec_helper])
|
|
2
2
|
|
3
3
|
describe CouchDocs do
|
4
4
|
it "should be able to create (or delete/create) a DB" do
|
5
|
-
Store.
|
5
|
+
CouchDocs::Store.
|
6
6
|
should_receive(:put!).
|
7
7
|
with("couchdb_url", anything())
|
8
8
|
|
@@ -23,11 +23,11 @@ describe CouchDocs do
|
|
23
23
|
|
24
24
|
it "should be able to load directory/JS files into CouchDB as design docs" do
|
25
25
|
store = mock("Store")
|
26
|
-
Store.stub!(:new).and_return(store)
|
26
|
+
CouchDocs::Store.stub!(:new).and_return(store)
|
27
27
|
|
28
28
|
dir = mock("Design Directory")
|
29
29
|
dir.stub!(:to_hash).and_return({ "foo" => "bar" })
|
30
|
-
DesignDirectory.stub!(:new).and_return(dir)
|
30
|
+
CouchDocs::DesignDirectory.stub!(:new).and_return(dir)
|
31
31
|
|
32
32
|
store.
|
33
33
|
should_receive(:put_design_documents).
|
@@ -42,9 +42,9 @@ describe CouchDocs do
|
|
42
42
|
stub!(:each_document).
|
43
43
|
and_yield('foo', {"foo" => "1"})
|
44
44
|
|
45
|
-
DocumentDirectory.stub!(:new).and_return(dir)
|
45
|
+
CouchDocs::DocumentDirectory.stub!(:new).and_return(dir)
|
46
46
|
|
47
|
-
Store.
|
47
|
+
CouchDocs::Store.
|
48
48
|
should_receive(:put!).
|
49
49
|
with('uri/foo', {"foo" => "1"})
|
50
50
|
|
@@ -52,7 +52,7 @@ describe CouchDocs do
|
|
52
52
|
end
|
53
53
|
|
54
54
|
it "should be able to upload a single document into CouchDB" do
|
55
|
-
Store.
|
55
|
+
CouchDocs::Store.
|
56
56
|
should_receive(:put!).
|
57
57
|
with('uri/foo', {"foo" => "1"})
|
58
58
|
|
@@ -64,13 +64,13 @@ describe CouchDocs do
|
|
64
64
|
context "dumping CouchDB documents to a directory" do
|
65
65
|
before(:each) do
|
66
66
|
@store = mock("Store")
|
67
|
-
Store.stub!(:new).and_return(@store)
|
67
|
+
CouchDocs::Store.stub!(:new).and_return(@store)
|
68
68
|
|
69
69
|
@des_dir = mock("Design Directory").as_null_object
|
70
|
-
DesignDirectory.stub!(:new).and_return(@des_dir)
|
70
|
+
CouchDocs::DesignDirectory.stub!(:new).and_return(@des_dir)
|
71
71
|
|
72
72
|
@dir = mock("Document Directory").as_null_object
|
73
|
-
DocumentDirectory.stub!(:new).and_return(@dir)
|
73
|
+
CouchDocs::DocumentDirectory.stub!(:new).and_return(@dir)
|
74
74
|
end
|
75
75
|
it "should be able to store all CouchDB documents on the filesystem" do
|
76
76
|
@store.stub!(:map).and_return([{'_id' => 'foo'}])
|
@@ -117,477 +117,4 @@ describe CouchDocs do
|
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
-
|
121
|
-
describe Store do
|
122
|
-
it "should require a CouchDB URL Root for instantiation" do
|
123
|
-
lambda { Store.new }.
|
124
|
-
should raise_error
|
125
|
-
|
126
|
-
lambda { Store.new("uri") }.
|
127
|
-
should_not raise_error
|
128
|
-
end
|
129
|
-
|
130
|
-
context "a valid store" do
|
131
|
-
before(:each) do
|
132
|
-
@it = Store.new("uri")
|
133
|
-
|
134
|
-
@hash = {
|
135
|
-
'a' => {
|
136
|
-
'b' => {
|
137
|
-
'c' => 'function(doc) { return true; }'
|
138
|
-
}
|
139
|
-
}
|
140
|
-
}
|
141
|
-
end
|
142
|
-
|
143
|
-
it "should be able to put a new document" do
|
144
|
-
Store.
|
145
|
-
should_receive(:put).
|
146
|
-
with("uri", { })
|
147
|
-
|
148
|
-
Store.put!("uri", { })
|
149
|
-
end
|
150
|
-
|
151
|
-
it "should delete existing docs if first put fails" do
|
152
|
-
Store.
|
153
|
-
stub!(:put).
|
154
|
-
and_raise(RestClient::RequestFailed)
|
155
|
-
|
156
|
-
Store.
|
157
|
-
should_receive(:delete_and_put).
|
158
|
-
with("uri", { })
|
159
|
-
|
160
|
-
Store.put!("uri", { })
|
161
|
-
end
|
162
|
-
|
163
|
-
it "should be able to delete and put" do
|
164
|
-
Store.
|
165
|
-
should_receive(:delete).
|
166
|
-
with("uri")
|
167
|
-
|
168
|
-
Store.
|
169
|
-
should_receive(:put).
|
170
|
-
with("uri", { })
|
171
|
-
|
172
|
-
Store.delete_and_put("uri", { })
|
173
|
-
end
|
174
|
-
|
175
|
-
it "should be able to load a hash into design docs" do
|
176
|
-
RestClient.
|
177
|
-
should_receive(:put).
|
178
|
-
with("uri/_design/a",
|
179
|
-
'{"b":{"c":"function(doc) { return true; }"}}',
|
180
|
-
:content_type => 'application/json')
|
181
|
-
@it.put_design_documents(@hash)
|
182
|
-
end
|
183
|
-
|
184
|
-
it "should be able to retrieve an existing document" do
|
185
|
-
RestClient.
|
186
|
-
stub!(:get).
|
187
|
-
and_return('{"_rev":"1234"}')
|
188
|
-
|
189
|
-
Store.get("uri").should == { '_rev' => "1234" }
|
190
|
-
end
|
191
|
-
|
192
|
-
it "should be able to delete an existing document" do
|
193
|
-
Store.stub!(:get).and_return({ '_rev' => '1234' })
|
194
|
-
|
195
|
-
RestClient.
|
196
|
-
should_receive(:delete).
|
197
|
-
with("uri?rev=1234")
|
198
|
-
|
199
|
-
Store.delete("uri")
|
200
|
-
end
|
201
|
-
|
202
|
-
it "should be able to load each document" do
|
203
|
-
Store.stub!(:get).
|
204
|
-
with("uri/_all_docs").
|
205
|
-
and_return({ "total_rows" => 2,
|
206
|
-
"offset" => 0,
|
207
|
-
"rows" => [{"id"=>"1", "value"=>{}, "key"=>"1"},
|
208
|
-
{"id"=>"2", "value"=>{}, "key"=>"2"}]})
|
209
|
-
|
210
|
-
Store.stub!(:get).with("uri/1?attachments=true")
|
211
|
-
Store.should_receive(:get).with("uri/2?attachments=true")
|
212
|
-
|
213
|
-
@it.each { }
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
describe DocumentDirectory do
|
219
|
-
it "should require a root directory for instantiation" do
|
220
|
-
lambda { DocumentDirectory.new }.
|
221
|
-
should raise_error
|
222
|
-
|
223
|
-
lambda { DocumentDirectory.new("foo") }.
|
224
|
-
should raise_error
|
225
|
-
|
226
|
-
lambda { DocumentDirectory.new("fixtures")}.
|
227
|
-
should_not raise_error
|
228
|
-
end
|
229
|
-
|
230
|
-
context "a valid directory" do
|
231
|
-
before(:each) do
|
232
|
-
@it = DocumentDirectory.new("fixtures")
|
233
|
-
end
|
234
|
-
|
235
|
-
it "should be able to iterate over the documents" do
|
236
|
-
everything = []
|
237
|
-
@it.each_document do |name, contents|
|
238
|
-
everything << [name, contents]
|
239
|
-
end
|
240
|
-
everything.
|
241
|
-
should == [['bar', {"bar" => "2"}],
|
242
|
-
['foo', {"foo" => "1"}]]
|
243
|
-
end
|
244
|
-
|
245
|
-
it "should be able to store a document" do
|
246
|
-
file = mock("File", :write => 42, :close => true)
|
247
|
-
File.
|
248
|
-
should_receive(:new).
|
249
|
-
with("fixtures/foo.json", "w+").
|
250
|
-
and_return(file)
|
251
|
-
|
252
|
-
@it.store_document({'_id' => 'foo'})
|
253
|
-
end
|
254
|
-
|
255
|
-
it "should be able to save a document as JSON" do
|
256
|
-
file = mock("File", :close => true)
|
257
|
-
File.stub!(:new).and_return(file)
|
258
|
-
|
259
|
-
file.should_receive(:write).with(%Q|{"_id":"foo"}|)
|
260
|
-
|
261
|
-
@it.store_document({'_id' => 'foo'})
|
262
|
-
end
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
describe DesignDirectory do
|
267
|
-
it "should require a root directory for instantiation" do
|
268
|
-
lambda { DesignDirectory.new }.
|
269
|
-
should raise_error
|
270
|
-
|
271
|
-
lambda { DesignDirectory.new("foo") }.
|
272
|
-
should raise_error
|
273
|
-
|
274
|
-
lambda { DesignDirectory.new("fixtures/_design")}.
|
275
|
-
should_not raise_error
|
276
|
-
end
|
277
|
-
|
278
|
-
it "should convert arrays into deep hashes" do
|
279
|
-
DesignDirectory.
|
280
|
-
a_to_hash(%w{a b c d}).
|
281
|
-
should == {
|
282
|
-
'a' => {
|
283
|
-
'b' => {
|
284
|
-
'c' => 'd'
|
285
|
-
}
|
286
|
-
}
|
287
|
-
}
|
288
|
-
end
|
289
|
-
|
290
|
-
context "a valid directory" do
|
291
|
-
before(:each) do
|
292
|
-
@it = DesignDirectory.new("fixtures/_design")
|
293
|
-
end
|
294
|
-
|
295
|
-
it "should list dirs, basename and contents of a file" do
|
296
|
-
@it.expand_file("fixtures/_design/a/b/c.js").
|
297
|
-
should == ['a', 'b', 'c', 'function(doc) { return true; }']
|
298
|
-
end
|
299
|
-
|
300
|
-
it "should assemble all documents into a single docs structure" do
|
301
|
-
@it.to_hash['a'].
|
302
|
-
should == {
|
303
|
-
'b' => {
|
304
|
-
'c' => 'function(doc) { return true; }',
|
305
|
-
'd' => 'function(doc) { return true; }'
|
306
|
-
}
|
307
|
-
}
|
308
|
-
end
|
309
|
-
|
310
|
-
it "should process code macros when assembling" do
|
311
|
-
@it.to_hash['x'].
|
312
|
-
should == {
|
313
|
-
'z' =>
|
314
|
-
"// !begin code foo.js\n" +
|
315
|
-
"function foo () { return \"foo\"; }\n" +
|
316
|
-
"// !end code foo.js\n" +
|
317
|
-
"function bar () { return \"bar\"; }\n"
|
318
|
-
}
|
319
|
-
end
|
320
|
-
|
321
|
-
it "should work with absolute !code paths"
|
322
|
-
|
323
|
-
it "should replace !code macros with the contents of the referenced file in lib" do
|
324
|
-
@it.stub!(:read_from_lib).and_return("awesome javascript")
|
325
|
-
|
326
|
-
@it.
|
327
|
-
process_code_macro(" // !code foo/bar.js ").
|
328
|
-
should =~ /awesome javascript/
|
329
|
-
end
|
330
|
-
|
331
|
-
it "should not affect normal lines when processing macros" do
|
332
|
-
@it.
|
333
|
-
process_code_macro(" var foo = 'bar'; ").
|
334
|
-
should == " var foo = 'bar'; "
|
335
|
-
end
|
336
|
-
|
337
|
-
it "should find files with relative paths in __lib" do
|
338
|
-
File.
|
339
|
-
should_receive(:read).
|
340
|
-
with("fixtures/_design/__lib/foo.js")
|
341
|
-
|
342
|
-
@it.read_from_lib("foo.js")
|
343
|
-
end
|
344
|
-
|
345
|
-
end
|
346
|
-
|
347
|
-
context "saving a JS attribute" do
|
348
|
-
before(:each) do
|
349
|
-
@it = DesignDirectory.new("/tmp")
|
350
|
-
|
351
|
-
FileUtils.stub!(:mkdir_p)
|
352
|
-
@file = mock("File").as_null_object
|
353
|
-
File.stub!(:new).and_return(@file)
|
354
|
-
end
|
355
|
-
|
356
|
-
it "should not store _id" do
|
357
|
-
File.
|
358
|
-
should_not_receive(:new).
|
359
|
-
with("/tmp/_design/foo/_id.js", "w+")
|
360
|
-
|
361
|
-
@it.save_js(nil, "_design/foo", { "_id" => "_design/foo"})
|
362
|
-
end
|
363
|
-
|
364
|
-
it "should create map the design document attribute to the filesystem" do
|
365
|
-
FileUtils.
|
366
|
-
should_receive(:mkdir_p).
|
367
|
-
with("/tmp/_design/foo")
|
368
|
-
|
369
|
-
@it.save_js("_design/foo", "bar", "json")
|
370
|
-
end
|
371
|
-
|
372
|
-
it "should store the attribute to the filesystem" do
|
373
|
-
File.
|
374
|
-
should_receive(:new).
|
375
|
-
with("/tmp/_design/foo/bar.js", "w+")
|
376
|
-
|
377
|
-
@it.save_js("_design/foo", "bar", "json")
|
378
|
-
end
|
379
|
-
|
380
|
-
it "should store hash values to the filesystem" do
|
381
|
-
File.
|
382
|
-
should_receive(:new).
|
383
|
-
with("/tmp/_design/foo/bar/baz.js", "w+")
|
384
|
-
|
385
|
-
@it.save_js("_design/foo", "bar", { "baz" => "json" })
|
386
|
-
end
|
387
|
-
|
388
|
-
it "should store the attribute to the filesystem" do
|
389
|
-
@file.
|
390
|
-
should_receive(:write).
|
391
|
-
with("json")
|
392
|
-
|
393
|
-
@it.save_js("_design/foo", "bar", "json")
|
394
|
-
end
|
395
|
-
|
396
|
-
it "should store the attributes with slashes to the filesystem" do
|
397
|
-
File.
|
398
|
-
should_receive(:new).
|
399
|
-
with("/tmp/_design/foo/bar%2Fbaz.js", "w+")
|
400
|
-
|
401
|
-
@it.save_js("_design/foo", "bar/baz", "json")
|
402
|
-
end
|
403
|
-
|
404
|
-
it "should strip lib code when dumping" do
|
405
|
-
js = <<_JS
|
406
|
-
// !begin code foo.js
|
407
|
-
function foo () { return 'foo'; }
|
408
|
-
// !end code foo.js
|
409
|
-
// !begin code bar.js
|
410
|
-
function bar () { return 'bar'; }
|
411
|
-
// !end code bar.js
|
412
|
-
function baz () { return 'baz'; }
|
413
|
-
_JS
|
414
|
-
|
415
|
-
@it.
|
416
|
-
remove_code_macros(js).
|
417
|
-
should == "// !code foo.js\n" +
|
418
|
-
"// !code bar.js\n" +
|
419
|
-
"function baz () { return 'baz'; }\n"
|
420
|
-
end
|
421
|
-
end
|
422
|
-
end
|
423
|
-
|
424
|
-
describe CommandLine do
|
425
|
-
it "should be able to run a single instance of a command line" do
|
426
|
-
CommandLine.
|
427
|
-
should_receive(:new).
|
428
|
-
with('foo', 'bar').
|
429
|
-
and_return(mock("Command Line").as_null_object)
|
430
|
-
|
431
|
-
CommandLine.run('foo', 'bar')
|
432
|
-
end
|
433
|
-
|
434
|
-
it "should run the command line instance" do
|
435
|
-
command_line = mock("Command Line").as_null_object
|
436
|
-
command_line.
|
437
|
-
should_receive(:run)
|
438
|
-
|
439
|
-
CommandLine.stub!(:new).and_return(command_line)
|
440
|
-
|
441
|
-
CommandLine.run('foo', 'bar')
|
442
|
-
end
|
443
|
-
|
444
|
-
context "an instance that dumps a CouchDB database" do
|
445
|
-
it "should dump CouchDB documents from uri to dir when run" do
|
446
|
-
@it = CommandLine.new(['dump', 'uri', 'dir'])
|
447
|
-
|
448
|
-
CouchDocs.
|
449
|
-
should_receive(:dump).
|
450
|
-
with("uri", "dir", nil)
|
451
|
-
|
452
|
-
@it.run
|
453
|
-
end
|
454
|
-
|
455
|
-
it "should be able to dump only design documents" do
|
456
|
-
@it = CommandLine.new(['dump', 'uri', 'dir', '-d'])
|
457
|
-
|
458
|
-
CouchDocs.
|
459
|
-
should_receive(:dump).
|
460
|
-
with("uri", "dir", :design)
|
461
|
-
|
462
|
-
@it.run
|
463
|
-
end
|
464
|
-
|
465
|
-
it "should be able to dump only regular documents" do
|
466
|
-
@it = CommandLine.new(['dump', 'uri', 'dir', '-D'])
|
467
|
-
|
468
|
-
CouchDocs.
|
469
|
-
should_receive(:dump).
|
470
|
-
with("uri", "dir", :doc)
|
471
|
-
|
472
|
-
@it.run
|
473
|
-
end
|
474
|
-
|
475
|
-
it "should be an initial add if everything is an add" do
|
476
|
-
@it = CommandLine.new(['push', 'uri'])
|
477
|
-
args = [mock(:type => :added),
|
478
|
-
mock(:type => :added)]
|
479
|
-
@it.should be_initial_add(args)
|
480
|
-
end
|
481
|
-
|
482
|
-
it "should not be an initial add if something is not an add" do
|
483
|
-
@it = CommandLine.new(['push', 'uri'])
|
484
|
-
args = [mock(:type => :foo),
|
485
|
-
mock(:type => :added)]
|
486
|
-
@it.should_not be_initial_add(args)
|
487
|
-
end
|
488
|
-
|
489
|
-
it "should be a design docs update if something changes in _design" do
|
490
|
-
@it = CommandLine.new(['push', 'uri'])
|
491
|
-
args = [mock(:path => "foo"),
|
492
|
-
mock(:path => "_design")]
|
493
|
-
@it.should be_design_doc_update(args)
|
494
|
-
end
|
495
|
-
|
496
|
-
it "should know document updates" do
|
497
|
-
@it = CommandLine.new(['push', 'uri'])
|
498
|
-
doc_update = mock(:path => "foo")
|
499
|
-
args = [doc_update,
|
500
|
-
mock(:path => "_design")]
|
501
|
-
|
502
|
-
@it.
|
503
|
-
documents(args).
|
504
|
-
should == [doc_update]
|
505
|
-
end
|
506
|
-
|
507
|
-
|
508
|
-
context "updates on the filesystem" do
|
509
|
-
before(:each) do
|
510
|
-
@args = mock("args")
|
511
|
-
@it = CommandLine.new(%w(push uri dir))
|
512
|
-
end
|
513
|
-
it "should only update design docs if only local design docs have changed" do
|
514
|
-
CouchDocs.
|
515
|
-
should_receive(:put_dir)
|
516
|
-
|
517
|
-
@it.stub!(:initial_add?).and_return(true)
|
518
|
-
@it.directory_watcher_update(@args)
|
519
|
-
end
|
520
|
-
context "not an inital add" do
|
521
|
-
before(:each) do
|
522
|
-
@it.stub!(:initial_add?).and_return(false)
|
523
|
-
@it.stub!(:design_doc_update?).and_return(false)
|
524
|
-
@it.stub!(:documents).and_return([])
|
525
|
-
CouchDocs.stub!(:put_design_dir)
|
526
|
-
end
|
527
|
-
it "should update design docs if there are design document updates" do
|
528
|
-
CouchDocs.
|
529
|
-
should_receive(:put_design_dir)
|
530
|
-
|
531
|
-
@it.stub!(:design_doc_update?).and_return(true)
|
532
|
-
@it.directory_watcher_update(@args)
|
533
|
-
end
|
534
|
-
it "should update documents (if any)" do
|
535
|
-
file_mock = mock("File", :path => "/foo")
|
536
|
-
@it.stub!(:documents).and_return([file_mock])
|
537
|
-
|
538
|
-
CouchDocs.
|
539
|
-
should_receive(:put_file).
|
540
|
-
with("uri", "/foo")
|
541
|
-
|
542
|
-
@it.directory_watcher_update(@args)
|
543
|
-
end
|
544
|
-
end
|
545
|
-
end
|
546
|
-
end
|
547
|
-
|
548
|
-
context "pushing" do
|
549
|
-
before(:each) do
|
550
|
-
CouchDocs.stub!(:put_dir)
|
551
|
-
|
552
|
-
@dw = mock("Directory Watcher").as_null_object
|
553
|
-
DirectoryWatcher.stub!(:new).and_return(@dw)
|
554
|
-
end
|
555
|
-
|
556
|
-
it "should know watch" do
|
557
|
-
@it = CommandLine.new(%w(push uri dir -w))
|
558
|
-
@it.options[:watch].should be_true
|
559
|
-
end
|
560
|
-
|
561
|
-
it "should run once normally" do
|
562
|
-
@dw.should_receive(:run_once)
|
563
|
-
|
564
|
-
@it = CommandLine.new(%w(push uri dir))
|
565
|
-
@it.run
|
566
|
-
end
|
567
|
-
|
568
|
-
it "should start a watcher with -w" do
|
569
|
-
@dw.should_receive(:start)
|
570
|
-
|
571
|
-
@it = CommandLine.new(%w(push uri dir -w))
|
572
|
-
@it.stub!(:active?).and_return(false)
|
573
|
-
@it.run
|
574
|
-
end
|
575
|
-
end
|
576
|
-
|
577
|
-
context "an instance that uploads to a CouchDB database" do
|
578
|
-
before(:each) do
|
579
|
-
@it = CommandLine.new(['load', 'dir', 'uri'])
|
580
|
-
end
|
581
|
-
|
582
|
-
it "should load CouchDB documents from dir to uri when run" do
|
583
|
-
CouchDocs.
|
584
|
-
should_receive(:put_dir).
|
585
|
-
with("uri", "dir")
|
586
|
-
|
587
|
-
@it.run
|
588
|
-
end
|
589
|
-
end
|
590
|
-
|
591
|
-
end
|
592
|
-
|
593
120
|
# EOF
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-cfs --color
|
data/spec/spec_helper.rb
CHANGED