sabbath 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/README.rdoc +22 -0
- data/Rakefile +23 -0
- data/VERSION +1 -0
- data/bin/sabbath +38 -0
- data/examples/basic/index.html +173 -0
- data/lib/sabbath/backend/beanstalk.rb +43 -0
- data/lib/sabbath/backend.rb +1 -0
- data/lib/sabbath/server.rb +143 -0
- data/lib/sabbath.rb +25 -0
- metadata +132 -0
data/README.rdoc
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
= Sabbath
|
2
|
+
|
3
|
+
REST interface to beanstalkd (or probably other queues at some point).
|
4
|
+
|
5
|
+
== Usage
|
6
|
+
|
7
|
+
>> sabbath -h
|
8
|
+
|
9
|
+
<< Usage: sabbath [options]
|
10
|
+
<<
|
11
|
+
<< Options:
|
12
|
+
<< -p, --port[OPTIONAL] Port (default: 11300)
|
13
|
+
<< -h, --host[OPTIONAL] Host (default: localhost)
|
14
|
+
<< -P, --web-port[OPTIONAL] Web port (default: 4848)
|
15
|
+
<< -H, --web-host[OPTIONAL] Web host (default: 0.0.0.0)
|
16
|
+
<< --help Show this help message.
|
17
|
+
|
18
|
+
== Why?
|
19
|
+
|
20
|
+
This allows you to interface with beanstalk over normal HTTP calls. I've included a really simple example in the +examples+ directory. It consumes
|
21
|
+
and pushes jobs onto a queue from jQuery.
|
22
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'jeweler'
|
5
|
+
Jeweler::Tasks.new do |s|
|
6
|
+
s.name = "sabbath"
|
7
|
+
s.description = s.summary = "Rest for your work (queues)"
|
8
|
+
s.email = "joshbuddy@gmail.com"
|
9
|
+
s.homepage = "http://github.com/joshbuddy/sabbath"
|
10
|
+
s.authors = ["Joshua Hull"].sort
|
11
|
+
s.files = FileList["[A-Z]*", "{lib,bin,examples}/**/*"]
|
12
|
+
s.add_dependency 'thin'
|
13
|
+
s.add_dependency 'eventmachine'
|
14
|
+
s.add_dependency 'em-beanstalk', '>=0.0.6'
|
15
|
+
s.add_dependency 'rack'
|
16
|
+
s.add_dependency 'usher'
|
17
|
+
s.add_dependency 'json'
|
18
|
+
s.add_dependency 'uuid'
|
19
|
+
end
|
20
|
+
Jeweler::GemcutterTasks.new
|
21
|
+
rescue LoadError
|
22
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
23
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/bin/sabbath
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby -rubygems
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'sabbath')
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
options = {}
|
7
|
+
options[:port] = 11300
|
8
|
+
options[:host] = 'localhost'
|
9
|
+
options[:web_port] = 4848
|
10
|
+
options[:web_host] = '0.0.0.0'
|
11
|
+
|
12
|
+
parser = OptionParser.new do |opts|
|
13
|
+
opts.banner = "Usage: sabbath [options]"
|
14
|
+
|
15
|
+
opts.separator ""
|
16
|
+
opts.separator "Options:"
|
17
|
+
|
18
|
+
opts.on("-p[OPTIONAL]", "--port", "Port (default: #{options[:port]})") do |v|
|
19
|
+
options[:port] = v
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on("-h[OPTIONAL]", "--host", "Host (default: #{options[:host]})") do |v|
|
23
|
+
options[:host] = v
|
24
|
+
end
|
25
|
+
|
26
|
+
opts.on("-P[OPTIONAL]", "--web-port", "Web port (default: #{options[:web_port]})") do |v|
|
27
|
+
options[:port] = v
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on("-H[OPTIONAL]", "--web-host", "Web host (default: #{options[:web_host]})") do |v|
|
31
|
+
options[:host] = v
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on_tail("-h", "--help", "Show this help message.") { puts opts; exit }
|
35
|
+
end
|
36
|
+
parser.parse!(ARGV)
|
37
|
+
|
38
|
+
Sabbath.new(options).start
|
@@ -0,0 +1,173 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<script src="http://www.google.com/jsapi"></script>
|
4
|
+
<script>
|
5
|
+
// Load jQuery
|
6
|
+
google.load("jquery", "1.3.2");
|
7
|
+
|
8
|
+
google.setOnLoadCallback(function() {
|
9
|
+
$(document).ready(function() {
|
10
|
+
var base = 'http://localhost:4848';
|
11
|
+
|
12
|
+
function loadJob(force) {
|
13
|
+
if (force || $('#jobs div').length == 0) $('#jobs').html('waiting for job...');
|
14
|
+
if ($('#jobs div').length == 0) {
|
15
|
+
|
16
|
+
|
17
|
+
$.ajax({
|
18
|
+
type: "GET",
|
19
|
+
dataType: "jsonp",
|
20
|
+
url: base + "/default",
|
21
|
+
|
22
|
+
async: true, /* If set to non-async, browser shows page as "Loading.."*/
|
23
|
+
cache: false,
|
24
|
+
timeout: 50000, /* Timeout in ms */
|
25
|
+
|
26
|
+
success: function (data, textStatus) {
|
27
|
+
// data could be xmlDoc, jsonObj, html, text, etc...
|
28
|
+
$('#jobs').html('<div id="' + data.id + '">' + data.body + '</div>');
|
29
|
+
},
|
30
|
+
error: function (XMLHttpRequest, textStatus, errorThrown) {
|
31
|
+
// typically only one of textStatus or errorThrown
|
32
|
+
// will have info
|
33
|
+
alert("fail:" +textStatus);
|
34
|
+
}
|
35
|
+
});
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
loadJob();
|
40
|
+
|
41
|
+
$('#approve').click(function() {
|
42
|
+
if ($('#jobs div').length > 0) {
|
43
|
+
var id = $('#jobs div')[0].id;
|
44
|
+
|
45
|
+
// do your approval here
|
46
|
+
|
47
|
+
$.ajax({
|
48
|
+
type: "GET",
|
49
|
+
dataType: "jsonp",
|
50
|
+
url: base + "/default/" + id + "?_method=delete",
|
51
|
+
|
52
|
+
async: true, /* If set to non-async, browser shows page as "Loading.."*/
|
53
|
+
cache: false,
|
54
|
+
timeout: 50000, /* Timeout in ms */
|
55
|
+
|
56
|
+
success: function (data, textStatus) {
|
57
|
+
loadJob(true);
|
58
|
+
alert('Approved!');
|
59
|
+
},
|
60
|
+
error: function (XMLHttpRequest, textStatus, errorThrown) {
|
61
|
+
// typically only one of textStatus or errorThrown
|
62
|
+
// will have info
|
63
|
+
alert("fail:" +textStatus);
|
64
|
+
}
|
65
|
+
});
|
66
|
+
} else {
|
67
|
+
alert('you have no jobs pending');
|
68
|
+
}
|
69
|
+
});
|
70
|
+
|
71
|
+
$('#reject').click(function() {
|
72
|
+
if ($('#jobs div').length > 0) {
|
73
|
+
var id = $('#jobs div')[0].id;
|
74
|
+
|
75
|
+
// do your rejection here
|
76
|
+
|
77
|
+
$.ajax({
|
78
|
+
type: "GET",
|
79
|
+
dataType: "jsonp",
|
80
|
+
url: base + "/default/" + id + "?_method=delete",
|
81
|
+
|
82
|
+
async: true, /* If set to non-async, browser shows page as "Loading.."*/
|
83
|
+
cache: false,
|
84
|
+
timeout: 50000, /* Timeout in ms */
|
85
|
+
|
86
|
+
success: function (data, textStatus) {
|
87
|
+
loadJob(true);
|
88
|
+
alert('Approved!');
|
89
|
+
},
|
90
|
+
error: function (XMLHttpRequest, textStatus, errorThrown) {
|
91
|
+
// typically only one of textStatus or errorThrown
|
92
|
+
// will have info
|
93
|
+
alert("fail:" +textStatus);
|
94
|
+
}
|
95
|
+
});
|
96
|
+
} else {
|
97
|
+
alert('you have no jobs pending');
|
98
|
+
}
|
99
|
+
});
|
100
|
+
|
101
|
+
$('#defer').click(function() {
|
102
|
+
if ($('#jobs div').length > 0) {
|
103
|
+
var id = $('#jobs div')[0].id;
|
104
|
+
|
105
|
+
// do your rejection here
|
106
|
+
|
107
|
+
$.ajax({
|
108
|
+
type: "GET",
|
109
|
+
dataType: "jsonp",
|
110
|
+
url: base + "/default/" + id + "/release?_method=put",
|
111
|
+
|
112
|
+
async: true, /* If set to non-async, browser shows page as "Loading.."*/
|
113
|
+
cache: false,
|
114
|
+
timeout: 50000, /* Timeout in ms */
|
115
|
+
|
116
|
+
success: function (data, textStatus) {
|
117
|
+
loadJob(true);
|
118
|
+
alert('Approved!');
|
119
|
+
},
|
120
|
+
error: function (XMLHttpRequest, textStatus, errorThrown) {
|
121
|
+
// typically only one of textStatus or errorThrown
|
122
|
+
// will have info
|
123
|
+
alert("fail:" +textStatus);
|
124
|
+
}
|
125
|
+
});
|
126
|
+
} else {
|
127
|
+
alert('you have no jobs pending');
|
128
|
+
}
|
129
|
+
});
|
130
|
+
|
131
|
+
$("#submit").submit(function(e) {
|
132
|
+
alert('sending!');
|
133
|
+
e.preventDefault();
|
134
|
+
$.ajax({
|
135
|
+
type: "GET",
|
136
|
+
dataType: "jsonp",
|
137
|
+
url: base + "/default",
|
138
|
+
data: {body: $('#body').val(), _method: 'post'},
|
139
|
+
async: true, /* If set to non-async, browser shows page as "Loading.."*/
|
140
|
+
cache: false,
|
141
|
+
timeout: 50000, /* Timeout in ms */
|
142
|
+
|
143
|
+
success: function (data, textStatus) {
|
144
|
+
alert('submitted new job');
|
145
|
+
loadJob();
|
146
|
+
},
|
147
|
+
error: function (XMLHttpRequest, textStatus, errorThrown) {
|
148
|
+
// typically only one of textStatus or errorThrown
|
149
|
+
// will have info
|
150
|
+
alert("fail:" +textStatus);
|
151
|
+
}
|
152
|
+
});
|
153
|
+
|
154
|
+
|
155
|
+
|
156
|
+
});
|
157
|
+
});
|
158
|
+
|
159
|
+
});
|
160
|
+
|
161
|
+
</script>
|
162
|
+
</head>
|
163
|
+
<body>
|
164
|
+
<h1>Jobs</h1>
|
165
|
+
<div id="jobs"></div>
|
166
|
+
<input type="button" id="approve" value="Approve"><input type="button" id="reject" value="Reject"><input type="button" id="defer" value="Defer">
|
167
|
+
|
168
|
+
<form id="submit">
|
169
|
+
<textarea id="body"></textarea><br>
|
170
|
+
<input type="submit" value="Submit">
|
171
|
+
</form>
|
172
|
+
</body>
|
173
|
+
</html>
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'em-beanstalk'
|
2
|
+
|
3
|
+
class Sabbath
|
4
|
+
class Backend
|
5
|
+
class Beanstalk
|
6
|
+
|
7
|
+
attr_reader :host, :port
|
8
|
+
|
9
|
+
Name = 'Beanstalkd'.freeze
|
10
|
+
|
11
|
+
def name
|
12
|
+
Name
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(host, port)
|
16
|
+
@host, @port = host, port
|
17
|
+
@conns = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def connection(id, tube = 'default')
|
21
|
+
@conns[id] ||= EM::Beanstalk.new(:host => host, :port => port, :tube => tube, :retry_count => 0, :raise_on_disconnect => false)
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_latest_job(conn_id, tube, timeout = nil, &block)
|
25
|
+
connection(conn_id, tube).reserve(timeout, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_job(conn_idtube, id, &block)
|
29
|
+
connection(conn_id, tube).peek(id, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_job(conn_id, tube, body, &block)
|
33
|
+
connection(conn_id, tube).put(body, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete_job(conn_id, tube, id, &block)
|
37
|
+
puts "deleting job #{tube.inspect} #{id.inspect}"
|
38
|
+
connection(conn_id, tube).delete(id, &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'sabbath/backend/beanstalk'
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module Thin
|
2
|
+
class Server
|
3
|
+
# Start the server and listen for connections.
|
4
|
+
def start
|
5
|
+
raise ArgumentError, 'app required' unless @app
|
6
|
+
|
7
|
+
log ">> Sabbath ---> connected to #{app.backend.name} on port #{app.backend.port}, host #{app.backend.host}"
|
8
|
+
log ">> Using Thin web server (v#{VERSION::STRING} codename #{VERSION::CODENAME})"
|
9
|
+
debug ">> Debugging ON"
|
10
|
+
trace ">> Tracing ON"
|
11
|
+
|
12
|
+
log ">> Maximum connections set to #{@backend.maximum_connections}"
|
13
|
+
log ">> Listening on #{@backend}, CTRL+C to stop"
|
14
|
+
|
15
|
+
@backend.start
|
16
|
+
end
|
17
|
+
alias :start! :start
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Sabbath
|
22
|
+
class Server
|
23
|
+
|
24
|
+
class DeferrableBody
|
25
|
+
include EventMachine::Deferrable
|
26
|
+
|
27
|
+
attr_accessor :jsonp_callback
|
28
|
+
|
29
|
+
def call(body)
|
30
|
+
body.each do |chunk|
|
31
|
+
@body_callback.call(chunk)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def each(&blk)
|
36
|
+
@body_callback = blk
|
37
|
+
end
|
38
|
+
|
39
|
+
def succeed_with(body)
|
40
|
+
data = if jsonp_callback
|
41
|
+
"#{jsonp_callback}(#{body.to_json})"
|
42
|
+
else
|
43
|
+
body.to_json
|
44
|
+
end
|
45
|
+
|
46
|
+
puts "sending #{data.inspect}"
|
47
|
+
call(Array(data))
|
48
|
+
succeed
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
AsyncResponse = [-1, {}, []].freeze
|
55
|
+
|
56
|
+
attr_reader :backend, :web_host, :web_port, :cookie_name
|
57
|
+
|
58
|
+
def initialize(backend, web_host, web_port, cookie_name = 'sabbath_id')
|
59
|
+
@backend = backend
|
60
|
+
@web_host, @web_port, @cookie_name = web_host, web_port, cookie_name
|
61
|
+
@router = Usher.new(:request_methods => [:request_method], :delimiters => ['/', '.'])
|
62
|
+
@router.add_route('/:tube', :conditions => {:request_method => 'GET'}) .name(:get_latest_job)
|
63
|
+
@router.add_route('/:tube/:job_id', :conditions => {:request_method => 'GET'}) .name(:get_job)
|
64
|
+
@router.add_route('/:tube', :conditions => {:request_method => 'POST'}) .name(:create_job)
|
65
|
+
@router.add_route('/:tube/:job_id', :conditions => {:request_method => 'DELETE'}) .name(:delete_job)
|
66
|
+
@router.add_route('/:tube/:job_id/release', :conditions => {:request_method => 'PUT'}) .name(:release_job)
|
67
|
+
end
|
68
|
+
|
69
|
+
def call(env)
|
70
|
+
request = Rack::Request.new(env)
|
71
|
+
query_params = Rack::Utils.parse_query(request.query_string)
|
72
|
+
env['REQUEST_METHOD'] = query_params['_method'].upcase if query_params['_method']
|
73
|
+
|
74
|
+
id = request.cookies[cookie_name] || UUID.new.generate
|
75
|
+
p id
|
76
|
+
common_response_headers = {'Content-Type' => 'text/javascript'}
|
77
|
+
|
78
|
+
common_response_headers['Set-cookie'] = Rack::Utils.build_query(cookie_name => id) unless request.cookies[cookie_name]
|
79
|
+
|
80
|
+
body = DeferrableBody.new
|
81
|
+
# Get the headers out there asap, let the client know we're alive...
|
82
|
+
EventMachine::next_tick {
|
83
|
+
body.jsonp_callback = query_params['callback']
|
84
|
+
case response = @router.recognize(request)
|
85
|
+
when nil
|
86
|
+
env['async.callback'].call([404, {}, []])
|
87
|
+
else
|
88
|
+
params = response.params_as_hash
|
89
|
+
case response.path.route.named
|
90
|
+
when :get_latest_job
|
91
|
+
puts "latest job..."
|
92
|
+
env['async.callback'].call([200, common_response_headers, body])
|
93
|
+
backend.get_latest_job(id, params[:tube], params['timeout']) {|job|
|
94
|
+
puts "sending job.body: #{job.body}"
|
95
|
+
body.succeed_with(:id => job.id, :body => job.body)
|
96
|
+
}.on_error {|message|
|
97
|
+
puts "message.. #{message}"
|
98
|
+
body.succeed_with(:error => message)
|
99
|
+
}
|
100
|
+
when :get_job
|
101
|
+
env['async.callback'].call([200, common_response_headers, body])
|
102
|
+
backend.get_job(id, params[:tube], params[:job_id]) {|job|
|
103
|
+
body.succeed_with(:id => job.id, :body => job.body)
|
104
|
+
}.on_error {|message|
|
105
|
+
body.succeed_with(:error => message)
|
106
|
+
}
|
107
|
+
when :create_job
|
108
|
+
env['async.callback'].call([200, common_response_headers, body])
|
109
|
+
backend.create_job(id, params[:tube], query_params['body']) {|id|
|
110
|
+
body.succeed_with(:id => id)
|
111
|
+
}.on_error {|message|
|
112
|
+
body.succeed_with(:error => message)
|
113
|
+
}
|
114
|
+
when :delete_job
|
115
|
+
env['async.callback'].call([200, common_response_headers, body])
|
116
|
+
backend.delete_job(id, params[:tube], params[:job_id]) {
|
117
|
+
body.succeed_with(:success => true)
|
118
|
+
}.on_error {|message|
|
119
|
+
body.succeed_with(:error => message)
|
120
|
+
}
|
121
|
+
when :release_job
|
122
|
+
env['async.callback'].call([200, common_response_headers, body])
|
123
|
+
backend.release_job(id, params[:tube], params[:job_id]) {
|
124
|
+
body.succeed_with(:success => true)
|
125
|
+
}.on_error {|message|
|
126
|
+
body.succeed_with(:error => message)
|
127
|
+
}
|
128
|
+
end
|
129
|
+
end
|
130
|
+
}
|
131
|
+
AsyncResponse
|
132
|
+
end
|
133
|
+
|
134
|
+
def start
|
135
|
+
@server = self
|
136
|
+
EM.run do
|
137
|
+
Thin::Server.start(web_host, web_port, self)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
|
data/lib/sabbath.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'thin'
|
2
|
+
require 'rack'
|
3
|
+
require 'usher'
|
4
|
+
require 'json'
|
5
|
+
require 'uuid'
|
6
|
+
|
7
|
+
$LOAD_PATH << File.dirname(__FILE__)
|
8
|
+
|
9
|
+
require 'sabbath/server'
|
10
|
+
require 'sabbath/backend'
|
11
|
+
|
12
|
+
class Sabbath
|
13
|
+
|
14
|
+
attr_reader :options
|
15
|
+
|
16
|
+
def initialize(options)
|
17
|
+
@options = options
|
18
|
+
@backend = Backend::Beanstalk.new(options[:host], options[:port])
|
19
|
+
end
|
20
|
+
|
21
|
+
def start
|
22
|
+
Server.new(@backend, options[:web_host], options[:web_port]).start
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sabbath
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joshua Hull
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-10 00:00:00 -05:00
|
13
|
+
default_executable: sabbath
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: thin
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: eventmachine
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: em-beanstalk
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.0.6
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: rack
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: usher
|
57
|
+
type: :runtime
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: json
|
67
|
+
type: :runtime
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: uuid
|
77
|
+
type: :runtime
|
78
|
+
version_requirement:
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
description: Rest for your work (queues)
|
86
|
+
email: joshbuddy@gmail.com
|
87
|
+
executables:
|
88
|
+
- sabbath
|
89
|
+
extensions: []
|
90
|
+
|
91
|
+
extra_rdoc_files:
|
92
|
+
- README.rdoc
|
93
|
+
files:
|
94
|
+
- README.rdoc
|
95
|
+
- Rakefile
|
96
|
+
- VERSION
|
97
|
+
- bin/sabbath
|
98
|
+
- examples/basic/index.html
|
99
|
+
- lib/sabbath.rb
|
100
|
+
- lib/sabbath/backend.rb
|
101
|
+
- lib/sabbath/backend/beanstalk.rb
|
102
|
+
- lib/sabbath/server.rb
|
103
|
+
has_rdoc: true
|
104
|
+
homepage: http://github.com/joshbuddy/sabbath
|
105
|
+
licenses: []
|
106
|
+
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options:
|
109
|
+
- --charset=UTF-8
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: "0"
|
117
|
+
version:
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: "0"
|
123
|
+
version:
|
124
|
+
requirements: []
|
125
|
+
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 1.3.5
|
128
|
+
signing_key:
|
129
|
+
specification_version: 3
|
130
|
+
summary: Rest for your work (queues)
|
131
|
+
test_files: []
|
132
|
+
|