couchrest 0.12.2 → 0.12.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -2
- data/Rakefile +1 -38
- data/examples/word_count/word_count.rb +3 -24
- data/examples/word_count/word_count_query.rb +7 -6
- data/examples/word_count/word_count_views.rb +26 -0
- data/lib/couchrest/core/document.rb +12 -0
- data/lib/couchrest/core/model.rb +7 -1
- data/lib/couchrest/monkeypatches.rb +15 -1
- data/lib/couchrest.rb +1 -2
- data/spec/couchrest/core/database_spec.rb +0 -1
- data/spec/couchrest/core/document_spec.rb +83 -0
- metadata +5 -15
- data/bin/couchdir +0 -20
data/README.md
CHANGED
@@ -6,8 +6,7 @@ which I find to be concise, clear, and well designed. CouchRest lightly wraps
|
|
6
6
|
CouchDB's HTTP API, managing JSON serialization, and remembering the URI-paths
|
7
7
|
to CouchDB's API endpoints so you don't have to.
|
8
8
|
|
9
|
-
CouchRest
|
10
|
-
framework-specific object oriented APIs.
|
9
|
+
CouchRest is designed to make a simple base for application and framework-specific object oriented APIs. CouchRest is Object-Mapper agnostic, the parsed JSON it returns from CouchDB shows up as subclasses of Ruby's Hash. Naked JSON, just as it was mean to be.
|
11
10
|
|
12
11
|
## Easy Install
|
13
12
|
|
data/Rakefile
CHANGED
@@ -25,16 +25,13 @@ spec = Gem::Specification.new do |s|
|
|
25
25
|
s.has_rdoc = true
|
26
26
|
s.authors = ["J. Chris Anderson"]
|
27
27
|
s.files = %w( LICENSE README.md Rakefile THANKS.md ) +
|
28
|
-
Dir["{
|
28
|
+
Dir["{examples,lib,spec,utils}/**/*"] -
|
29
29
|
Dir["spec/tmp"]
|
30
30
|
s.extra_rdoc_files = %w( README.md LICENSE THANKS.md )
|
31
31
|
s.require_path = "lib"
|
32
|
-
s.bindir = 'bin'
|
33
|
-
s.executables << 'couchdir'
|
34
32
|
s.add_dependency("json", ">= 1.1.2")
|
35
33
|
s.add_dependency("rest-client", ">= 0.5")
|
36
34
|
s.add_dependency("mime-types", ">= 1.15")
|
37
|
-
s.add_dependency("extlib", ">= 0.9.6")
|
38
35
|
end
|
39
36
|
|
40
37
|
|
@@ -46,40 +43,6 @@ task :gemspec do
|
|
46
43
|
end
|
47
44
|
end
|
48
45
|
|
49
|
-
# desc "Update Github Gemspec"
|
50
|
-
# task :gemspec do
|
51
|
-
# skip_fields = %w(new_platform original_platform)
|
52
|
-
# integer_fields = %w(specification_version)
|
53
|
-
#
|
54
|
-
# result = "Gem::Specification.new do |s|\n"
|
55
|
-
# spec.instance_variables.each do |ivar|
|
56
|
-
# value = spec.instance_variable_get(ivar)
|
57
|
-
# name = ivar.split("@").last
|
58
|
-
# next if skip_fields.include?(name) || value.nil? || value == "" || (value.respond_to?(:empty?) && value.empty?)
|
59
|
-
# if name == "dependencies"
|
60
|
-
# value.each do |d|
|
61
|
-
# dep, *ver = d.to_s.split(" ")
|
62
|
-
# result << " s.add_dependency #{dep.inspect}, [#{ /\(([^\,]*)/ . match(ver.join(" "))[1].inspect}]\n"
|
63
|
-
# end
|
64
|
-
# else
|
65
|
-
# case value
|
66
|
-
# when Array
|
67
|
-
# value = name != "files" ? value.inspect : value.inspect.split(",").join(",\n")
|
68
|
-
# when Fixnum
|
69
|
-
# # leave as-is
|
70
|
-
# when String
|
71
|
-
# value = value.to_i if integer_fields.include?(name)
|
72
|
-
# value = value.inspect
|
73
|
-
# else
|
74
|
-
# value = value.to_s.inspect
|
75
|
-
# end
|
76
|
-
# result << " s.#{name} = #{value}\n"
|
77
|
-
# end
|
78
|
-
# end
|
79
|
-
# result << "end"
|
80
|
-
# File.open(File.join(File.dirname(__FILE__), "#{spec.name}.gemspec"), "w"){|f| f << result}
|
81
|
-
# end
|
82
|
-
|
83
46
|
desc "Run all specs"
|
84
47
|
Spec::Rake::SpecTask.new('spec') do |t|
|
85
48
|
t.spec_files = FileList['spec/**/*_spec.rb']
|
@@ -1,4 +1,5 @@
|
|
1
|
-
require
|
1
|
+
require 'rubygems'
|
2
|
+
require 'couchrest'
|
2
3
|
|
3
4
|
couch = CouchRest.new("http://127.0.0.1:5984")
|
4
5
|
db = couch.database('word-count-example')
|
@@ -39,29 +40,7 @@ books.keys.each do |book|
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
end
|
42
|
-
|
43
|
-
# word_count = {
|
44
|
-
# :map => 'function(doc){
|
45
|
-
# var words = doc.text.split(/\W/);
|
46
|
-
# words.forEach(function(word){
|
47
|
-
# if (word.length > 0) emit([word,doc.title],1);
|
48
|
-
# });
|
49
|
-
# }',
|
50
|
-
# :reduce => 'function(key,combine){
|
51
|
-
# return sum(combine);
|
52
|
-
# }'
|
53
|
-
# }
|
54
|
-
#
|
55
|
-
# db.delete db.get("_design/word_count") rescue nil
|
56
|
-
#
|
57
|
-
# db.save({
|
58
|
-
# "_id" => "_design/word_count",
|
59
|
-
# :views => {
|
60
|
-
# :count => word_count,
|
61
|
-
# :words => {:map => word_count[:map]}
|
62
|
-
# }
|
63
|
-
# })
|
64
43
|
|
65
44
|
# puts "The books have been stored in your CouchDB. To initiate the MapReduce process, visit http://127.0.0.1:5984/_utils/ in your browser and click 'word-count-example', then select view 'words' or 'count'. The process could take about 15 minutes on an average MacBook."
|
66
|
-
|
45
|
+
|
67
46
|
|
@@ -1,22 +1,23 @@
|
|
1
|
-
require
|
1
|
+
require 'rubygems'
|
2
|
+
require 'couchrest'
|
2
3
|
|
3
4
|
couch = CouchRest.new("http://127.0.0.1:5984")
|
4
5
|
db = couch.database('word-count-example')
|
5
6
|
|
6
7
|
puts "Now that we've parsed all those books into CouchDB, the queries we can run are incredibly flexible."
|
7
8
|
puts "\nThe simplest query we can run is the total word count for all words in all documents:"
|
8
|
-
|
9
|
-
puts db.view('word_count/
|
9
|
+
puts "this will take a few minutes the first time. if it times out, just rerun this script in a few few minutes."
|
10
|
+
puts db.view('word_count/words').inspect
|
10
11
|
|
11
12
|
puts "\nWe can also narrow the query down to just one word, across all documents. Here is the count for 'flight' in all three books:"
|
12
13
|
|
13
14
|
word = 'flight'
|
14
15
|
params = {
|
15
16
|
:startkey => [word],
|
16
|
-
:endkey => [word,
|
17
|
+
:endkey => [word,{}]
|
17
18
|
}
|
18
19
|
|
19
|
-
puts db.view('word_count/
|
20
|
+
puts db.view('word_count/words',params).inspect
|
20
21
|
|
21
22
|
puts "\nWe scope the query using startkey and endkey params to take advantage of CouchDB's collation ordering. Here are the params for the last query:"
|
22
23
|
puts params.inspect
|
@@ -28,7 +29,7 @@ params = {
|
|
28
29
|
:key => [word, title]
|
29
30
|
}
|
30
31
|
|
31
|
-
puts db.view('word_count/
|
32
|
+
puts db.view('word_count/words',params).inspect
|
32
33
|
|
33
34
|
|
34
35
|
puts "\nHere are the params for 'flight' in the da-vinci book:"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'couchrest'
|
3
|
+
|
4
|
+
couch = CouchRest.new("http://127.0.0.1:5984")
|
5
|
+
db = couch.database('word-count-example')
|
6
|
+
|
7
|
+
word_count = {
|
8
|
+
:map => 'function(doc){
|
9
|
+
var words = doc.text.split(/\W/);
|
10
|
+
words.forEach(function(word){
|
11
|
+
if (word.length > 0) emit([word,doc.title],1);
|
12
|
+
});
|
13
|
+
}',
|
14
|
+
:reduce => 'function(key,combine){
|
15
|
+
return sum(combine);
|
16
|
+
}'
|
17
|
+
}
|
18
|
+
|
19
|
+
db.delete db.get("_design/word_count") rescue nil
|
20
|
+
|
21
|
+
db.save({
|
22
|
+
"_id" => "_design/word_count",
|
23
|
+
:views => {
|
24
|
+
:words => word_count
|
25
|
+
}
|
26
|
+
})
|
@@ -56,6 +56,18 @@ module CouchRest
|
|
56
56
|
end
|
57
57
|
result['ok']
|
58
58
|
end
|
59
|
+
|
60
|
+
def copy(dest)
|
61
|
+
raise ArgumentError, "doc.database required to copy" unless database
|
62
|
+
result = database.copy(self, dest)
|
63
|
+
result['ok']
|
64
|
+
end
|
65
|
+
|
66
|
+
def move(dest)
|
67
|
+
raise ArgumentError, "doc.database required to copy" unless database
|
68
|
+
result = database.move(self, dest)
|
69
|
+
result['ok']
|
70
|
+
end
|
59
71
|
|
60
72
|
end
|
61
73
|
|
data/lib/couchrest/core/model.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
|
2
|
+
begin
|
3
|
+
require 'extlib'
|
4
|
+
rescue
|
5
|
+
puts "CouchRest::Model requires extlib. This is left out of the gemspec on purpose."
|
6
|
+
raise
|
7
|
+
end
|
3
8
|
require 'digest/md5'
|
4
9
|
require File.dirname(__FILE__) + '/document'
|
5
10
|
require 'mime/types'
|
@@ -439,6 +444,7 @@ module CouchRest
|
|
439
444
|
saved['views'][name] = view
|
440
445
|
end
|
441
446
|
database.save(saved)
|
447
|
+
self.design_doc = saved
|
442
448
|
else
|
443
449
|
design_doc['_id'] = did
|
444
450
|
design_doc.delete('_rev')
|
@@ -8,7 +8,7 @@ class Time
|
|
8
8
|
|
9
9
|
def to_json(options = nil)
|
10
10
|
u = self.utc
|
11
|
-
%("#{u.strftime("%Y/%m/%d %H:%M:%S
|
11
|
+
%("#{u.strftime("%Y/%m/%d %H:%M:%S +0000")}")
|
12
12
|
end
|
13
13
|
|
14
14
|
# Decodes the JSON time format to a UTC time.
|
@@ -21,4 +21,18 @@ class Time
|
|
21
21
|
# rescue
|
22
22
|
# fallback
|
23
23
|
# end
|
24
|
+
end
|
25
|
+
|
26
|
+
module RestClient
|
27
|
+
def self.copy(url, headers={})
|
28
|
+
Request.execute(:method => :copy,
|
29
|
+
:url => url,
|
30
|
+
:headers => headers)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.move(url, headers={})
|
34
|
+
Request.execute(:method => :move,
|
35
|
+
:url => url,
|
36
|
+
:headers => headers)
|
37
|
+
end
|
24
38
|
end
|
data/lib/couchrest.rb
CHANGED
@@ -15,7 +15,6 @@
|
|
15
15
|
require "rubygems"
|
16
16
|
require 'json'
|
17
17
|
require 'rest_client'
|
18
|
-
# require 'extlib'
|
19
18
|
|
20
19
|
$:.unshift File.dirname(__FILE__) unless
|
21
20
|
$:.include?(File.dirname(__FILE__)) ||
|
@@ -26,7 +25,7 @@ require 'couchrest/monkeypatches'
|
|
26
25
|
|
27
26
|
# = CouchDB, close to the metal
|
28
27
|
module CouchRest
|
29
|
-
VERSION = '0.12.
|
28
|
+
VERSION = '0.12.4'
|
30
29
|
|
31
30
|
autoload :Server, 'couchrest/core/server'
|
32
31
|
autoload :Database, 'couchrest/core/database'
|
@@ -128,3 +128,86 @@ describe "destroying a document from a db using bulk save" do
|
|
128
128
|
lambda{@db.get @resp['id']}.should raise_error
|
129
129
|
end
|
130
130
|
end
|
131
|
+
|
132
|
+
describe "copying a document" do
|
133
|
+
before :each do
|
134
|
+
@db = reset_test_db!
|
135
|
+
@resp = @db.save({'key' => 'value'})
|
136
|
+
@docid = 'new-location'
|
137
|
+
@doc = @db.get(@resp['id'])
|
138
|
+
end
|
139
|
+
describe "to a new location" do
|
140
|
+
it "should work" do
|
141
|
+
@doc.copy @docid
|
142
|
+
newdoc = @db.get(@docid)
|
143
|
+
newdoc['key'].should == 'value'
|
144
|
+
end
|
145
|
+
it "should fail without a database" do
|
146
|
+
lambda{CouchRest::Document.new({"not"=>"a real doc"}).copy}.should raise_error(ArgumentError)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
describe "to an existing location" do
|
150
|
+
before :each do
|
151
|
+
@db.save({'_id' => @docid, 'will-exist' => 'here'})
|
152
|
+
end
|
153
|
+
it "should fail without a rev" do
|
154
|
+
lambda{@doc.copy @docid}.should raise_error(RestClient::RequestFailed)
|
155
|
+
end
|
156
|
+
it "should succeed with a rev" do
|
157
|
+
@to_be_overwritten = @db.get(@docid)
|
158
|
+
@doc.copy "#{@docid}?rev=#{@to_be_overwritten['_rev']}"
|
159
|
+
newdoc = @db.get(@docid)
|
160
|
+
newdoc['key'].should == 'value'
|
161
|
+
end
|
162
|
+
it "should succeed given the doc to overwrite" do
|
163
|
+
@to_be_overwritten = @db.get(@docid)
|
164
|
+
@doc.copy @to_be_overwritten
|
165
|
+
newdoc = @db.get(@docid)
|
166
|
+
newdoc['key'].should == 'value'
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "MOVE existing document" do
|
172
|
+
before :each do
|
173
|
+
@db = reset_test_db!
|
174
|
+
@resp = @db.save({'key' => 'value'})
|
175
|
+
@docid = 'new-location'
|
176
|
+
@doc = @db.get(@resp['id'])
|
177
|
+
end
|
178
|
+
describe "to a new location" do
|
179
|
+
it "should work" do
|
180
|
+
@doc.move @docid
|
181
|
+
newdoc = @db.get(@docid)
|
182
|
+
newdoc['key'].should == 'value'
|
183
|
+
lambda {@db.get(@resp['id'])}.should raise_error(RestClient::ResourceNotFound)
|
184
|
+
end
|
185
|
+
it "should fail without a database" do
|
186
|
+
lambda{CouchRest::Document.new({"not"=>"a real doc"}).move}.should raise_error(ArgumentError)
|
187
|
+
lambda{CouchRest::Document.new({"_id"=>"not a real doc"}).move}.should raise_error(ArgumentError)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
describe "to an existing location" do
|
191
|
+
before :each do
|
192
|
+
@db.save({'_id' => @docid, 'will-exist' => 'here'})
|
193
|
+
end
|
194
|
+
it "should fail without a rev" do
|
195
|
+
lambda{@doc.move @docid}.should raise_error(RestClient::RequestFailed)
|
196
|
+
lambda{@db.get(@resp['id'])}.should_not raise_error
|
197
|
+
end
|
198
|
+
it "should succeed with a rev" do
|
199
|
+
@to_be_overwritten = @db.get(@docid)
|
200
|
+
@doc.move "#{@docid}?rev=#{@to_be_overwritten['_rev']}"
|
201
|
+
newdoc = @db.get(@docid)
|
202
|
+
newdoc['key'].should == 'value'
|
203
|
+
lambda {@db.get(@resp['id'])}.should raise_error(RestClient::ResourceNotFound)
|
204
|
+
end
|
205
|
+
it "should succeed given the doc to overwrite" do
|
206
|
+
@to_be_overwritten = @db.get(@docid)
|
207
|
+
@doc.move @to_be_overwritten
|
208
|
+
newdoc = @db.get(@docid)
|
209
|
+
newdoc['key'].should == 'value'
|
210
|
+
lambda {@db.get(@resp['id'])}.should raise_error(RestClient::ResourceNotFound)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: couchrest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.
|
4
|
+
version: 0.12.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- J. Chris Anderson
|
@@ -10,7 +10,7 @@ bindir: bin
|
|
10
10
|
cert_chain: []
|
11
11
|
|
12
12
|
date: 2008-11-22 00:00:00 -08:00
|
13
|
-
default_executable:
|
13
|
+
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: json
|
@@ -42,20 +42,10 @@ dependencies:
|
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: "1.15"
|
44
44
|
version:
|
45
|
-
- !ruby/object:Gem::Dependency
|
46
|
-
name: extlib
|
47
|
-
type: :runtime
|
48
|
-
version_requirement:
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - ">="
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: 0.9.6
|
54
|
-
version:
|
55
45
|
description: CouchRest provides a simple interface on top of CouchDB's RESTful HTTP API, as well as including some utility scripts for managing views and attachments.
|
56
46
|
email: jchris@apache.org
|
57
|
-
executables:
|
58
|
-
|
47
|
+
executables: []
|
48
|
+
|
59
49
|
extensions: []
|
60
50
|
|
61
51
|
extra_rdoc_files:
|
@@ -67,7 +57,6 @@ files:
|
|
67
57
|
- README.md
|
68
58
|
- Rakefile
|
69
59
|
- THANKS.md
|
70
|
-
- bin/couchdir
|
71
60
|
- examples/model
|
72
61
|
- examples/model/example.rb
|
73
62
|
- examples/word_count
|
@@ -84,6 +73,7 @@ files:
|
|
84
73
|
- examples/word_count/views/word_count/count-reduce.js
|
85
74
|
- examples/word_count/word_count.rb
|
86
75
|
- examples/word_count/word_count_query.rb
|
76
|
+
- examples/word_count/word_count_views.rb
|
87
77
|
- lib/couchrest
|
88
78
|
- lib/couchrest/commands
|
89
79
|
- lib/couchrest/commands/generate.rb
|
data/bin/couchdir
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
unless ARGV.length >= 2
|
4
|
-
puts "usage: couchdir path/to/directory db-name [docid]"
|
5
|
-
exit
|
6
|
-
end
|
7
|
-
|
8
|
-
require 'rubygems'
|
9
|
-
require 'couchrest'
|
10
|
-
|
11
|
-
dirname = ARGV[0]
|
12
|
-
dbname = ARGV[1]
|
13
|
-
docid = ARGV[2]
|
14
|
-
|
15
|
-
puts "Create attachments for the files in #{dirname} in database #{dbname}."
|
16
|
-
|
17
|
-
fm = CouchRest::FileManager.new(dbname)
|
18
|
-
fm.loud = true
|
19
|
-
puts "Pushing views from directory #{dirname} to database #{fm.db}"
|
20
|
-
fm.push_directory(dirname, docid)
|