couchrest 1.1.0.pre2 → 1.1.0.pre3
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/.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