eee-c-couch_docs 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,3 @@
1
+ == 0.9.0 / 2009-08-08
2
+
3
+ * Import from couch_design_docs (name change to reflect increased functionality)
data/README.rdoc ADDED
@@ -0,0 +1,66 @@
1
+ couch_docs
2
+ by Chris Strom
3
+ http://github.com/eee-c/couch_docs
4
+ (used to be couch_design_docs)
5
+
6
+ == DESCRIPTION:
7
+
8
+ Manage CouchDB views and documents.
9
+
10
+ == FEATURES/PROBLEMS:
11
+
12
+ * Store your CouchDB documents on the filesystem for on-demand
13
+ upload. Design documents are kept in a <tt>_design</tt>
14
+ sub-directory, with <tt>.js</tt> extensions. Normal documents are
15
+ stored with a <tt>.json</tt> extension.
16
+
17
+ == SYNOPSIS:
18
+
19
+ DB_URL = "http://localhost:5984/db"
20
+ DIRECTORY = "/repos/db/couchdb/"
21
+
22
+ # /repos/db/couchdb/_design/lucene/transform.js
23
+ # /repos/db/couchdb/foo.json
24
+
25
+ CouchDocs.put_dir(DB_URL, DIRECTORY)
26
+
27
+ # => lucene design document with a "transform" function containing
28
+ # the contents of transform.js
29
+ # - AND -
30
+ # a document named "foo" with the JSON contents from the foo.json
31
+ # file
32
+
33
+ == REQUIREMENTS:
34
+
35
+ * CouchDB
36
+ * JSON
37
+ * RestClient
38
+
39
+ == INSTALL:
40
+
41
+ * sudo gem install couch_docs
42
+
43
+ == LICENSE:
44
+
45
+ (The MIT License)
46
+
47
+ Copyright (c) 2009
48
+
49
+ Permission is hereby granted, free of charge, to any person obtaining
50
+ a copy of this software and associated documentation files (the
51
+ 'Software'), to deal in the Software without restriction, including
52
+ without limitation the rights to use, copy, modify, merge, publish,
53
+ distribute, sublicense, and/or sell copies of the Software, and to
54
+ permit persons to whom the Software is furnished to do so, subject to
55
+ the following conditions:
56
+
57
+ The above copyright notice and this permission notice shall be
58
+ included in all copies or substantial portions of the Software.
59
+
60
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
61
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
62
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
63
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
64
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
65
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
66
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ # Look in the tasks/setup.rb file for the various options that can be
2
+ # configured in this Rakefile. The .rake files in the tasks directory
3
+ # are where the options are used.
4
+
5
+ begin
6
+ require 'bones'
7
+ Bones.setup
8
+ rescue LoadError
9
+ begin
10
+ load 'tasks/setup.rb'
11
+ rescue LoadError
12
+ raise RuntimeError, '### please install the "bones" gem ###'
13
+ end
14
+ end
15
+
16
+ ensure_in_path 'lib'
17
+ require 'couch_docs'
18
+
19
+ task :default => 'spec:run'
20
+
21
+ PROJ.name = 'couch_docs'
22
+ PROJ.authors = 'Chris Strom'
23
+ PROJ.email = 'chris@eeecooks.com'
24
+ PROJ.url = 'http://github.com/eee-c/couch_docs'
25
+ PROJ.version = CouchDocs::VERSION
26
+ PROJ.rubyforge.name = 'couch_docs'
27
+
28
+ PROJ.spec.opts << '--color'
29
+
30
+ PROJ.gem.dependencies = %w{json rest-client}
31
+
32
+ PROJ.readme_file = 'README.rdoc'
33
+
34
+ depend_on 'rest-client'
35
+ depend_on 'json'
36
+
37
+ # EOF
data/bin/couch-docs ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(
4
+ File.join(File.dirname(__FILE__), %w[.. lib couch_docs]))
5
+
6
+ # Put your code here
7
+
8
+ CouchDocs::CommandLine.run ARGV
9
+
10
+ # EOF
@@ -0,0 +1,49 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{couch_docs}
5
+ s.version = "0.9.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Chris Strom"]
9
+ s.date = %q{2009-08-09}
10
+ s.default_executable = %q{couch-docs}
11
+ s.description = %q{Manage CouchDB views and documents.}
12
+ s.email = %q{chris@eeecooks.com}
13
+ s.executables = ["couch-docs"]
14
+ s.extra_rdoc_files = ["History.txt", "README.rdoc", "bin/couch-docs"]
15
+ s.files = ["History.txt", "README.rdoc", "Rakefile", "bin/couch-docs", "couch_docs.gemspec", "fixtures/_design/a/b/c.js", "fixtures/_design/a/b/d.js", "fixtures/bar.json", "fixtures/foo.json", "lib/couch_docs.rb", "lib/couch_docs/command_line.rb", "lib/couch_docs/design_directory.rb", "lib/couch_docs/document_directory.rb", "lib/couch_docs/store.rb", "spec/couch_docs_spec.rb", "spec/spec_helper.rb", "test/test_couch_docs.rb"]
16
+ s.has_rdoc = true
17
+ s.homepage = %q{http://github.com/eee-c/couch_docs}
18
+ s.rdoc_options = ["--main", "README.rdoc"]
19
+ s.require_paths = ["lib"]
20
+ s.rubyforge_project = %q{couch_docs}
21
+ s.rubygems_version = %q{1.3.1}
22
+ s.summary = %q{Manage CouchDB views and documents}
23
+ s.test_files = ["test/test_couch_docs.rb"]
24
+
25
+ if s.respond_to? :specification_version then
26
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
27
+ s.specification_version = 2
28
+
29
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
30
+ s.add_runtime_dependency(%q<json>, [">= 0"])
31
+ s.add_runtime_dependency(%q<rest-client>, [">= 0"])
32
+ s.add_runtime_dependency(%q<rest-client>, [">= 1.0.3"])
33
+ s.add_runtime_dependency(%q<json>, [">= 1.1.6"])
34
+ s.add_development_dependency(%q<bones>, [">= 2.5.1"])
35
+ else
36
+ s.add_dependency(%q<json>, [">= 0"])
37
+ s.add_dependency(%q<rest-client>, [">= 0"])
38
+ s.add_dependency(%q<rest-client>, [">= 1.0.3"])
39
+ s.add_dependency(%q<json>, [">= 1.1.6"])
40
+ s.add_dependency(%q<bones>, [">= 2.5.1"])
41
+ end
42
+ else
43
+ s.add_dependency(%q<json>, [">= 0"])
44
+ s.add_dependency(%q<rest-client>, [">= 0"])
45
+ s.add_dependency(%q<rest-client>, [">= 1.0.3"])
46
+ s.add_dependency(%q<json>, [">= 1.1.6"])
47
+ s.add_dependency(%q<bones>, [">= 2.5.1"])
48
+ end
49
+ end
@@ -0,0 +1 @@
1
+ function(doc) { return true; }
@@ -0,0 +1 @@
1
+ function(doc) { return true; }
data/fixtures/bar.json ADDED
@@ -0,0 +1 @@
1
+ {"bar":"2"}
data/fixtures/foo.json ADDED
@@ -0,0 +1 @@
1
+ {"foo":"1"}
data/lib/couch_docs.rb ADDED
@@ -0,0 +1,94 @@
1
+ module CouchDocs
2
+
3
+ # :stopdoc:
4
+ VERSION = '0.9.0'
5
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
6
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
7
+ # :startdoc:
8
+
9
+ # Returns the version string for the library.
10
+ #
11
+ def self.version
12
+ VERSION
13
+ end
14
+
15
+ # For a CouchDB database described by <tt>db_uri</tt> and a
16
+ # directory, <tt>dir</tt> containing design documents, creates
17
+ # design documents in the CouchDB database
18
+ #
19
+ def self.put_dir(db_uri, dir)
20
+ self.put_design_dir(db_uri, "#{dir}/_design")
21
+ self.put_document_dir(db_uri, dir)
22
+ end
23
+
24
+ # Alias for <tt>put_dir</tt>
25
+ def self.upload_dir(db_uri, dir)
26
+ self.put_dir(db_uri, dir)
27
+ end
28
+
29
+ # Upload design documents from <tt>dir</tt> to the CouchDB database
30
+ # located at <tt>db_uri</tt>
31
+ #
32
+ def self.put_design_dir(db_uri, dir)
33
+ store = Store.new(db_uri)
34
+ dir = DesignDirectory.new(dir)
35
+ store.put_design_documents(dir.to_hash)
36
+ end
37
+
38
+ # Upload documents from <tt>dir</tt> to the CouchDB database
39
+ # located at <tt>db_uri</tt>
40
+ #
41
+ def self.put_document_dir(db_uri, dir)
42
+ store = Store.new(db_uri)
43
+ dir = DocumentDirectory.new(dir)
44
+ dir.each_document do |name, contents|
45
+ Store.put!("#{db_uri}/#{name}", contents)
46
+ end
47
+ end
48
+
49
+ # Dump all documents located at <tt>db_uri</tt> into the directory
50
+ # <tt>dir</tt>
51
+ #
52
+ def self.dump(db_uri, dir)
53
+ store = Store.new(db_uri)
54
+ dir = DocumentDirectory.new(dir)
55
+ store.
56
+ map.
57
+ reject { |doc| doc['_id'] =~ /^_design/ }.
58
+ each { |doc| dir.store_document(doc) }
59
+ end
60
+
61
+ # Returns the library path for the module. If any arguments are given,
62
+ # they will be joined to the end of the libray path using
63
+ # <tt>File.join</tt>.
64
+ #
65
+ def self.libpath( *args )
66
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
67
+ end
68
+
69
+ # Returns the lpath for the module. If any arguments are given,
70
+ # they will be joined to the end of the path using
71
+ # <tt>File.join</tt>.
72
+ #
73
+ def self.path( *args )
74
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
75
+ end
76
+
77
+ # Utility method used to require all files ending in .rb that lie in the
78
+ # directory below this file that has the same name as the filename passed
79
+ # in. Optionally, a specific _directory_ name can be passed in such that
80
+ # the _filename_ does not have to be equivalent to the directory.
81
+ #
82
+ def self.require_all_libs_relative_to( fname, dir = nil )
83
+ dir ||= ::File.basename(fname, '.*')
84
+ search_me = ::File.expand_path(
85
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
86
+
87
+ Dir.glob(search_me).sort.each {|rb| require rb}
88
+ end
89
+
90
+ end # module CouchDocs
91
+
92
+ CouchDocs.require_all_libs_relative_to(__FILE__)
93
+
94
+ # EOF
@@ -0,0 +1,28 @@
1
+ module CouchDocs
2
+ class CommandLine
3
+ def self.run(*args)
4
+ CommandLine.new(*args).run
5
+ end
6
+
7
+ attr_accessor :command, :options
8
+
9
+ def initialize(args)
10
+ @command = args.shift
11
+ @options = args
12
+ end
13
+
14
+ def run
15
+ case command
16
+ when "dump"
17
+ CouchDocs.dump(*options)
18
+ when "load"
19
+ CouchDocs.put_document_dir(*options.reverse)
20
+ when "help", "--help", "-h"
21
+ puts "#{$0} load dir couchdb_uri"
22
+ puts "#{$0} dump couchdb_uri dir"
23
+ else
24
+ raise ArgumentError.new("Unknown command #{command}")
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,46 @@
1
+ class Hash
2
+ def deep_merge(other)
3
+ self.merge(other) do |key, oldval, newval|
4
+ oldval.deep_merge(newval)
5
+ end
6
+ end
7
+ end
8
+
9
+ module CouchDocs
10
+ class DesignDirectory
11
+
12
+ attr_accessor :couch_view_dir
13
+
14
+ def self.a_to_hash(a)
15
+ key = a.first
16
+ if (a.length > 2)
17
+ { key => a_to_hash(a[1,a.length]) }
18
+ else
19
+ { key => a.last }
20
+ end
21
+ end
22
+
23
+ def initialize(path)
24
+ Dir.new(path) # Just checkin'
25
+ @couch_view_dir = path
26
+ end
27
+
28
+ def to_hash
29
+ Dir["#{couch_view_dir}/**/*.js"].inject({}) do |memo, filename|
30
+ DesignDirectory.
31
+ a_to_hash(expand_file(filename)).
32
+ deep_merge(memo)
33
+ end
34
+ end
35
+
36
+ def expand_file(filename)
37
+ File.dirname(filename).
38
+ gsub(/#{couch_view_dir}\/?/, '').
39
+ split(/\//) +
40
+ [
41
+ File.basename(filename, '.js'),
42
+ File.new(filename).read
43
+ ]
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ module CouchDocs
2
+ class DocumentDirectory
3
+
4
+ attr_accessor :couch_doc_dir
5
+
6
+ def initialize(path)
7
+ Dir.new(path)
8
+ @couch_doc_dir = path
9
+ end
10
+
11
+ def each_document
12
+ Dir["#{couch_doc_dir}/*.json"].each do |filename|
13
+ yield [ File.basename(filename, '.json'),
14
+ JSON.parse(File.new(filename).read) ]
15
+
16
+ end
17
+ end
18
+
19
+ def store_document(doc)
20
+ file = File.new("#{couch_doc_dir}/#{doc['_id']}.json", "w+")
21
+ file.write(doc.to_json)
22
+ file.close
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,64 @@
1
+ require 'rubygems'
2
+ require 'restclient'
3
+ require 'json'
4
+
5
+ module CouchDocs
6
+ class Store
7
+ include Enumerable
8
+
9
+ attr_accessor :url
10
+
11
+ # Initialize a CouchDB store object. Requires a URL for the
12
+ # target CouchDB database.
13
+ #
14
+ def initialize(url)
15
+ @url = url
16
+ end
17
+
18
+ # Loads all supplied design documents in the current store.
19
+ # Given a hash <tt>h</tt>, the keys being the CouchDB document
20
+ # name and values of design documents
21
+ #
22
+ def put_design_documents(h)
23
+ h.each_pair do |document_name, doc|
24
+ Store.put!("#{url}/_design/#{document_name}", doc)
25
+ end
26
+ end
27
+
28
+ # Create or replace the document located at <tt>path</tt> with the
29
+ # Hash document <tt>doc</tt>
30
+ #
31
+ def self.put!(path, doc)
32
+ self.put(path, doc)
33
+ rescue RestClient::RequestFailed
34
+ self.delete_and_put(path, doc)
35
+ end
36
+
37
+ def self.delete_and_put(path, doc)
38
+ self.delete(path)
39
+ self.put(path, doc)
40
+ end
41
+
42
+ def self.put(path, doc)
43
+ RestClient.put path,
44
+ doc.to_json,
45
+ :content_type => 'application/json'
46
+ end
47
+
48
+ def self.delete(path)
49
+ # retrieve existing to obtain the revision
50
+ old = self.get(path)
51
+ RestClient.delete(path + "?rev=#{old['_rev']}")
52
+ end
53
+
54
+ def self.get(path)
55
+ JSON.parse(RestClient.get(path))
56
+ end
57
+
58
+ def each
59
+ Store.get("#{url}/_all_docs")['rows'].each do |rec|
60
+ yield Store.get("#{url}/#{rec['id']}")
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,320 @@
1
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
2
+
3
+ describe CouchDocs do
4
+ it "should be able to load design and normal documents" do
5
+ CouchDocs.
6
+ should_receive(:put_design_dir).
7
+ with("uri", "fixtures/_design")
8
+
9
+ CouchDocs.
10
+ should_receive(:put_document_dir).
11
+ with("uri", "fixtures")
12
+
13
+ CouchDocs.put_dir("uri", "fixtures")
14
+ end
15
+
16
+ it "should be able to load directory/JS files into CouchDB as design docs" do
17
+ store = mock("Store")
18
+ Store.stub!(:new).and_return(store)
19
+
20
+ dir = mock("Design Directory")
21
+ dir.stub!(:to_hash).and_return({ "foo" => "bar" })
22
+ DesignDirectory.stub!(:new).and_return(dir)
23
+
24
+ store.
25
+ should_receive(:put_design_documents).
26
+ with({ "foo" => "bar" })
27
+
28
+ CouchDocs.put_design_dir("uri", "fixtures")
29
+ end
30
+
31
+ it "should be able to load documents into CouchDB" do
32
+ store = mock("Store")
33
+ Store.stub!(:new).and_return(store)
34
+
35
+ dir = mock("Document Directory")
36
+ dir.
37
+ stub!(:each_document).
38
+ and_yield('foo', {"foo" => "1"})
39
+
40
+ DocumentDirectory.stub!(:new).and_return(dir)
41
+
42
+ Store.
43
+ should_receive(:put!).
44
+ with('uri/foo', {"foo" => "1"})
45
+
46
+ CouchDocs.put_document_dir("uri", "fixtures")
47
+ end
48
+
49
+ context "dumping CouchDB documents to a directory" do
50
+ before(:each) do
51
+ @store = mock("Store")
52
+ Store.stub!(:new).and_return(@store)
53
+
54
+ @dir = mock("Document Directory")
55
+ DocumentDirectory.stub!(:new).and_return(@dir)
56
+ end
57
+ it "should be able to store all CouchDB documents on the filesystem" do
58
+ @store.stub!(:map).and_return([{'_id' => 'foo'}])
59
+ @dir.
60
+ should_receive(:store_document).
61
+ with({'_id' => 'foo'})
62
+
63
+ CouchDocs.dump("uri", "fixtures")
64
+ end
65
+ it "should be able to store all CouchDB documents on the filesystem" do
66
+ @store.stub!(:map).and_return([{'_id' => '_design/foo'}])
67
+ @dir.
68
+ should_not_receive(:store_document)
69
+
70
+ CouchDocs.dump("uri", "fixtures")
71
+ end
72
+ end
73
+ end
74
+
75
+
76
+ describe Store do
77
+ it "should require a CouchDB URL Root for instantiation" do
78
+ lambda { Store.new }.
79
+ should raise_error
80
+
81
+ lambda { Store.new("uri") }.
82
+ should_not raise_error
83
+ end
84
+
85
+ context "a valid store" do
86
+ before(:each) do
87
+ @it = Store.new("uri")
88
+
89
+ @hash = {
90
+ 'a' => {
91
+ 'b' => {
92
+ 'c' => 'function(doc) { return true; }'
93
+ }
94
+ }
95
+ }
96
+ end
97
+
98
+ it "should be able to put a new document" do
99
+ Store.
100
+ should_receive(:put).
101
+ with("uri", { })
102
+
103
+ Store.put!("uri", { })
104
+ end
105
+
106
+ it "should delete existing docs if first put fails" do
107
+ Store.
108
+ stub!(:put).
109
+ and_raise(RestClient::RequestFailed)
110
+
111
+ Store.
112
+ should_receive(:delete_and_put).
113
+ with("uri", { })
114
+
115
+ Store.put!("uri", { })
116
+ end
117
+
118
+ it "should be able to delete and put" do
119
+ Store.
120
+ should_receive(:delete).
121
+ with("uri")
122
+
123
+ Store.
124
+ should_receive(:put).
125
+ with("uri", { })
126
+
127
+ Store.delete_and_put("uri", { })
128
+ end
129
+
130
+ it "should be able to load a hash into design docs" do
131
+ RestClient.
132
+ should_receive(:put).
133
+ with("uri/_design/a",
134
+ '{"b":{"c":"function(doc) { return true; }"}}',
135
+ :content_type => 'application/json')
136
+ @it.put_design_documents(@hash)
137
+ end
138
+
139
+ it "should be able to retrieve an existing document" do
140
+ RestClient.
141
+ stub!(:get).
142
+ and_return('{"_rev":"1234"}')
143
+
144
+ Store.get("uri").should == { '_rev' => "1234" }
145
+ end
146
+
147
+ it "should be able to delete an existing document" do
148
+ Store.stub!(:get).and_return({ '_rev' => '1234' })
149
+
150
+ RestClient.
151
+ should_receive(:delete).
152
+ with("uri?rev=1234")
153
+
154
+ Store.delete("uri")
155
+ end
156
+
157
+ it "should be able to load each document" do
158
+ Store.stub!(:get).
159
+ with("uri/_all_docs").
160
+ and_return({ "total_rows" => 2,
161
+ "offset" => 0,
162
+ "rows" => [{"id"=>"1", "value"=>{}, "key"=>"1"},
163
+ {"id"=>"2", "value"=>{}, "key"=>"2"}]})
164
+
165
+ Store.stub!(:get).with("uri/1")
166
+ Store.should_receive(:get).with("uri/2")
167
+
168
+ @it.each { }
169
+ end
170
+ end
171
+ end
172
+
173
+ describe DocumentDirectory do
174
+ it "should require a root directory for instantiation" do
175
+ lambda { DocumentDirectory.new }.
176
+ should raise_error
177
+
178
+ lambda { DocumentDirectory.new("foo") }.
179
+ should raise_error
180
+
181
+ lambda { DocumentDirectory.new("fixtures")}.
182
+ should_not raise_error
183
+ end
184
+
185
+ context "a valid directory" do
186
+ before(:each) do
187
+ @it = DocumentDirectory.new("fixtures")
188
+ end
189
+
190
+ it "should be able to iterate over the documents" do
191
+ everything = []
192
+ @it.each_document do |name, contents|
193
+ everything << [name, contents]
194
+ end
195
+ everything.
196
+ should == [['bar', {"bar" => "2"}],
197
+ ['foo', {"foo" => "1"}]]
198
+ end
199
+
200
+ it "should be able to store a document" do
201
+ file = mock("File", :write => 42, :close => true)
202
+ File.
203
+ should_receive(:new).
204
+ with("fixtures/foo.json", "w+").
205
+ and_return(file)
206
+
207
+ @it.store_document({'_id' => 'foo'})
208
+ end
209
+
210
+ it "should be able to save a document as JSON" do
211
+ file = mock("File", :close => true)
212
+ File.stub!(:new).and_return(file)
213
+
214
+ file.should_receive(:write).with(%Q|{"_id":"foo"}|)
215
+
216
+ @it.store_document({'_id' => 'foo'})
217
+ end
218
+ end
219
+ end
220
+
221
+ describe DesignDirectory do
222
+ it "should require a root directory for instantiation" do
223
+ lambda { DesignDirectory.new }.
224
+ should raise_error
225
+
226
+ lambda { DesignDirectory.new("foo") }.
227
+ should raise_error
228
+
229
+ lambda { DesignDirectory.new("fixtures/_design")}.
230
+ should_not raise_error
231
+ end
232
+
233
+ it "should convert arrays into deep hashes" do
234
+ DesignDirectory.
235
+ a_to_hash(%w{a b c d}).
236
+ should == {
237
+ 'a' => {
238
+ 'b' => {
239
+ 'c' => 'd'
240
+ }
241
+ }
242
+ }
243
+ end
244
+
245
+ context "a valid directory" do
246
+ before(:each) do
247
+ @it = DesignDirectory.new("fixtures/_design")
248
+ end
249
+
250
+ it "should list dirs, basename and contents of a file" do
251
+ @it.expand_file("fixtures/_design/a/b/c.js").
252
+ should == ['a', 'b', 'c', 'function(doc) { return true; }']
253
+ end
254
+
255
+ it "should assemble all documents into a single docs structure" do
256
+ @it.to_hash.
257
+ should == {
258
+ 'a' => {
259
+ 'b' => {
260
+ 'c' => 'function(doc) { return true; }',
261
+ 'd' => 'function(doc) { return true; }'
262
+ }
263
+ }
264
+
265
+ }
266
+ end
267
+ end
268
+ end
269
+
270
+ describe CommandLine do
271
+ it "should be able to run a single instance of a command line" do
272
+ CommandLine.
273
+ should_receive(:new).
274
+ with('foo', 'bar').
275
+ and_return(mock("Command Line").as_null_object)
276
+
277
+ CommandLine.run('foo', 'bar')
278
+ end
279
+
280
+ it "should run the command line instance" do
281
+ command_line = mock("Command Line").as_null_object
282
+ command_line.
283
+ should_receive(:run)
284
+
285
+ CommandLine.stub!(:new).and_return(command_line)
286
+
287
+ CommandLine.run('foo', 'bar')
288
+ end
289
+
290
+ context "an instance that dumps a CouchDB database" do
291
+ before(:each) do
292
+ @it = CommandLine.new(['dump', 'uri', 'dir'])
293
+ end
294
+
295
+ it "should dump CouchDB documents from uri to dir when run" do
296
+ CouchDocs.
297
+ should_receive(:dump).
298
+ with("uri", "dir")
299
+
300
+ @it.run
301
+ end
302
+ end
303
+
304
+ context "an instance that uploads to a CouchDB database" do
305
+ before(:each) do
306
+ @it = CommandLine.new(['load', 'dir', 'uri'])
307
+ end
308
+
309
+ it "should dump CouchDB documents from uri to dir when run" do
310
+ CouchDocs.
311
+ should_receive(:put_document_dir).
312
+ with("uri", "dir")
313
+
314
+ @it.run
315
+ end
316
+ end
317
+
318
+ end
319
+
320
+ # EOF
@@ -0,0 +1,18 @@
1
+
2
+ require File.expand_path(
3
+ File.join(File.dirname(__FILE__), %w[.. lib couch_docs]))
4
+
5
+ include CouchDocs
6
+
7
+ Spec::Runner.configure do |config|
8
+ # == Mock Framework
9
+ #
10
+ # RSpec uses it's own mocking framework by default. If you prefer to
11
+ # use mocha, flexmock or RR, uncomment the appropriate line:
12
+ #
13
+ # config.mock_with :mocha
14
+ # config.mock_with :flexmock
15
+ # config.mock_with :rr
16
+ end
17
+
18
+ # EOF
File without changes
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eee-c-couch_docs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Chris Strom
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-09 00:00:00 -07:00
13
+ default_executable: couch-docs
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: json
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rest-client
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: rest-client
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.3
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: json
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.1.6
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: bones
57
+ type: :development
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 2.5.1
64
+ version:
65
+ description: Manage CouchDB views and documents.
66
+ email: chris@eeecooks.com
67
+ executables:
68
+ - couch-docs
69
+ extensions: []
70
+
71
+ extra_rdoc_files:
72
+ - History.txt
73
+ - README.rdoc
74
+ - bin/couch-docs
75
+ files:
76
+ - History.txt
77
+ - README.rdoc
78
+ - Rakefile
79
+ - bin/couch-docs
80
+ - couch_docs.gemspec
81
+ - fixtures/_design/a/b/c.js
82
+ - fixtures/_design/a/b/d.js
83
+ - fixtures/bar.json
84
+ - fixtures/foo.json
85
+ - lib/couch_docs.rb
86
+ - lib/couch_docs/command_line.rb
87
+ - lib/couch_docs/design_directory.rb
88
+ - lib/couch_docs/document_directory.rb
89
+ - lib/couch_docs/store.rb
90
+ - spec/couch_docs_spec.rb
91
+ - spec/spec_helper.rb
92
+ - test/test_couch_docs.rb
93
+ has_rdoc: true
94
+ homepage: http://github.com/eee-c/couch_docs
95
+ licenses:
96
+ post_install_message:
97
+ rdoc_options:
98
+ - --main
99
+ - README.rdoc
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: "0"
107
+ version:
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: "0"
113
+ version:
114
+ requirements: []
115
+
116
+ rubyforge_project: couch_docs
117
+ rubygems_version: 1.3.5
118
+ signing_key:
119
+ specification_version: 2
120
+ summary: Manage CouchDB views and documents
121
+ test_files:
122
+ - test/test_couch_docs.rb