couchrest 1.1.0.pre2 → 1.1.0.pre3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Rakefile +17 -21
- data/couchrest.gemspec +5 -5
- data/history.txt +7 -0
- data/lib/couchrest.rb +10 -10
- data/lib/couchrest/database.rb +14 -14
- data/lib/couchrest/design.rb +4 -3
- data/lib/couchrest/document.rb +89 -21
- data/lib/couchrest/helper/streamer.rb +3 -3
- data/lib/couchrest/middlewares/logger.rb +2 -2
- data/lib/couchrest/rest_api.rb +63 -45
- data/lib/couchrest/version.rb +3 -0
- data/spec/couchrest/database_spec.rb +1 -1
- data/spec/couchrest/document_spec.rb +94 -13
- data/spec/couchrest/helpers/pager_spec.rb +6 -13
- data/spec/spec_helper.rb +3 -2
- metadata +19 -34
- data/lib/couchrest/response.rb +0 -16
data/.gitignore
CHANGED
data/Rakefile
CHANGED
@@ -1,33 +1,20 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'bundler'
|
3
|
-
|
4
|
-
|
5
|
-
require 'rake'
|
3
|
+
require 'rspec/core/rake_task'
|
6
4
|
require "rake/rdoctask"
|
7
5
|
|
8
|
-
|
9
|
-
require 'couchrest'
|
10
|
-
|
11
|
-
begin
|
12
|
-
require 'spec/rake/spectask'
|
13
|
-
rescue LoadError
|
14
|
-
puts <<-EOS
|
15
|
-
To use rspec for testing you must install rspec gem:
|
16
|
-
gem install rspec
|
17
|
-
EOS
|
18
|
-
exit(0)
|
19
|
-
end
|
6
|
+
Bundler::GemHelper.install_tasks
|
20
7
|
|
21
8
|
desc "Run all specs"
|
22
|
-
|
23
|
-
|
24
|
-
|
9
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
10
|
+
spec.rspec_opts = ["--color"]
|
11
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
25
12
|
end
|
26
13
|
|
27
14
|
desc "Print specdocs"
|
28
|
-
|
29
|
-
|
30
|
-
|
15
|
+
RSpec::Core::RakeTask.new(:doc) do |spec|
|
16
|
+
spec.rspec_opts = ["--format", "specdoc"]
|
17
|
+
spec.pattern = 'spec/*_spec.rb'
|
31
18
|
end
|
32
19
|
|
33
20
|
desc "Generate the rdoc"
|
@@ -40,3 +27,12 @@ end
|
|
40
27
|
|
41
28
|
desc "Run the rspec"
|
42
29
|
task :default => :spec
|
30
|
+
|
31
|
+
module Rake
|
32
|
+
def self.remove_task(task_name)
|
33
|
+
Rake.application.instance_variable_get('@tasks').delete(task_name.to_s)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
Rake.remove_task("github:release")
|
38
|
+
Rake.remove_task("release")
|
data/couchrest.gemspec
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
2
|
+
require File.join(File.dirname(__FILE__),'lib','couchrest','version')
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{couchrest}
|
5
|
-
s.version =
|
5
|
+
s.version = CouchRest::VERSION
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["J. Chris Anderson", "Matt Aimonetti", "Marcos Tapajos", "Will Leinweber", "Sam Lown"]
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
|
29
29
|
s.add_dependency(%q<rest-client>, ["~> 1.6.1"])
|
30
30
|
s.add_dependency(%q<mime-types>, ["~> 1.15"])
|
31
|
-
s.add_dependency(%q<
|
32
|
-
s.add_development_dependency(%q<
|
33
|
-
|
31
|
+
s.add_dependency(%q<multi_json>, ["~> 1.0.0"])
|
32
|
+
s.add_development_dependency(%q<json>, ["~> 1.5.1"])
|
33
|
+
s.add_development_dependency(%q<rspec>, "~> 2.6.0")
|
34
34
|
end
|
data/history.txt
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 1.1.0.pre3 - 2011-06-06
|
2
|
+
|
3
|
+
* Major changes
|
4
|
+
* CouchRest::Response removed
|
5
|
+
* CouchRest::Document now forwards key Hash methods (instead of inheritance) (thanks @karmi for prompting the discussion: https://github.com/crx/tire/commit/abf491d0035843a0a7395c8c32b9b7c2120071f9)
|
6
|
+
* Support multiple JSON gems with multi_json (thanks chrisdurtschi)
|
7
|
+
|
1
8
|
== 1.1.0.pre2 - 2011-04-08
|
2
9
|
|
3
10
|
* Major changes
|
data/lib/couchrest.rb
CHANGED
@@ -13,24 +13,24 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
15
|
require 'rest_client'
|
16
|
-
require '
|
16
|
+
require 'multi_json'
|
17
17
|
|
18
18
|
# Not sure why this is required, so removed until a reason is found!
|
19
19
|
$:.unshift File.dirname(__FILE__) unless
|
20
20
|
$:.include?(File.dirname(__FILE__)) ||
|
21
21
|
$:.include?(File.expand_path(File.dirname(__FILE__)))
|
22
|
-
|
22
|
+
|
23
23
|
require 'couchrest/monkeypatches'
|
24
24
|
require 'couchrest/rest_api'
|
25
25
|
require 'couchrest/support/inheritable_attributes'
|
26
|
+
require 'couchrest/version'
|
27
|
+
|
28
|
+
require 'forwardable'
|
26
29
|
|
27
30
|
# = CouchDB, close to the metal
|
28
31
|
module CouchRest
|
29
|
-
VERSION = '1.0.1'
|
30
|
-
|
31
32
|
autoload :Server, 'couchrest/server'
|
32
33
|
autoload :Database, 'couchrest/database'
|
33
|
-
autoload :Response, 'couchrest/response'
|
34
34
|
autoload :Document, 'couchrest/document'
|
35
35
|
autoload :Design, 'couchrest/design'
|
36
36
|
autoload :Model, 'couchrest/model'
|
@@ -38,11 +38,11 @@ module CouchRest
|
|
38
38
|
autoload :Streamer, 'couchrest/helper/streamer'
|
39
39
|
autoload :Attachments, 'couchrest/helper/attachments'
|
40
40
|
autoload :Upgrade, 'couchrest/helper/upgrade'
|
41
|
-
|
41
|
+
|
42
42
|
# we extend CouchRest with the RestAPI module which gives us acess to
|
43
43
|
# the get, post, put, delete and copy
|
44
|
-
CouchRest.extend(::RestAPI)
|
45
|
-
|
44
|
+
CouchRest.extend(::CouchRest::RestAPI)
|
45
|
+
|
46
46
|
# The CouchRest module methods handle the basic JSON serialization
|
47
47
|
# and deserialization, as well as query parameters. The module also includes
|
48
48
|
# some helpers for tasks like instantiating a new Database or Server instance.
|
@@ -53,7 +53,7 @@ module CouchRest
|
|
53
53
|
def new(*opts)
|
54
54
|
Server.new(*opts)
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
def parse url
|
58
58
|
case url
|
59
59
|
when /^(https?:\/\/)(.*)\/(.*)\/(.*)/
|
@@ -111,7 +111,7 @@ module CouchRest
|
|
111
111
|
def paramify_url url, params = {}
|
112
112
|
if params && !params.empty?
|
113
113
|
query = params.collect do |k,v|
|
114
|
-
v = v
|
114
|
+
v = MultiJson.encode(v) if %w{key startkey endkey}.include?(k.to_s)
|
115
115
|
"#{k}=#{CGI.escape(v.to_s)}"
|
116
116
|
end.join("&")
|
117
117
|
url = "#{url}?#{query}"
|
data/lib/couchrest/database.rb
CHANGED
@@ -75,7 +75,7 @@ module CouchRest
|
|
75
75
|
|
76
76
|
# == Retrieving and saving single documents
|
77
77
|
|
78
|
-
# GET a document from CouchDB, by id. Returns a
|
78
|
+
# GET a document from CouchDB, by id. Returns a Document or Design.
|
79
79
|
def get(id, params = {})
|
80
80
|
slug = escape_docid(id)
|
81
81
|
url = CouchRest.paramify_url("#{@root}/#{slug}", params)
|
@@ -118,13 +118,13 @@ module CouchRest
|
|
118
118
|
if bulk
|
119
119
|
@bulk_save_cache << doc
|
120
120
|
bulk_save if @bulk_save_cache.length >= @bulk_save_cache_limit
|
121
|
-
return {
|
121
|
+
return {'ok' => true} # Compatibility with Document#save
|
122
122
|
elsif !bulk && @bulk_save_cache.length > 0
|
123
123
|
bulk_save
|
124
124
|
end
|
125
125
|
result = if doc['_id']
|
126
126
|
slug = escape_docid(doc['_id'])
|
127
|
-
begin
|
127
|
+
begin
|
128
128
|
uri = "#{@root}/#{slug}"
|
129
129
|
uri << "?batch=ok" if batch
|
130
130
|
CouchRest.put uri, doc
|
@@ -186,11 +186,11 @@ module CouchRest
|
|
186
186
|
# If <tt>bulk</tt> is true (false by default) the deletion is recorded for bulk-saving (bulk-deletion :) later.
|
187
187
|
# Bulk saving happens automatically when #bulk_save_cache limit is exceded, or on the next non bulk save.
|
188
188
|
def delete_doc(doc, bulk = false)
|
189
|
-
raise ArgumentError, "_id and _rev required for deleting" unless doc['_id'] && doc['_rev']
|
189
|
+
raise ArgumentError, "_id and _rev required for deleting" unless doc['_id'] && doc['_rev']
|
190
190
|
if bulk
|
191
|
-
@bulk_save_cache << { '_id' => doc['_id'], '_rev' => doc['_rev'],
|
191
|
+
@bulk_save_cache << { '_id' => doc['_id'], '_rev' => doc['_rev'], :_deleted => true }
|
192
192
|
return bulk_save if @bulk_save_cache.length >= @bulk_save_cache_limit
|
193
|
-
return {
|
193
|
+
return {'ok' => true} # Mimic the non-deferred version
|
194
194
|
end
|
195
195
|
slug = escape_docid(doc['_id'])
|
196
196
|
CouchRest.delete "#{@root}/#{slug}?rev=#{doc['_rev']}"
|
@@ -201,7 +201,7 @@ module CouchRest
|
|
201
201
|
# hash with a '_rev' key
|
202
202
|
def copy_doc(doc, dest)
|
203
203
|
raise ArgumentError, "_id is required for copying" unless doc['_id']
|
204
|
-
slug = escape_docid(doc['_id'])
|
204
|
+
slug = escape_docid(doc['_id'])
|
205
205
|
destination = if dest.respond_to?(:has_key?) && dest['_id'] && dest['_rev']
|
206
206
|
"#{dest['_id']}?rev=#{dest['_rev']}"
|
207
207
|
else
|
@@ -243,7 +243,7 @@ module CouchRest
|
|
243
243
|
# Query a CouchDB view as defined by a <tt>_design</tt> document. Accepts
|
244
244
|
# paramaters as described in http://wiki.apache.org/couchdb/HttpViewApi
|
245
245
|
def view(name, params = {}, payload = {}, &block)
|
246
|
-
payload[
|
246
|
+
payload['keys'] = params.delete(:keys) if params[:keys]
|
247
247
|
# Try recognising the name, otherwise assume already prepared
|
248
248
|
view_path = name =~ /^([^_].+?)\/(.*)$/ ? "_design/#{$1}/_view/#{$2}" : name
|
249
249
|
url = CouchRest.paramify_url "#{@root}/#{view_path}", params
|
@@ -306,14 +306,14 @@ module CouchRest
|
|
306
306
|
# GET an attachment directly from CouchDB
|
307
307
|
def fetch_attachment(doc, name)
|
308
308
|
uri = url_for_attachment(doc, name)
|
309
|
-
|
309
|
+
CouchRest.get uri, :raw => true
|
310
310
|
end
|
311
311
|
|
312
312
|
# PUT an attachment directly to CouchDB
|
313
313
|
def put_attachment(doc, name, file, options = {})
|
314
314
|
docid = escape_docid(doc['_id'])
|
315
315
|
uri = url_for_attachment(doc, name)
|
316
|
-
|
316
|
+
CouchRest.put(uri, file, options.merge(:raw => true))
|
317
317
|
end
|
318
318
|
|
319
319
|
# DELETE an attachment directly from CouchDB
|
@@ -343,12 +343,12 @@ module CouchRest
|
|
343
343
|
raise ArgumentError, "must provide a target or source option" unless (options.key?(:target) || options.key?(:source))
|
344
344
|
payload = options
|
345
345
|
if options.has_key?(:target)
|
346
|
-
payload[
|
346
|
+
payload['source'] = other_db.root
|
347
347
|
else
|
348
|
-
payload[
|
348
|
+
payload['target'] = other_db.root
|
349
349
|
end
|
350
|
-
payload[
|
351
|
-
payload[
|
350
|
+
payload['continuous'] = continuous
|
351
|
+
payload['doc_ids'] = options[:doc_ids] if options[:doc_ids]
|
352
352
|
CouchRest.post "#{@host}/_replicate", payload
|
353
353
|
end
|
354
354
|
|
data/lib/couchrest/design.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
-
module CouchRest
|
1
|
+
module CouchRest
|
2
2
|
class Design < Document
|
3
|
+
|
3
4
|
def view_by *keys
|
4
5
|
opts = keys.pop if keys.last.is_a?(Hash)
|
5
6
|
opts ||= {}
|
6
7
|
self['views'] ||= {}
|
7
8
|
method_name = "by_#{keys.join('_and_')}"
|
8
|
-
|
9
|
+
|
9
10
|
if opts[:map]
|
10
11
|
view = {}
|
11
12
|
view['map'] = opts.delete(:map)
|
@@ -31,7 +32,7 @@ JAVASCRIPT
|
|
31
32
|
self['views'][method_name]['couchrest-defaults'] = opts unless opts.empty?
|
32
33
|
method_name
|
33
34
|
end
|
34
|
-
|
35
|
+
|
35
36
|
# Dispatches to any named view.
|
36
37
|
# (using the database where this design doc was saved)
|
37
38
|
def view view_name, query={}, &block
|
data/lib/couchrest/document.rb
CHANGED
@@ -1,38 +1,89 @@
|
|
1
|
-
require 'delegate'
|
2
1
|
|
3
|
-
|
4
|
-
|
2
|
+
#
|
3
|
+
# CouchRest::Document
|
4
|
+
#
|
5
|
+
# Provides basic functions for controlling documents returned from
|
6
|
+
# the CouchDB database and provides methods to act as a wrapper around
|
7
|
+
# a Hash of @_attributes.
|
8
|
+
#
|
9
|
+
# The idea is to provide the basic functionality of a Hash, just
|
10
|
+
# enought to support the needs of CouchRest, but not inherit all
|
11
|
+
# of the functionality found in a basic Hash.
|
12
|
+
#
|
13
|
+
# A Response is similar to Rails' HashWithIndifferentAccess as all
|
14
|
+
# requests will convert the keys into Symbols and be stored in the
|
15
|
+
# master hash as such.
|
16
|
+
#
|
17
|
+
|
18
|
+
module CouchRest
|
19
|
+
class Document
|
20
|
+
extend Forwardable
|
5
21
|
include CouchRest::Attachments
|
6
22
|
extend CouchRest::InheritableAttributes
|
7
|
-
|
23
|
+
|
8
24
|
couchrest_inheritable_accessor :database
|
9
25
|
attr_accessor :database
|
10
|
-
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
26
|
+
|
27
|
+
# Initialize a new CouchRest Document and prepare
|
28
|
+
# a hidden attributes hash.
|
29
|
+
#
|
30
|
+
# When inherting a Document, it is essential that the
|
31
|
+
# super method is called before you own changes to ensure
|
32
|
+
# that the attributes hash has been initialized before
|
33
|
+
# you attempt to use it.
|
34
|
+
def initialize(attrs = nil)
|
35
|
+
@_attributes = {}
|
36
|
+
attrs.each{|k,v| self[k] = v} unless attrs.nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
# Hash equivilent methods to access the attributes
|
40
|
+
|
41
|
+
def_delegators :@_attributes, :to_a, :==, :eql?, :keys, :values, :each,
|
42
|
+
:reject, :reject!, :empty?, :clear, :merge, :merge!,
|
43
|
+
:encode_json, :as_json, :to_json
|
44
|
+
|
45
|
+
def []=(key, value)
|
46
|
+
@_attributes[key.to_s] = value
|
47
|
+
end
|
48
|
+
def [](key)
|
49
|
+
@_attributes[key.to_s]
|
50
|
+
end
|
51
|
+
def has_key?(key)
|
52
|
+
@_attributes.has_key?(key.to_s)
|
53
|
+
end
|
54
|
+
def delete(key)
|
55
|
+
@_attributes.delete(key.to_s)
|
56
|
+
end
|
57
|
+
def dup
|
58
|
+
new = super
|
59
|
+
@_attributes = @_attributes.dup
|
60
|
+
new
|
61
|
+
end
|
62
|
+
def clone
|
63
|
+
new = super
|
64
|
+
@_attributes = @_attributes.dup
|
65
|
+
new
|
66
|
+
end
|
67
|
+
def to_hash
|
68
|
+
@_attributes
|
69
|
+
end
|
70
|
+
|
18
71
|
def id
|
19
72
|
self['_id']
|
20
73
|
end
|
21
|
-
|
22
74
|
def id=(id)
|
23
75
|
self['_id'] = id
|
24
76
|
end
|
25
|
-
|
26
77
|
def rev
|
27
78
|
self['_rev']
|
28
79
|
end
|
29
|
-
|
80
|
+
|
30
81
|
# returns true if the document has never been saved
|
31
82
|
def new?
|
32
83
|
!rev
|
33
84
|
end
|
34
85
|
alias :new_document? :new?
|
35
|
-
|
86
|
+
|
36
87
|
# Saves the document to the db using create or update. Also runs the :save
|
37
88
|
# callbacks. Sets the <tt>_id</tt> and <tt>_rev</tt> fields based on
|
38
89
|
# CouchDB's response.
|
@@ -57,7 +108,7 @@ module CouchRest
|
|
57
108
|
end
|
58
109
|
result['ok']
|
59
110
|
end
|
60
|
-
|
111
|
+
|
61
112
|
# copies the document to a new id. If the destination id currently exists, a rev must be provided.
|
62
113
|
# <tt>dest</tt> can take one of two forms if overwriting: "id_to_overwrite?rev=revision" or the actual doc
|
63
114
|
# hash with a '_rev' key
|
@@ -66,7 +117,7 @@ module CouchRest
|
|
66
117
|
result = database.copy_doc(self, dest)
|
67
118
|
result['ok']
|
68
119
|
end
|
69
|
-
|
120
|
+
|
70
121
|
# Returns the CouchDB uri for the document
|
71
122
|
def uri(append_rev = false)
|
72
123
|
return nil if new?
|
@@ -78,12 +129,29 @@ module CouchRest
|
|
78
129
|
end
|
79
130
|
couch_uri
|
80
131
|
end
|
81
|
-
|
132
|
+
|
82
133
|
# Returns the document's database
|
83
134
|
def database
|
84
135
|
@database || self.class.database
|
85
136
|
end
|
86
|
-
|
137
|
+
|
138
|
+
# Provide details of the current keys in the reponse. Based on ActiveRecord::Base.
|
139
|
+
def inspect
|
140
|
+
attributes_as_nice_string = self.keys.collect { |key|
|
141
|
+
"#{key}: #{self[key].inspect}"
|
142
|
+
}.compact.join(", ")
|
143
|
+
"#<#{self.class} #{attributes_as_nice_string}>"
|
144
|
+
end
|
145
|
+
|
146
|
+
class << self
|
147
|
+
# override the CouchRest::Model-wide default_database
|
148
|
+
# This is not a thread safe operation, do not change the model
|
149
|
+
# database at runtime.
|
150
|
+
def use_database(db)
|
151
|
+
self.database = db
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
87
155
|
end
|
88
|
-
|
156
|
+
|
89
157
|
end
|
@@ -16,7 +16,7 @@ module CouchRest
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def post(url, params = {}, &block)
|
19
|
-
open_pipe("curl #{default_curl_opts} -d \"#{escape_quotes(params
|
19
|
+
open_pipe("curl #{default_curl_opts} -d \"#{escape_quotes(MultiJson.encode(params))}\" \"#{url}\"", &block)
|
20
20
|
end
|
21
21
|
|
22
22
|
protected
|
@@ -40,7 +40,7 @@ module CouchRest
|
|
40
40
|
def parse_line line
|
41
41
|
return nil unless line
|
42
42
|
if /(\{.*\}),?/.match(line.chomp)
|
43
|
-
|
43
|
+
MultiJson.decode($1)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
@@ -49,7 +49,7 @@ module CouchRest
|
|
49
49
|
parts = first.split(',')
|
50
50
|
parts.pop
|
51
51
|
line = parts.join(',')
|
52
|
-
|
52
|
+
MultiJson.decode("#{line}}")
|
53
53
|
rescue
|
54
54
|
nil
|
55
55
|
end
|
@@ -68,7 +68,7 @@ module RestClient
|
|
68
68
|
|
69
69
|
def self.post(uri, payload, headers=nil)
|
70
70
|
start_query = Time.now
|
71
|
-
log = {:method => :post, :uri => uri, :payload => (payload ? (
|
71
|
+
log = {:method => :post, :uri => uri, :payload => (payload ? (MultiJson.decode(payload) rescue 'parsing error') : nil), :headers => headers}
|
72
72
|
response = super(uri, payload, headers=nil)
|
73
73
|
end_query = Time.now
|
74
74
|
log[:duration] = (end_query - start_query)
|
@@ -78,7 +78,7 @@ module RestClient
|
|
78
78
|
|
79
79
|
def self.put(uri, payload, headers=nil)
|
80
80
|
start_query = Time.now
|
81
|
-
log = {:method => :put, :uri => uri, :payload => (payload ? (
|
81
|
+
log = {:method => :put, :uri => uri, :payload => (payload ? (MultiJson.decode(payload) rescue 'parsing error') : nil), :headers => headers}
|
82
82
|
response = super(uri, payload, headers=nil)
|
83
83
|
end_query = Time.now
|
84
84
|
log[:duration] = (end_query - start_query)
|
data/lib/couchrest/rest_api.rb
CHANGED
@@ -1,59 +1,77 @@
|
|
1
|
-
module
|
1
|
+
module CouchRest
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
module RestAPI
|
4
|
+
|
5
|
+
def default_headers
|
6
|
+
{
|
7
|
+
:content_type => :json,
|
8
|
+
:accept => :json
|
9
|
+
}
|
10
|
+
end
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
12
|
+
def get(uri, options = {})
|
13
|
+
begin
|
14
|
+
parse_response(RestClient.get(uri, default_headers), options.dup)
|
15
|
+
rescue => e
|
16
|
+
if $DEBUG
|
17
|
+
raise "Error while sending a GET request #{uri}\n: #{e}"
|
18
|
+
else
|
19
|
+
raise e
|
20
|
+
end
|
19
21
|
end
|
20
22
|
end
|
21
|
-
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
def put(uri, doc = nil, options = {})
|
25
|
+
opts = options.dup
|
26
|
+
payload = payload_from_doc(doc, opts)
|
27
|
+
begin
|
28
|
+
parse_response(RestClient.put(uri, payload, default_headers.merge(opts)), opts)
|
29
|
+
rescue Exception => e
|
30
|
+
if $DEBUG
|
31
|
+
raise "Error while sending a PUT request #{uri}\npayload: #{payload.inspect}\n#{e}"
|
32
|
+
else
|
33
|
+
raise e
|
34
|
+
end
|
31
35
|
end
|
32
36
|
end
|
33
|
-
end
|
34
37
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
def post(uri, doc = nil, options = {})
|
39
|
+
opts = options.dup
|
40
|
+
payload = payload_from_doc(doc, opts)
|
41
|
+
begin
|
42
|
+
parse_response(RestClient.post(uri, payload, default_headers.merge(opts)), opts)
|
43
|
+
rescue Exception => e
|
44
|
+
if $DEBUG
|
45
|
+
raise "Error while sending a POST request #{uri}\npayload: #{payload.inspect}\n#{e}"
|
46
|
+
else
|
47
|
+
raise e
|
48
|
+
end
|
44
49
|
end
|
45
50
|
end
|
46
|
-
end
|
47
51
|
|
48
|
-
|
49
|
-
|
50
|
-
|
52
|
+
def delete(uri, options = {})
|
53
|
+
parse_response(RestClient.delete(uri, default_headers), options.dup)
|
54
|
+
end
|
51
55
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
56
|
+
def copy(uri, destination, options = {})
|
57
|
+
parse_response(RestClient::Request.execute( :method => :copy,
|
58
|
+
:url => uri,
|
59
|
+
:headers => default_headers.merge('Destination' => destination)
|
60
|
+
).to_s, options)
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
# Check if the provided doc is nil or special IO device or temp file. If not,
|
66
|
+
# encode it into a string.
|
67
|
+
def payload_from_doc(doc, opts = {})
|
68
|
+
(opts.delete(:raw) || doc.nil? || doc.is_a?(IO) || doc.is_a?(Tempfile)) ? doc : MultiJson.encode(doc)
|
69
|
+
end
|
58
70
|
|
71
|
+
# Parse the response provided.
|
72
|
+
def parse_response(result, opts = {})
|
73
|
+
opts.delete(:raw) ? result : MultiJson.decode(result, opts.update(:max_nesting => false))
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
59
77
|
end
|
@@ -257,7 +257,7 @@ describe CouchRest::Database do
|
|
257
257
|
])
|
258
258
|
rescue RestClient::RequestFailed => e
|
259
259
|
# soon CouchDB will provide _which_ docs conflicted
|
260
|
-
|
260
|
+
MultiJson.decode(e.response.body)['error'].should == 'conflict'
|
261
261
|
end
|
262
262
|
end
|
263
263
|
end
|
@@ -9,6 +9,36 @@ describe CouchRest::Document do
|
|
9
9
|
@db = @couch.database!(TESTDB)
|
10
10
|
end
|
11
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
|
+
end
|
31
|
+
|
32
|
+
describe "hash methods" do
|
33
|
+
it "should respond to forwarded hash methods" do
|
34
|
+
@doc = CouchRest::Document.new(:foo => 'bar')
|
35
|
+
[:to_a, :==, :eql?, :keys, :values, :each, :reject, :reject!, :empty?,
|
36
|
+
:clear, :merge, :merge!, :encode_json, :as_json, :to_json].each do |call|
|
37
|
+
@doc.should respond_to(call)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
12
42
|
describe "[]=" do
|
13
43
|
before(:each) do
|
14
44
|
@doc = CouchRest::Document.new
|
@@ -29,6 +59,57 @@ describe CouchRest::Document do
|
|
29
59
|
end
|
30
60
|
end
|
31
61
|
|
62
|
+
describe "#has_key?" do
|
63
|
+
before :each do
|
64
|
+
@doc = CouchRest::Document.new
|
65
|
+
end
|
66
|
+
it "should confirm existance of key" do
|
67
|
+
@doc[:test] = 'example'
|
68
|
+
@doc.has_key?('test').should be_true
|
69
|
+
@doc.has_key?(:test).should be_true
|
70
|
+
end
|
71
|
+
it "should deny existance of key" do
|
72
|
+
@doc.has_key?(:bardom).should be_false
|
73
|
+
@doc.has_key?('bardom').should be_false
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#dup" do
|
78
|
+
it "should also clone the attributes" do
|
79
|
+
@doc = CouchRest::Document.new('foo' => 'bar')
|
80
|
+
@doc2 = @doc.dup
|
81
|
+
@doc2.delete('foo')
|
82
|
+
@doc2['foo'].should be_nil
|
83
|
+
@doc['foo'].should eql('bar')
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#clone" do
|
88
|
+
it "should also clone the attributes" do
|
89
|
+
@doc = CouchRest::Document.new('foo' => 'bar')
|
90
|
+
@doc2 = @doc.clone
|
91
|
+
@doc2.delete('foo')
|
92
|
+
@doc2['foo'].should be_nil
|
93
|
+
@doc['foo'].should eql('bar')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
describe "#inspect" do
|
99
|
+
it "should provide a string of keys and values of the Response" do
|
100
|
+
@doc = CouchRest::Document.new('foo' => 'bar')
|
101
|
+
@doc.inspect.should eql("#<CouchRest::Document foo: \"bar\">")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "responding to Hash methods" do
|
106
|
+
it "should delegate requests" do
|
107
|
+
@doc = CouchRest::Document.new('foo' => 'bar')
|
108
|
+
@doc.keys.should eql(['foo'])
|
109
|
+
@doc.values.should eql(['bar'])
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
32
113
|
describe "default database" do
|
33
114
|
before(:each) do
|
34
115
|
Video.use_database nil
|
@@ -220,7 +301,7 @@ describe "dealing with attachments" do
|
|
220
301
|
response = @db.save_doc({'key' => 'value'})
|
221
302
|
@doc = @db.get(response['id'])
|
222
303
|
end
|
223
|
-
|
304
|
+
|
224
305
|
def append_attachment(name='test.html', attach=@attach)
|
225
306
|
@doc['_attachments'] ||= {}
|
226
307
|
@doc['_attachments'][name] = {
|
@@ -230,50 +311,50 @@ describe "dealing with attachments" do
|
|
230
311
|
@doc.save
|
231
312
|
@rev = @doc['_rev']
|
232
313
|
end
|
233
|
-
|
314
|
+
|
234
315
|
describe "PUTing an attachment directly to the doc" do
|
235
316
|
before do
|
236
317
|
@doc.put_attachment('test.html', @attach)
|
237
318
|
end
|
238
|
-
|
319
|
+
|
239
320
|
it "is there" do
|
240
321
|
@db.fetch_attachment(@doc, 'test.html').should == @attach
|
241
322
|
end
|
242
|
-
|
323
|
+
|
243
324
|
it "updates the revision" do
|
244
|
-
@doc[
|
325
|
+
@doc[:_rev].should_not == @rev
|
245
326
|
end
|
246
|
-
|
327
|
+
|
247
328
|
it "updates attachments" do
|
248
329
|
@attach2 = "<html><head><title>My Doc</title></head><body><p>Is Different.</p></body></html>"
|
249
330
|
@doc.put_attachment('test.html', @attach2)
|
250
331
|
@db.fetch_attachment(@doc, 'test.html').should == @attach2
|
251
332
|
end
|
252
333
|
end
|
253
|
-
|
334
|
+
|
254
335
|
describe "fetching an attachment from a doc directly" do
|
255
336
|
before do
|
256
337
|
append_attachment
|
257
338
|
end
|
258
|
-
|
339
|
+
|
259
340
|
it "pulls the attachment" do
|
260
341
|
@doc.fetch_attachment('test.html').should == @attach
|
261
342
|
end
|
262
343
|
end
|
263
|
-
|
344
|
+
|
264
345
|
describe "deleting an attachment from a doc directly" do
|
265
346
|
before do
|
266
347
|
append_attachment
|
267
348
|
@doc.delete_attachment('test.html')
|
268
349
|
end
|
269
|
-
|
350
|
+
|
270
351
|
it "removes it" do
|
271
352
|
lambda { @db.fetch_attachment(@doc, 'test.html').should }.should raise_error(RestClient::ResourceNotFound)
|
272
353
|
end
|
273
|
-
|
354
|
+
|
274
355
|
it "updates the revision" do
|
275
|
-
@doc[
|
356
|
+
@doc[:_rev].should_not == @rev
|
276
357
|
end
|
277
358
|
end
|
278
|
-
|
359
|
+
|
279
360
|
end
|
@@ -7,6 +7,11 @@ describe CouchRest::Pager do
|
|
7
7
|
@db.delete! rescue nil
|
8
8
|
@db = @cr.create_db(TESTDB) rescue nil
|
9
9
|
@pager = CouchRest::Pager.new(@db)
|
10
|
+
@docs = []
|
11
|
+
100.times do |i|
|
12
|
+
@docs << ({:number => (i % 10)})
|
13
|
+
end
|
14
|
+
@db.bulk_save(@docs)
|
10
15
|
end
|
11
16
|
|
12
17
|
after(:all) do
|
@@ -21,13 +26,6 @@ describe CouchRest::Pager do
|
|
21
26
|
end
|
22
27
|
|
23
28
|
describe "paging all docs" do
|
24
|
-
before(:all) do
|
25
|
-
@docs = []
|
26
|
-
100.times do |i|
|
27
|
-
@docs << ({:number => (i % 10)})
|
28
|
-
end
|
29
|
-
@db.bulk_save(@docs)
|
30
|
-
end
|
31
29
|
it "should yield total_docs / limit times" do
|
32
30
|
n = 0
|
33
31
|
@pager.all_docs(10) do |doc|
|
@@ -55,11 +53,6 @@ describe CouchRest::Pager do
|
|
55
53
|
|
56
54
|
describe "Pager with a view and docs" do
|
57
55
|
before(:all) do
|
58
|
-
@docs = []
|
59
|
-
100.times do |i|
|
60
|
-
@docs << ({:number => (i % 10)})
|
61
|
-
end
|
62
|
-
@db.bulk_save(@docs)
|
63
56
|
@db.save_doc({
|
64
57
|
'_id' => '_design/magic',
|
65
58
|
'views' => {
|
@@ -119,4 +112,4 @@ describe CouchRest::Pager do
|
|
119
112
|
results[9].should be_nil
|
120
113
|
end
|
121
114
|
end
|
122
|
-
end
|
115
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
+
require "bundler/setup"
|
1
2
|
require "rubygems"
|
2
|
-
require "
|
3
|
+
require "rspec"
|
3
4
|
|
4
5
|
require File.join(File.dirname(__FILE__), '..','lib','couchrest')
|
5
6
|
# check the following file to see how to use the spec'd features.
|
@@ -21,7 +22,7 @@ def reset_test_db!
|
|
21
22
|
DB
|
22
23
|
end
|
23
24
|
|
24
|
-
|
25
|
+
RSpec.configure do |config|
|
25
26
|
config.before(:all) { reset_test_db! }
|
26
27
|
|
27
28
|
config.after(:all) do
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: couchrest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 1
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
- pre2
|
10
|
-
version: 1.1.0.pre2
|
4
|
+
prerelease: 6
|
5
|
+
version: 1.1.0.pre3
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- J. Chris Anderson
|
@@ -30,10 +25,6 @@ dependencies:
|
|
30
25
|
requirements:
|
31
26
|
- - ~>
|
32
27
|
- !ruby/object:Gem::Version
|
33
|
-
segments:
|
34
|
-
- 1
|
35
|
-
- 6
|
36
|
-
- 1
|
37
28
|
version: 1.6.1
|
38
29
|
type: :runtime
|
39
30
|
version_requirements: *id001
|
@@ -45,42 +36,42 @@ dependencies:
|
|
45
36
|
requirements:
|
46
37
|
- - ~>
|
47
38
|
- !ruby/object:Gem::Version
|
48
|
-
segments:
|
49
|
-
- 1
|
50
|
-
- 15
|
51
39
|
version: "1.15"
|
52
40
|
type: :runtime
|
53
41
|
version_requirements: *id002
|
54
42
|
- !ruby/object:Gem::Dependency
|
55
|
-
name:
|
43
|
+
name: multi_json
|
56
44
|
prerelease: false
|
57
45
|
requirement: &id003 !ruby/object:Gem::Requirement
|
58
46
|
none: false
|
59
47
|
requirements:
|
60
48
|
- - ~>
|
61
49
|
- !ruby/object:Gem::Version
|
62
|
-
|
63
|
-
- 1
|
64
|
-
- 5
|
65
|
-
- 1
|
66
|
-
version: 1.5.1
|
50
|
+
version: 1.0.0
|
67
51
|
type: :runtime
|
68
52
|
version_requirements: *id003
|
69
53
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
54
|
+
name: json
|
71
55
|
prerelease: false
|
72
56
|
requirement: &id004 !ruby/object:Gem::Requirement
|
73
57
|
none: false
|
74
58
|
requirements:
|
75
59
|
- - ~>
|
76
60
|
- !ruby/object:Gem::Version
|
77
|
-
|
78
|
-
- 1
|
79
|
-
- 3
|
80
|
-
- 0
|
81
|
-
version: 1.3.0
|
61
|
+
version: 1.5.1
|
82
62
|
type: :development
|
83
63
|
version_requirements: *id004
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: rspec
|
66
|
+
prerelease: false
|
67
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ~>
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 2.6.0
|
73
|
+
type: :development
|
74
|
+
version_requirements: *id005
|
84
75
|
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.
|
85
76
|
email: jchris@apache.org
|
86
77
|
executables: []
|
@@ -123,10 +114,10 @@ files:
|
|
123
114
|
- lib/couchrest/helper/upgrade.rb
|
124
115
|
- lib/couchrest/middlewares/logger.rb
|
125
116
|
- lib/couchrest/monkeypatches.rb
|
126
|
-
- lib/couchrest/response.rb
|
127
117
|
- lib/couchrest/rest_api.rb
|
128
118
|
- lib/couchrest/server.rb
|
129
119
|
- lib/couchrest/support/inheritable_attributes.rb
|
120
|
+
- lib/couchrest/version.rb
|
130
121
|
- spec/.gitignore
|
131
122
|
- spec/couchrest/couchrest_spec.rb
|
132
123
|
- spec/couchrest/database_spec.rb
|
@@ -161,23 +152,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
161
152
|
requirements:
|
162
153
|
- - ">="
|
163
154
|
- !ruby/object:Gem::Version
|
164
|
-
segments:
|
165
|
-
- 0
|
166
155
|
version: "0"
|
167
156
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
168
157
|
none: false
|
169
158
|
requirements:
|
170
159
|
- - ">"
|
171
160
|
- !ruby/object:Gem::Version
|
172
|
-
segments:
|
173
|
-
- 1
|
174
|
-
- 3
|
175
|
-
- 1
|
176
161
|
version: 1.3.1
|
177
162
|
requirements: []
|
178
163
|
|
179
164
|
rubyforge_project:
|
180
|
-
rubygems_version: 1.3.
|
165
|
+
rubygems_version: 1.3.9.1
|
181
166
|
signing_key:
|
182
167
|
specification_version: 3
|
183
168
|
summary: Lean and RESTful interface to CouchDB.
|
data/lib/couchrest/response.rb
DELETED