em-couchdb-request 0.0.1
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 +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/em-couchdb-request.gemspec +23 -0
- data/lib/em-couchdb-request/base.rb +53 -0
- data/lib/em-couchdb-request/database.rb +50 -0
- data/lib/em-couchdb-request/load_testing/agent.rb +145 -0
- data/lib/em-couchdb-request/server.rb +55 -0
- data/lib/em-couchdb-request/version.rb +5 -0
- data/lib/em-couchdb-request.rb +8 -0
- data/spec/database_spec.rb +92 -0
- data/spec/helper.rb +4 -0
- data/spec/server_spec.rb +29 -0
- metadata +111 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Louie Zhao
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Em::Couchdb::Request
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'em-couchdb-request'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install em-couchdb-request
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'em-couchdb-request/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "em-couchdb-request"
|
8
|
+
gem.version = EventMachine::Couchdb::VERSION
|
9
|
+
gem.authors = ["Louie Zhao"]
|
10
|
+
gem.email = ["louie.zhao@gmail.com"]
|
11
|
+
gem.description = %q{EventMachine based, async CouchDB request client}
|
12
|
+
gem.summary = %q{EventMachine based, async CouchDB request client}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency "json"
|
21
|
+
gem.add_dependency "em-http-request"
|
22
|
+
gem.add_development_dependency "rspec"
|
23
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module EventMachine
|
2
|
+
module Couchdb
|
3
|
+
|
4
|
+
class Base
|
5
|
+
|
6
|
+
attr_reader :connect_options, :request_options
|
7
|
+
|
8
|
+
REQUEST_OPTIONS = {
|
9
|
+
:head => {
|
10
|
+
'content-type' => 'application/json'
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
def log(msg, start_at=Time.now)
|
15
|
+
span = "%8.2f" % ((Time.now - start_at) * 1000)
|
16
|
+
puts "#{Time.now.strftime("%X")}\t#{span}\t#{msg}"
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def base_uri
|
22
|
+
raise NotImplementedError
|
23
|
+
end
|
24
|
+
|
25
|
+
def new_http_request(opts={}, &callback)
|
26
|
+
start_at = Time.now
|
27
|
+
|
28
|
+
url = opts.delete :url
|
29
|
+
method = opts.delete(:method) || :get
|
30
|
+
|
31
|
+
request_options = REQUEST_OPTIONS.merge(@request_options || {})
|
32
|
+
|
33
|
+
http = EventMachine::HttpRequest.new("#{base_uri}/#{url}", @connect_options).send method, request_options.merge(opts)
|
34
|
+
|
35
|
+
http.callback {
|
36
|
+
resp = JSON.load(http.response) rescue {}
|
37
|
+
callback.call resp
|
38
|
+
}
|
39
|
+
|
40
|
+
http.errback {
|
41
|
+
log "#{http.error || 'ERROR'}:\tunable to #{method} #{url}", start_at
|
42
|
+
}
|
43
|
+
|
44
|
+
http
|
45
|
+
end
|
46
|
+
|
47
|
+
def paramize(opts)
|
48
|
+
opts.collect{ |k, v| "#{k}=#{v}" }.join('&')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module EventMachine
|
2
|
+
module Couchdb
|
3
|
+
|
4
|
+
class Database < Base
|
5
|
+
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(uri, name, opts={})
|
9
|
+
@uri = uri
|
10
|
+
@name = name
|
11
|
+
@connect_options = opts[:connect_options] || {}
|
12
|
+
@request_options = opts[:request_options] || {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def base_uri
|
16
|
+
[@uri, @name].join('/')
|
17
|
+
end
|
18
|
+
|
19
|
+
def all_docs(&callback)
|
20
|
+
new_http_request :url => "_all_docs", &callback
|
21
|
+
end
|
22
|
+
|
23
|
+
def doc(doc_id, &callback)
|
24
|
+
new_http_request :url => doc_id, &callback
|
25
|
+
end
|
26
|
+
|
27
|
+
def save_doc(doc, &callback)
|
28
|
+
method = doc['id'] ? :put : :post
|
29
|
+
new_http_request :url => doc['id'], :method => method, :body => JSON.dump(doc), &callback
|
30
|
+
end
|
31
|
+
|
32
|
+
def delete_doc(doc, &callback)
|
33
|
+
new_http_request :url => "#{doc['id']}?rev=#{doc['rev']}", :method => :delete, &callback
|
34
|
+
end
|
35
|
+
|
36
|
+
def changes(opts, &stream)
|
37
|
+
http = new_http_request(:url => "_changes?#{paramize(opts)}") {}
|
38
|
+
|
39
|
+
http.stream { |chunk|
|
40
|
+
data = JSON.load(chunk) rescue {}
|
41
|
+
stream.call data
|
42
|
+
}
|
43
|
+
|
44
|
+
http
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
module EventMachine
|
2
|
+
module Couchdb
|
3
|
+
module LoadTesting
|
4
|
+
|
5
|
+
class KeyboardHandler < EM::Connection
|
6
|
+
include EM::Protocols::LineText2
|
7
|
+
|
8
|
+
def initialize(project)
|
9
|
+
@project = project
|
10
|
+
end
|
11
|
+
|
12
|
+
def receive_line(data)
|
13
|
+
@project.lock = false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Agent
|
18
|
+
DEFAULT_OPTIONS = {
|
19
|
+
:content_size => 1024 * 1, # size of random bytes written to a random document in the database
|
20
|
+
:push_interval => 20, # interval between PUSH
|
21
|
+
:poll_interval => 0.001, # interval between generating POLL connections - control the creating speed
|
22
|
+
:poll_max_count => 2500, # count of the total POLL connections
|
23
|
+
:poll_bulk_count => 500, # size of a POLL GROUP - that is created continously (step by POLL_INTERVAL)
|
24
|
+
:poll_bulk_interval => 1200 # interval between POLL GROUP (or continue by pressing any key)
|
25
|
+
}
|
26
|
+
|
27
|
+
# lock to disable creating new poll connection
|
28
|
+
attr_accessor :lock
|
29
|
+
|
30
|
+
def initialize(uri, name, opts={})
|
31
|
+
@server = EventMachine::Couchdb::Server.new uri, opts
|
32
|
+
@db = @server.em_database(name)
|
33
|
+
@docs = []
|
34
|
+
|
35
|
+
@max_id = 0
|
36
|
+
@count = 0
|
37
|
+
@lock = false
|
38
|
+
|
39
|
+
@options = DEFAULT_OPTIONS.merge(opts[:agent_options])
|
40
|
+
end
|
41
|
+
|
42
|
+
def push
|
43
|
+
EM.run {
|
44
|
+
@db.all_docs { |resp|
|
45
|
+
@docs = resp["rows"].collect{ |row| row["id"] }
|
46
|
+
}
|
47
|
+
|
48
|
+
puts ">> Start to push to #{@db.base_uri} every #{@options[:push_interval]} seconds ..."
|
49
|
+
|
50
|
+
EM.add_periodic_timer(@options[:push_interval]) {
|
51
|
+
#
|
52
|
+
# --- why get the doc first before updating ---
|
53
|
+
#
|
54
|
+
# To update an existing document, you also issue a PUT request.
|
55
|
+
# In this case, the JSON body must contain a _rev property, which lets CouchDB know which revision the edits are based on.
|
56
|
+
# If the revision of the document currently stored in the database doesn't match, then a 409 conflict error is returned.
|
57
|
+
begin
|
58
|
+
start_at = Time.now
|
59
|
+
@db.doc(@docs.sample) { |resp|
|
60
|
+
# set the new content
|
61
|
+
resp[:random_bytes] = SecureRandom.hex(@options[:content_size])
|
62
|
+
# update doc and record the latest revision
|
63
|
+
@db.save_doc(resp) { |resp|
|
64
|
+
@db.log "PUSH\t#{@options[:content_size]}\t#{resp["rev"]}", start_at
|
65
|
+
}
|
66
|
+
}
|
67
|
+
rescue
|
68
|
+
@db.log "PUSH\t#{@options[:content_size]}\t#{resp["rev"]}", start_at
|
69
|
+
end
|
70
|
+
}
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
def poll
|
75
|
+
# http://eventmachine.rubyforge.org/docs/EPOLL.html
|
76
|
+
EM.epoll
|
77
|
+
|
78
|
+
EM.run {
|
79
|
+
EM.open_keyboard(KeyboardHandler, self)
|
80
|
+
|
81
|
+
@server.get_db(@db.name) { |resp|
|
82
|
+
# ensure to get something for feedback when connection
|
83
|
+
seq = resp["update_seq"] - 1
|
84
|
+
|
85
|
+
# auto continue for each POLL_BULK_INTERVAL
|
86
|
+
b_timer = nil
|
87
|
+
if @options[:poll_bulk_interval] > 0
|
88
|
+
b_timer = EM.add_periodic_timer(@options[:poll_bulk_interval]) {
|
89
|
+
@lock = false
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
puts ">> Start to poll from #{@db.base_uri} (since #{seq}) every #{@options[:poll_interval]} seconds ..."
|
94
|
+
|
95
|
+
timer = EM.add_periodic_timer(@options[:poll_interval]) {
|
96
|
+
new_poll_request(:seq => seq) unless @lock
|
97
|
+
|
98
|
+
if @max_id % @options[:poll_bulk_count] == 0
|
99
|
+
@lock = true
|
100
|
+
end
|
101
|
+
|
102
|
+
if @max_id >= @options[:poll_max_count]
|
103
|
+
timer.cancel
|
104
|
+
b_timer.try(:cancel)
|
105
|
+
end
|
106
|
+
}
|
107
|
+
}
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
protected
|
112
|
+
|
113
|
+
def new_poll_request(opts={})
|
114
|
+
# simulate 'AUTO INCREMENT ID' for index
|
115
|
+
@count += 1
|
116
|
+
@max_id += 1
|
117
|
+
index = @max_id
|
118
|
+
start_at = Time.now
|
119
|
+
|
120
|
+
# http://wiki.apache.org/couchdb/HTTP%5Fdatabase%5FAPI#Changes
|
121
|
+
# heartbeat - overrides any timeout to keep the feed alive indefinitely.
|
122
|
+
# num - help to debug
|
123
|
+
http = @db.changes({:feed => 'continuous', :heartbeat => 600000, :since => opts[:seq], :num => index}) { |chunk|
|
124
|
+
# {"seq"=>76, "id"=>"eventmachine_couchdb_document", "changes"=>[{"rev"=>"40-084b145e56f8f1edd2d4cd94b8a01561"}]}
|
125
|
+
rev = (chunk['changes'] || [{}]).last['rev']
|
126
|
+
@db.log "[#{index}]\t#{@count}\tPOLL\t#{rev}", start_at
|
127
|
+
start_at = Time.now
|
128
|
+
}
|
129
|
+
|
130
|
+
http.callback {
|
131
|
+
@count -= 1
|
132
|
+
@db.log "[#{index}]\t#{@count}\tE_PO\t#{http.response}", start_at
|
133
|
+
EM.stop if @count == 0
|
134
|
+
}
|
135
|
+
|
136
|
+
http.errback {
|
137
|
+
@count -= 1
|
138
|
+
@db.log "[#{index}]\t#{@count}\tF_PO\t#{http.error || 'ERROR'}", start_at
|
139
|
+
EM.stop if @count == 0
|
140
|
+
}
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module EventMachine
|
2
|
+
module Couchdb
|
3
|
+
|
4
|
+
class Server < Base
|
5
|
+
|
6
|
+
attr_reader :uri
|
7
|
+
|
8
|
+
def initialize(uri, opts={})
|
9
|
+
@uri = uri
|
10
|
+
@connect_options = opts[:connect_options] || {}
|
11
|
+
@request_options = opts[:request_options] || {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def em_database(db_name)
|
15
|
+
Database.new @uri, db_name, {:connect_options => @connect_options, :request_options => @request_options}
|
16
|
+
end
|
17
|
+
|
18
|
+
# Async http request
|
19
|
+
|
20
|
+
def all_dbs(&callback)
|
21
|
+
new_http_request :url => "_all_dbs", &callback
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_db(db_name, &callback)
|
25
|
+
new_http_request :url => db_name, &callback
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_db(db_name, &callback)
|
29
|
+
new_http_request :url => db_name, :method => :put, &callback
|
30
|
+
end
|
31
|
+
|
32
|
+
def delete_db(db_name, &callback)
|
33
|
+
new_http_request :url => db_name, :method => :delete, &callback
|
34
|
+
end
|
35
|
+
|
36
|
+
def ensure_db(db_name, &callback)
|
37
|
+
get_db(db_name) { |resp|
|
38
|
+
if resp['db_name']
|
39
|
+
callback.call
|
40
|
+
else
|
41
|
+
create_db(db_name, &callback)
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def base_uri
|
49
|
+
@uri
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe EventMachine::Couchdb do
|
4
|
+
|
5
|
+
server = EventMachine::Couchdb::Server.new('http://127.0.0.1:5984')
|
6
|
+
|
7
|
+
document = {
|
8
|
+
:time => Time.now
|
9
|
+
}
|
10
|
+
|
11
|
+
context "database" do
|
12
|
+
it "should create/get/delete document" do
|
13
|
+
EventMachine.run {
|
14
|
+
server.ensure_db(DB_NAME_PRFIX) {
|
15
|
+
db = server.em_database(DB_NAME_PRFIX)
|
16
|
+
db.save_doc(document) { |resp|
|
17
|
+
# {"ok"=>true, "id"=>"03399b2af07128fd8bba5650f301f97f", "rev"=>"1-5f68969911f890fe17b3c440b6e6f517"}
|
18
|
+
resp['ok'].should == true
|
19
|
+
doc_id = resp['id']
|
20
|
+
db.all_docs { |resp|
|
21
|
+
# {"total_rows"=>2, "offset"=>0, "rows"=>[{"id"=>"03399b2af07128fd8bba5650f3032057", "key"=>"03399b2af07128fd8bba5650f3032057", "value"=>{"rev"=>"1-bdf934324ba35521452df4abb4d92e30"}}, {"id"=>"eventmachine_couchdb_document", "key"=>"eventmachine_couchdb_document", "value"=>{"rev"=>"16-09f0db6392d6595615ae36bbdc9cc5d0"}}]} to include "03399b2af07128fd8bba5650f3032057"
|
22
|
+
resp["rows"].collect{ |row| row["id"] }.should include(doc_id)
|
23
|
+
db.doc(doc_id) { |resp|
|
24
|
+
# {"_id"=>"03399b2af07128fd8bba5650f301f97f", "_rev"=>"1-5f68969911f890fe17b3c440b6e6f517", "time"=>"2012-11-29 17:36:00 +0800"}
|
25
|
+
resp[:time] = Time.now
|
26
|
+
db.save_doc(resp) { |resp|
|
27
|
+
# {"ok"=>true, "id"=>"03399b2af07128fd8bba5650f301f97f", "rev"=>"2-7e493efb649ace136d0f23c59a089f3d"}
|
28
|
+
resp['ok'].should == true
|
29
|
+
db.delete_doc(resp) { |resp|
|
30
|
+
# {"ok"=>true, "id"=>"03399b2af07128fd8bba5650f301f97f", "rev"=>"3-9de477509c9e66189f33bd7fae9b17db"}
|
31
|
+
resp['ok'].should == true
|
32
|
+
EventMachine.stop
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should get continuous changes" do
|
43
|
+
latest_rev = nil
|
44
|
+
check_times = 0
|
45
|
+
|
46
|
+
EventMachine.run {
|
47
|
+
server.ensure_db(DB_NAME_PRFIX) {
|
48
|
+
db = server.em_database(DB_NAME_PRFIX)
|
49
|
+
|
50
|
+
# Get database update_seq and fire the continous poll conncetion to wait for changes
|
51
|
+
server.get_db(DB_NAME_PRFIX) { |resp|
|
52
|
+
seq = resp["update_seq"]
|
53
|
+
db.changes({:feed => 'continuous', :since => seq}) { |chunk|
|
54
|
+
# {"seq"=>76, "id"=>"eventmachine_couchdb_document", "changes"=>[{"rev"=>"40-084b145e56f8f1edd2d4cd94b8a01561"}]}
|
55
|
+
if rev = (chunk['changes'].first['rev'] rescue nil)
|
56
|
+
rev.should == latest_rev
|
57
|
+
EventMachine.stop if (check_times += 1) == 4
|
58
|
+
end
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
EventMachine.add_periodic_timer(0.5) do
|
63
|
+
#
|
64
|
+
# --- why get the doc first before updating ---
|
65
|
+
#
|
66
|
+
# To update an existing document, you also issue a PUT request.
|
67
|
+
# In this case, the JSON body must contain a _rev property, which lets CouchDB know which revision the edits are based on.
|
68
|
+
# If the revision of the document currently stored in the database doesn't match, then a 409 conflict error is returned.
|
69
|
+
|
70
|
+
db.doc(DOC_ID_PREFIX) { |resp|
|
71
|
+
# set to create the document if not exist
|
72
|
+
if resp['error'] == 'not_found'
|
73
|
+
resp = document
|
74
|
+
resp['id'] = DOC_ID_PREFIX
|
75
|
+
end
|
76
|
+
|
77
|
+
# set the new content
|
78
|
+
resp[:time] = Time.now
|
79
|
+
|
80
|
+
# update doc and record the latest revision
|
81
|
+
db.save_doc(resp) { |resp|
|
82
|
+
latest_rev = resp['rev']
|
83
|
+
}
|
84
|
+
}
|
85
|
+
end
|
86
|
+
}
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/spec/helper.rb
ADDED
data/spec/server_spec.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe EventMachine::Couchdb do
|
4
|
+
|
5
|
+
context "server" do
|
6
|
+
server = EventMachine::Couchdb::Server.new('http://127.0.0.1:5984')
|
7
|
+
|
8
|
+
it "should create/get/delete database" do
|
9
|
+
db_name = "#{DB_NAME_PRFIX}_#{Time.now.to_i}"
|
10
|
+
|
11
|
+
EventMachine.run {
|
12
|
+
server.create_db(db_name) { |resp|
|
13
|
+
resp['ok'].should == true
|
14
|
+
server.all_dbs { |resp|
|
15
|
+
resp.should include(db_name)
|
16
|
+
server.get_db(db_name) { |resp|
|
17
|
+
resp['update_seq'].should == 0
|
18
|
+
server.delete_db(db_name) { |resp|
|
19
|
+
resp['ok'].should == true
|
20
|
+
EventMachine.stop
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: em-couchdb-request
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Louie Zhao
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-06 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: em-http-request
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: EventMachine based, async CouchDB request client
|
63
|
+
email:
|
64
|
+
- louie.zhao@gmail.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- Gemfile
|
71
|
+
- LICENSE.txt
|
72
|
+
- README.md
|
73
|
+
- Rakefile
|
74
|
+
- em-couchdb-request.gemspec
|
75
|
+
- lib/em-couchdb-request.rb
|
76
|
+
- lib/em-couchdb-request/base.rb
|
77
|
+
- lib/em-couchdb-request/database.rb
|
78
|
+
- lib/em-couchdb-request/load_testing/agent.rb
|
79
|
+
- lib/em-couchdb-request/server.rb
|
80
|
+
- lib/em-couchdb-request/version.rb
|
81
|
+
- spec/database_spec.rb
|
82
|
+
- spec/helper.rb
|
83
|
+
- spec/server_spec.rb
|
84
|
+
homepage: ''
|
85
|
+
licenses: []
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
requirements: []
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 1.8.24
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: EventMachine based, async CouchDB request client
|
108
|
+
test_files:
|
109
|
+
- spec/database_spec.rb
|
110
|
+
- spec/helper.rb
|
111
|
+
- spec/server_spec.rb
|