sr-couchy 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +77 -0
- data/Rakefile +46 -0
- data/bin/couchy +80 -0
- data/couchy.gemspec +58 -0
- data/lib/couchy.rb +21 -0
- data/lib/couchy/database.rb +129 -0
- data/lib/couchy/server.rb +89 -0
- data/spec/couchy_spec.rb +71 -0
- data/spec/database_spec.rb +417 -0
- data/spec/fixtures/attachments/test.html +11 -0
- data/spec/fixtures/views/lib.js +3 -0
- data/spec/fixtures/views/test_view/lib.js +3 -0
- data/spec/fixtures/views/test_view/only-map.js +4 -0
- data/spec/fixtures/views/test_view/test-map.js +3 -0
- data/spec/fixtures/views/test_view/test-reduce.js +3 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +5 -0
- data/test/couchy_test.rb +13 -0
- data/test/database_test.rb +193 -0
- data/test/server_test.rb +211 -0
- data/test/test_helper.rb +10 -0
- data/vendor/addressable/.gitignore +7 -0
- data/vendor/addressable/CHANGELOG +51 -0
- data/vendor/addressable/LICENSE +20 -0
- data/vendor/addressable/README +24 -0
- data/vendor/addressable/Rakefile +51 -0
- data/vendor/addressable/lib/addressable/idna.rb +4867 -0
- data/vendor/addressable/lib/addressable/uri.rb +2212 -0
- data/vendor/addressable/lib/addressable/version.rb +35 -0
- data/vendor/addressable/spec/addressable/idna_spec.rb +196 -0
- data/vendor/addressable/spec/addressable/uri_spec.rb +3827 -0
- data/vendor/addressable/spec/data/rfc3986.txt +3419 -0
- data/vendor/addressable/tasks/clobber.rake +2 -0
- data/vendor/addressable/tasks/gem.rake +62 -0
- data/vendor/addressable/tasks/git.rake +40 -0
- data/vendor/addressable/tasks/metrics.rake +22 -0
- data/vendor/addressable/tasks/rdoc.rake +29 -0
- data/vendor/addressable/tasks/rubyforge.rake +89 -0
- data/vendor/addressable/tasks/spec.rake +107 -0
- data/vendor/addressable/website/index.html +107 -0
- metadata +113 -0
data/README.textile
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
h1. Couchy: There Are Many Like It but This One is Mine
|
2
|
+
|
3
|
+
Couchy is a simple, no-frills, Ruby wrapper around the nice
|
4
|
+
"CouchDB HTTP API":http://wiki.apache.org/couchdb/HttpRestApt.
|
5
|
+
|
6
|
+
h2. Quick overview
|
7
|
+
|
8
|
+
<pre>
|
9
|
+
server = CouchRest.new
|
10
|
+
database = server.database('articles')
|
11
|
+
response = database.save(:title => 'Atom-Powered Robots Run Amok', :content => 'Some text.')
|
12
|
+
document = database.get(response['id'])
|
13
|
+
database.delete(document)
|
14
|
+
puts document.inspect
|
15
|
+
</pre>
|
16
|
+
|
17
|
+
|
18
|
+
h2. Requirements
|
19
|
+
|
20
|
+
The fellowing gems are required:
|
21
|
+
|
22
|
+
* @rest-client@
|
23
|
+
* @addressable@
|
24
|
+
|
25
|
+
To run the test and generate the code coverage report, you also need :
|
26
|
+
|
27
|
+
* @test/spec@
|
28
|
+
* @mocha@
|
29
|
+
* @rcov@
|
30
|
+
* @rspec@ (for the legacy tests)
|
31
|
+
|
32
|
+
and @yard@ to generate the documentation.
|
33
|
+
|
34
|
+
h2. Genesis
|
35
|
+
|
36
|
+
It started as an Hardcore Forking Action of "jchris's CouchRest":original
|
37
|
+
I ended up:
|
38
|
+
|
39
|
+
* Writing more tests. The legacy tests are rather integration tests while those
|
40
|
+
I wrote are unit tests.
|
41
|
+
* DRY-ing it up
|
42
|
+
* Writing some doc using "YARD":yard
|
43
|
+
|
44
|
+
Unfortunately, jchris didn't merge the changes for some reasons.
|
45
|
+
|
46
|
+
Thank a lot to him for having written CouchRest in the first place and having
|
47
|
+
allowed me to relicense my fork under another license.
|
48
|
+
|
49
|
+
h2. License
|
50
|
+
|
51
|
+
(The MIT License)
|
52
|
+
|
53
|
+
Copyright (c) 2008 "Simon Rozet":sr <simon@rozet.name>
|
54
|
+
|
55
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
56
|
+
a copy of this software and associated documentation files (the
|
57
|
+
'Software'), to deal in the Software without restriction, including
|
58
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
59
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
60
|
+
permit persons to whom the Software is furnished to do so, subject to
|
61
|
+
the following conditions:
|
62
|
+
|
63
|
+
The above copyright notice and this permission notice shall be
|
64
|
+
included in all copies or substantial portions of the Software.
|
65
|
+
|
66
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
67
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
68
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
69
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
70
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
71
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
72
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
73
|
+
|
74
|
+
[yard]http://yard.soen.ca/
|
75
|
+
[couchdb]http://couchdb.org
|
76
|
+
[original]http://github.com/jchris/couchrest
|
77
|
+
[sr]http://purl.org/net/sr/
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
require 'rcov/rcovtask'
|
4
|
+
require 'yard'
|
5
|
+
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
task :test => :"test:all"
|
9
|
+
|
10
|
+
namespace :test do
|
11
|
+
desc 'Run all tests'
|
12
|
+
task :all => [:unit, :integration]
|
13
|
+
|
14
|
+
desc 'Run unit tests'
|
15
|
+
task :unit do
|
16
|
+
sh 'testrb test/*.rb'
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Run integration tests"
|
20
|
+
Spec::Rake::SpecTask.new('integration') do |t|
|
21
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Rcov::RcovTask.new do |t|
|
26
|
+
t.test_files = FileList['test/*_test.rb']
|
27
|
+
t.rcov_opts << '-Ilib'
|
28
|
+
t.rcov_opts << '-x"home"'
|
29
|
+
t.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
YARD::Rake::YardocTask.new
|
33
|
+
|
34
|
+
task :publish => [:"publish:doc", :"publish:coverage"]
|
35
|
+
|
36
|
+
namespace :publish do
|
37
|
+
task :doc => :yardoc do
|
38
|
+
sh 'cp -r doc ~/web/atonie.org/2008/couchy'
|
39
|
+
sh 'cd ~/web/atonie.org && git add 2008/couchy/doc && git commit -m "update couchy doc"'
|
40
|
+
end
|
41
|
+
|
42
|
+
task :coverage => :rcov do
|
43
|
+
sh 'cp -r coverage ~/web/atonie.org/2008/couchy'
|
44
|
+
sh 'cd ~/web/atonie.org && git add 2008/couchy/coverage && git commit -m "update couchy coverage"'
|
45
|
+
end
|
46
|
+
end
|
data/bin/couchy
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'thor'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
require File.dirname(__FILE__) + '/../lib/couchy'
|
8
|
+
|
9
|
+
module Couchy
|
10
|
+
class ViewManager < Thor
|
11
|
+
desc 'generate DESIGN VIEW',
|
12
|
+
'Generate directory structure for DESIGN/VIEW in PATH suitable for the `push` task.'
|
13
|
+
def generate(path, design, view='all')
|
14
|
+
path = File.join(Dir.pwd, path, design)
|
15
|
+
FileUtils.mkdir_p path
|
16
|
+
create_sample_view(path, view)
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'push PATH DATABASE', 'Push views avalaible in PATH to DATABASE.'
|
20
|
+
method_options :server => :optional,
|
21
|
+
:force => :boolean
|
22
|
+
def push(path, database_name)
|
23
|
+
@database_name = database_name
|
24
|
+
designs = find_designs(path)
|
25
|
+
documents = designs.map { |design| document_for(*design) }
|
26
|
+
documents.each do |document|
|
27
|
+
if document_exists?(document) && options[:force]
|
28
|
+
puts "Deleting `#{document['_id']}'"
|
29
|
+
database.delete database.get(document['_id'])
|
30
|
+
end
|
31
|
+
puts "Saving `#{document['_id']}' to `#{database.name}' on `#{server.uri}'"
|
32
|
+
database.save(document)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def find_designs(path)
|
38
|
+
views = Dir[File.join(path, '**/*-*.js')].inject({}) do |memo, path|
|
39
|
+
path = Pathname.new(path)
|
40
|
+
parts = path.split
|
41
|
+
design = parts.first.split.last.to_s
|
42
|
+
view = parts.last.to_s
|
43
|
+
view_type = view[/\-(\w+)\.js/] && $1
|
44
|
+
view_body = File.read(path)
|
45
|
+
memo.tap do |memo|
|
46
|
+
memo[design] = {} unless memo[design]
|
47
|
+
memo[design][view_type] = view_body
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def document_for(name, views)
|
53
|
+
{ '_id' => "_design/#{name}",
|
54
|
+
'language' => 'javascript',
|
55
|
+
'views' => views }
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_sample_view(path, view)
|
59
|
+
File.open(File.join(path, "#{view}-map.js"), 'w') do |file|
|
60
|
+
file.puts 'function(doc) {'
|
61
|
+
file.puts ' emit(null, doc);'
|
62
|
+
file.puts '}'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def document_exists?(document)
|
67
|
+
database.documents['rows'].collect { |row| row['id'] }.include?(document['_id'])
|
68
|
+
end
|
69
|
+
|
70
|
+
def database
|
71
|
+
@database ||= server.database(@database_name)
|
72
|
+
end
|
73
|
+
|
74
|
+
def server
|
75
|
+
@server ||= options[:server] ? Couchy::Server.new(options[:server]) : Couchy.new
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
Couchy::ViewManager.start
|
data/couchy.gemspec
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'couchy'
|
3
|
+
s.version = '0.0.2'
|
4
|
+
s.date = '2008-10-07'
|
5
|
+
s.summary = 'Simple, no-frills, Ruby wrapper around the nice CouchDB HTTP API'
|
6
|
+
s.description = 'Simple, no-frills, Ruby wrapper around the nice CouchDB HTTP API'
|
7
|
+
s.homepage = 'http://github.com/sr/couchy'
|
8
|
+
s.email = 'simon@rozet.name'
|
9
|
+
s.authors = ['Simon Rozet']
|
10
|
+
s.has_rdoc = false
|
11
|
+
s.executables = ['couchy']
|
12
|
+
|
13
|
+
s.files = %w(
|
14
|
+
README.textile
|
15
|
+
Rakefile
|
16
|
+
bin/couchy
|
17
|
+
couchy.gemspec
|
18
|
+
lib/couchy.rb
|
19
|
+
lib/couchy/database.rb
|
20
|
+
lib/couchy/server.rb
|
21
|
+
spec/couchy_spec.rb
|
22
|
+
spec/database_spec.rb
|
23
|
+
spec/fixtures/attachments/test.html
|
24
|
+
spec/fixtures/views/lib.js
|
25
|
+
spec/fixtures/views/test_view/lib.js
|
26
|
+
spec/fixtures/views/test_view/only-map.js
|
27
|
+
spec/fixtures/views/test_view/test-map.js
|
28
|
+
spec/fixtures/views/test_view/test-reduce.js
|
29
|
+
spec/spec.opts
|
30
|
+
spec/spec_helper.rb
|
31
|
+
test/couchy_test.rb
|
32
|
+
test/database_test.rb
|
33
|
+
test/server_test.rb
|
34
|
+
test/test_helper.rb
|
35
|
+
vendor/addressable/.gitignore
|
36
|
+
vendor/addressable/CHANGELOG
|
37
|
+
vendor/addressable/LICENSE
|
38
|
+
vendor/addressable/README
|
39
|
+
vendor/addressable/Rakefile
|
40
|
+
vendor/addressable/lib/addressable/idna.rb
|
41
|
+
vendor/addressable/lib/addressable/uri.rb
|
42
|
+
vendor/addressable/lib/addressable/version.rb
|
43
|
+
vendor/addressable/spec/addressable/idna_spec.rb
|
44
|
+
vendor/addressable/spec/addressable/uri_spec.rb
|
45
|
+
vendor/addressable/spec/data/rfc3986.txt
|
46
|
+
vendor/addressable/tasks/clobber.rake
|
47
|
+
vendor/addressable/tasks/gem.rake
|
48
|
+
vendor/addressable/tasks/git.rake
|
49
|
+
vendor/addressable/tasks/metrics.rake
|
50
|
+
vendor/addressable/tasks/rdoc.rake
|
51
|
+
vendor/addressable/tasks/rubyforge.rake
|
52
|
+
vendor/addressable/tasks/spec.rake
|
53
|
+
vendor/addressable/website/index.html
|
54
|
+
)
|
55
|
+
|
56
|
+
s.test_files = s.files.select { |path| path =~ /^(test|spec)/ }
|
57
|
+
s.add_dependency('rest-client', ['> 0.0.0'])
|
58
|
+
end
|
data/lib/couchy.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'json'
|
3
|
+
require 'rest_client'
|
4
|
+
|
5
|
+
$:.unshift File.dirname(__FILE__) + '/../vendor/addressable/lib'
|
6
|
+
require 'addressable/uri'
|
7
|
+
|
8
|
+
$:.unshift File.dirname(__FILE__) + '/couchy'
|
9
|
+
|
10
|
+
module Couchy
|
11
|
+
autoload :Server, 'server'
|
12
|
+
autoload :Database, 'database'
|
13
|
+
|
14
|
+
# Shortcut for Couchy::Server.new
|
15
|
+
#
|
16
|
+
# @param [String] uri The URI of the CouchDB server. defaults to "http://localhost:5984/"
|
17
|
+
# @return Couchy::Server
|
18
|
+
def self.new(server_uri='http://localhost:5984/')
|
19
|
+
Server.new(server_uri)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module Couchy
|
5
|
+
class Database
|
6
|
+
attr_accessor :server, :name
|
7
|
+
|
8
|
+
def initialize(server, database_name)
|
9
|
+
@name = database_name
|
10
|
+
@server = server
|
11
|
+
end
|
12
|
+
|
13
|
+
# Gets a list of all the documents available in the database
|
14
|
+
#
|
15
|
+
# @param [Hash] params
|
16
|
+
#
|
17
|
+
# @return [Hash] Parsed server response
|
18
|
+
def documents(params={})
|
19
|
+
server.get("#{name}/_all_docs", params)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Creates a temporary view
|
23
|
+
#
|
24
|
+
# @param [String] function The view function
|
25
|
+
# @param [Hash] params
|
26
|
+
#
|
27
|
+
# @return [Hash] Parsed server response
|
28
|
+
def temp_view(function, params={})
|
29
|
+
server.post("#{name}/_temp_view", function,
|
30
|
+
params.merge!(:headers => {'Content-Type' => 'application/json'}))
|
31
|
+
end
|
32
|
+
|
33
|
+
# Query a view
|
34
|
+
#
|
35
|
+
# @param [String] view_name The name of the view
|
36
|
+
# @param [Hash] params
|
37
|
+
#
|
38
|
+
# @return [Hash] Parsed server response
|
39
|
+
def view(view_name, params={})
|
40
|
+
server.get("#{name}/_view/#{view_name}", params)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Retrieves a document by its ID
|
44
|
+
#
|
45
|
+
# @param [String] id The ID of the document
|
46
|
+
#
|
47
|
+
# @return [Hash] Parsed server response
|
48
|
+
def get(id)
|
49
|
+
server.get("#{name}/#{CGI.escape(id)}")
|
50
|
+
end
|
51
|
+
|
52
|
+
# Retrieves an attachment from a document
|
53
|
+
#
|
54
|
+
# @param [String] document_id The ID of the document
|
55
|
+
# @param [String] attachment_name The name of the attachment
|
56
|
+
#
|
57
|
+
# @return [Hash] Parsed server response
|
58
|
+
def fetch_attachment(document_id, attachment_name)
|
59
|
+
server.get("#{name}/#{CGI.escape(document_id)}/#{CGI.escape(attachment_name)}", :no_json => true)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Saves or updates a document
|
63
|
+
#
|
64
|
+
# @param [Hash] doc The document
|
65
|
+
#
|
66
|
+
# @return [Hash] Parsed server response
|
67
|
+
def save(doc)
|
68
|
+
doc = encode_attachments_of(doc)
|
69
|
+
|
70
|
+
if doc['_id']
|
71
|
+
server.put("#{name}/#{CGI.escape(doc['_id'])}", doc)
|
72
|
+
else
|
73
|
+
server.post("#{name}", doc)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Saves or updates a bunch of documents
|
78
|
+
#
|
79
|
+
# @param [Array] docs The documents to save
|
80
|
+
#
|
81
|
+
# @return [Hash] Parsed server response
|
82
|
+
def bulk_save(docs)
|
83
|
+
server.post("#{name}/_bulk_docs", {:docs => docs})
|
84
|
+
end
|
85
|
+
|
86
|
+
# Deletes a document
|
87
|
+
#
|
88
|
+
# @param [String, Hash] document Document ID or an Hash representing the document
|
89
|
+
# @param [String] revision Document's revision
|
90
|
+
#
|
91
|
+
# @raise ArgumentError When the Hash representing the document neither has
|
92
|
+
# an ID nor a revision
|
93
|
+
#
|
94
|
+
# @raise ArgumentError When document is neither an ID nor an Hash
|
95
|
+
# representing a document
|
96
|
+
#
|
97
|
+
# @return [Hash] Parsed server response
|
98
|
+
def delete(document, revision=nil)
|
99
|
+
case document
|
100
|
+
when String
|
101
|
+
raise ArgumentError, 'Document revision must be specified' unless revision
|
102
|
+
server.delete "#{name}/#{CGI.escape(document)}", :rev => revision
|
103
|
+
when Hash
|
104
|
+
raise ArgumentError, 'Document ID and revision must be specified' unless
|
105
|
+
document['_id'] && document['_rev']
|
106
|
+
server.delete("#{name}/#{CGI.escape(document['_id'])}", :rev => document['_rev'])
|
107
|
+
else
|
108
|
+
raise ArgumentError, 'Document must be an Hash representing the document or its ID'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Deletes the current database
|
113
|
+
#
|
114
|
+
# @return [Hash] Parsed server response
|
115
|
+
def delete!
|
116
|
+
server.delete(name)
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
def encode_attachments_of(doc)
|
121
|
+
return doc unless doc['_attachments']
|
122
|
+
doc['_attachments'].each { |_, v| v.update('data' => base64(v['data'])) } and doc
|
123
|
+
end
|
124
|
+
|
125
|
+
def base64(data)
|
126
|
+
Base64.encode64(data.to_s).gsub(/\s/,'')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Couchy
|
2
|
+
class Server
|
3
|
+
attr_accessor :uri
|
4
|
+
|
5
|
+
def initialize(uri)
|
6
|
+
@uri = Addressable::URI.parse(uri)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Gets information about the server
|
10
|
+
#
|
11
|
+
# @return [Hash] Parsed server response
|
12
|
+
def info
|
13
|
+
get '/'
|
14
|
+
end
|
15
|
+
|
16
|
+
# Restarts the server
|
17
|
+
#
|
18
|
+
# @return [Hash] Parsed server response
|
19
|
+
def restart!
|
20
|
+
post '_restart'
|
21
|
+
end
|
22
|
+
|
23
|
+
# Gets a list of all the databases available on the server
|
24
|
+
#
|
25
|
+
# @return [Array] Parsed server response
|
26
|
+
def databases
|
27
|
+
get '_all_dbs'
|
28
|
+
end
|
29
|
+
|
30
|
+
# Gets a new [Couchy::Database] for the database
|
31
|
+
#
|
32
|
+
# @param [String] name The name of the database
|
33
|
+
#
|
34
|
+
# @return [Couchy::Database] The database
|
35
|
+
def database(name)
|
36
|
+
Database.new(self, name)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Creates a database
|
40
|
+
#
|
41
|
+
# @param [String] name Database's name
|
42
|
+
#
|
43
|
+
# @return [Couchy::Database] The newly created database
|
44
|
+
def create_db(name)
|
45
|
+
put(name)
|
46
|
+
database(name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def get(path, params={})
|
50
|
+
need_json = !params.delete(:no_json)
|
51
|
+
response = RestClient.get(uri_for(path, params))
|
52
|
+
need_json ? json(response, :max_nesting => false) : response
|
53
|
+
end
|
54
|
+
|
55
|
+
def post(path, doc=nil, params={})
|
56
|
+
headers = params.delete(:headers)
|
57
|
+
payload = doc.to_json if doc
|
58
|
+
json RestClient.post(uri_for(path, params), payload, headers)
|
59
|
+
end
|
60
|
+
|
61
|
+
def put(path, doc=nil)
|
62
|
+
payload = doc.to_json if doc
|
63
|
+
json RestClient.put(uri_for(path), payload)
|
64
|
+
end
|
65
|
+
|
66
|
+
def delete(path, params={})
|
67
|
+
json RestClient.delete(uri_for(path, params))
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
def uri_for(path, params={})
|
72
|
+
u = uri.join(path)
|
73
|
+
u.query_values = stringify_keys_and_jsonify_values(params) if params.any?
|
74
|
+
u.to_s
|
75
|
+
end
|
76
|
+
|
77
|
+
def json(json_string, options={})
|
78
|
+
JSON.parse(json_string, options)
|
79
|
+
end
|
80
|
+
|
81
|
+
def stringify_keys_and_jsonify_values(hash)
|
82
|
+
hash.inject({}) do |memo, (key, value)|
|
83
|
+
value = value.to_json if %w(key startkey endkey).include?(key.to_s)
|
84
|
+
memo[key.to_s] = value.to_s
|
85
|
+
memo
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|