async_sinatra 0.1.5 → 0.2.0
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 +8 -2
- data/Rakefile +11 -12
- data/examples/basic.ru +9 -0
- data/lib/sinatra/async.rb +66 -29
- data/lib/sinatra/async/test.rb +67 -0
- data/test/borked_test_crohr.rb +161 -0
- data/test/test_async.rb +116 -0
- metadata +53 -30
data/README.rdoc
CHANGED
@@ -7,11 +7,17 @@
|
|
7
7
|
== DESCRIPTION:
|
8
8
|
|
9
9
|
A Sinatra plugin to provide convenience whilst performing asynchronous
|
10
|
-
responses inside of the Sinatra framework running under
|
10
|
+
responses inside of the Sinatra framework running under async webservers.
|
11
11
|
|
12
12
|
To properly utilise this package, some knowledge of EventMachine and/or
|
13
13
|
asynchronous patterns is recommended.
|
14
14
|
|
15
|
+
Currently, supporting servers include:
|
16
|
+
|
17
|
+
* Thin
|
18
|
+
* Rainbows
|
19
|
+
* Zbatery
|
20
|
+
|
15
21
|
== SYNOPSIS:
|
16
22
|
|
17
23
|
A quick example:
|
@@ -36,7 +42,7 @@ See Sinatra::Async for more details.
|
|
36
42
|
== REQUIREMENTS:
|
37
43
|
|
38
44
|
* Sinatra (>= 0.9)
|
39
|
-
*
|
45
|
+
* An async webserver
|
40
46
|
|
41
47
|
== INSTALL:
|
42
48
|
|
data/Rakefile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
2
|
require 'rake/clean'
|
3
3
|
|
4
|
-
task :default => :
|
4
|
+
task :default => :test
|
5
5
|
|
6
6
|
def spec(file = Dir['*.gemspec'].first)
|
7
7
|
@spec ||=
|
@@ -19,27 +19,25 @@ end
|
|
19
19
|
|
20
20
|
def manifest; @manifest ||= `git ls-files`.split("\n").reject{|s|s=~/\.gemspec$|\.gitignore$/}; end
|
21
21
|
|
22
|
-
require '
|
23
|
-
def gem_task; @gem_task ||=
|
22
|
+
require 'rubygems/package_task'
|
23
|
+
def gem_task; @gem_task ||= Gem::PackageTask.new(spec); end
|
24
24
|
gem_task.define
|
25
25
|
Rake::Task[:clobber].enhance [:clobber_package]
|
26
26
|
|
27
27
|
require 'rake/testtask'
|
28
|
-
Rake::TestTask.new
|
28
|
+
Rake::TestTask.new do |t|
|
29
29
|
t.test_files = spec.test_files
|
30
|
-
t.ruby_opts = ['-rubygems']
|
30
|
+
t.ruby_opts = ['-rubygems']
|
31
31
|
t.warning = true
|
32
32
|
end unless spec.test_files.empty?
|
33
33
|
|
34
|
-
require '
|
35
|
-
|
36
|
-
rdtask = Rake::RDocTask.new do |rd|
|
34
|
+
require 'rdoc/task'
|
35
|
+
rdtask = RDoc::Task.new do |rd|
|
37
36
|
rd.title = spec.name
|
38
37
|
rd.main = spec.extra_rdoc_files.first
|
39
38
|
lib_rexp = spec.require_paths.map { |p| Regexp.escape p }.join('|')
|
40
39
|
rd.rdoc_files.include(*manifest.grep(/^(?:#{lib_rexp})/))
|
41
40
|
rd.rdoc_files.include(*spec.extra_rdoc_files)
|
42
|
-
rd.template = 'darkfish' if df
|
43
41
|
end
|
44
42
|
|
45
43
|
Rake::Task[:clobber].enhance [:clobber_rdoc]
|
@@ -70,7 +68,7 @@ task :gemspec => spec.filename
|
|
70
68
|
|
71
69
|
task spec.filename do
|
72
70
|
spec.files = manifest
|
73
|
-
spec.test_files = manifest.grep(/
|
71
|
+
spec.test_files = manifest.grep(%r{test/test_.*\.rb})
|
74
72
|
open(spec.filename, 'w') { |w| w.write spec.to_ruby }
|
75
73
|
end
|
76
74
|
|
@@ -90,7 +88,8 @@ task :tag do
|
|
90
88
|
end
|
91
89
|
end
|
92
90
|
|
93
|
-
desc "Release #{gem_task.
|
91
|
+
desc "Release #{gem_task.gem_spec.file_name}"
|
94
92
|
task :release => [:tag, :gem, :publish] do |t|
|
95
|
-
sh "rubyforge add_release #{spec.rubyforge_project} #{spec.name} #{spec.version} #{gem_task.package_dir}/#{gem_task.
|
93
|
+
sh "rubyforge add_release #{spec.rubyforge_project} #{spec.name} #{spec.version} #{gem_task.package_dir}/#{gem_task.gem_spec.file_name}"
|
94
|
+
sh "gem push #{gem_task.package_dir}/#{gem_task.gem_spec.file_name}"
|
96
95
|
end
|
data/examples/basic.ru
CHANGED
@@ -18,6 +18,15 @@ class AsyncTest < Sinatra::Base
|
|
18
18
|
raise 'boom'
|
19
19
|
end
|
20
20
|
|
21
|
+
aget '/araise' do
|
22
|
+
EM.add_timer(1) { body { raise "boom" } }
|
23
|
+
end
|
24
|
+
|
25
|
+
# This will blow up in thin currently
|
26
|
+
aget '/raise/die' do
|
27
|
+
EM.add_timer(1) { raise 'die' }
|
28
|
+
end
|
29
|
+
|
21
30
|
end
|
22
31
|
|
23
32
|
run AsyncTest.new
|
data/lib/sinatra/async.rb
CHANGED
@@ -35,6 +35,7 @@ module Sinatra #:nodoc:
|
|
35
35
|
#
|
36
36
|
# end
|
37
37
|
module Async
|
38
|
+
|
38
39
|
# Similar to Sinatra::Base#get, but the block will be scheduled to run
|
39
40
|
# during the next tick of the EventMachine reactor. In the meantime,
|
40
41
|
# Thin will hold onto the client connection, awaiting a call to
|
@@ -58,43 +59,79 @@ module Sinatra #:nodoc:
|
|
58
59
|
|
59
60
|
private
|
60
61
|
def aroute(verb, path, opts = {}, &block) #:nodoc:
|
62
|
+
method = "A#{verb} #{path}".to_sym
|
63
|
+
define_method method, &block
|
64
|
+
|
61
65
|
route(verb, path, opts) do |*bargs|
|
62
|
-
method
|
66
|
+
async_runner(method, *bargs)
|
67
|
+
async_response
|
68
|
+
end
|
69
|
+
end
|
63
70
|
|
64
|
-
|
65
|
-
|
66
|
-
|
71
|
+
module Helpers
|
72
|
+
# Send the given body or block as the final response to the asynchronous
|
73
|
+
# request.
|
74
|
+
def body(*args)
|
75
|
+
if @async_running
|
76
|
+
block_given? ? async_handle_exception { super yield } : super
|
77
|
+
request.env['async.callback'][
|
78
|
+
[response.status, response.headers, response.body]
|
79
|
+
]
|
80
|
+
else
|
81
|
+
super
|
82
|
+
end
|
83
|
+
end
|
67
84
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
85
|
+
# By default async_schedule calls EventMachine#next_tick, if you're using
|
86
|
+
# threads or some other scheduling mechanism, it must take the block
|
87
|
+
# passed here.
|
88
|
+
def async_schedule(&b)
|
89
|
+
if options.environment == :test
|
90
|
+
options.set :async_schedules, [] unless options.respond_to? :async_schedules
|
91
|
+
options.async_schedules << b
|
92
|
+
else
|
93
|
+
EM.next_tick(&b)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Defaults to throw async as that is most commonly used by servers.
|
98
|
+
def async_response
|
99
|
+
throw :async
|
100
|
+
end
|
101
|
+
|
102
|
+
def async_runner(method, *bargs)
|
103
|
+
async_schedule do
|
104
|
+
@async_running = true
|
105
|
+
async_handle_exception do
|
106
|
+
if h = catch(:halt) { __send__(method, *bargs); nil }
|
107
|
+
invoke { halt h }
|
108
|
+
invoke { error_block! response.status }
|
109
|
+
body(response.body)
|
82
110
|
end
|
83
111
|
end
|
84
|
-
|
112
|
+
end
|
113
|
+
end
|
85
114
|
|
86
|
-
|
115
|
+
def async_handle_exception
|
116
|
+
yield
|
117
|
+
rescue ::Exception => boom
|
118
|
+
if options.show_exceptions?
|
119
|
+
printer = Sinatra::ShowExceptions.new(proc{ raise boom })
|
120
|
+
s, h, b = printer.call(request.env)
|
121
|
+
response.status = s
|
122
|
+
response.headers.replace(h)
|
123
|
+
response.body = b
|
124
|
+
else
|
125
|
+
body(handle_exception!(boom))
|
126
|
+
end
|
87
127
|
end
|
88
|
-
end
|
89
128
|
|
90
|
-
|
91
|
-
#
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
[response.status, response.headers, response.body]
|
97
|
-
] if respond_to?(:__async_callback)
|
129
|
+
# Asynchronous halt must be used when the halt is occuring outside of
|
130
|
+
# the original call stack.
|
131
|
+
def ahalt(*args)
|
132
|
+
invoke { halt(*args) }
|
133
|
+
invoke { error_block! response.status }
|
134
|
+
body response.body
|
98
135
|
end
|
99
136
|
end
|
100
137
|
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'sinatra/async'
|
2
|
+
require 'rack/test'
|
3
|
+
|
4
|
+
class Rack::MockResponse
|
5
|
+
def async?
|
6
|
+
self.status == -1
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Sinatra::Async::Test
|
11
|
+
class AsyncSession < Rack::MockSession
|
12
|
+
def request(uri, env)
|
13
|
+
env['async.callback'] = lambda { |r| s,h,b = *r; handle_last_response(uri, env, s,h,b) }
|
14
|
+
env['async.close'] = lambda { raise 'close connection' } # XXX deal with this
|
15
|
+
catch(:async) { super }
|
16
|
+
@last_response ||= Rack::MockResponse.new(-1, {}, [], env["rack.errors"].flush)
|
17
|
+
end
|
18
|
+
|
19
|
+
def handle_last_response(uri, env, status, headers, body)
|
20
|
+
@last_response = Rack::MockResponse.new(status, headers, body, env["rack.errors"].flush)
|
21
|
+
body.close if body.respond_to?(:close)
|
22
|
+
|
23
|
+
cookie_jar.merge(last_response.headers["Set-Cookie"], uri)
|
24
|
+
|
25
|
+
@after_request.each { |hook| hook.call }
|
26
|
+
@last_response
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module Methods
|
31
|
+
include Rack::Test::Methods
|
32
|
+
|
33
|
+
%w(get put post delete head).each do |m|
|
34
|
+
eval <<-RUBY, binding, __FILE__, __LINE__ + 1
|
35
|
+
def a#{m}(*args)
|
36
|
+
#{m}(*args)
|
37
|
+
assert_async
|
38
|
+
async_continue
|
39
|
+
end
|
40
|
+
RUBY
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_rack_mock_session # XXX move me
|
44
|
+
Sinatra::Async::Test::AsyncSession.new(app)
|
45
|
+
end
|
46
|
+
|
47
|
+
def assert_async
|
48
|
+
assert last_response.async?
|
49
|
+
end
|
50
|
+
|
51
|
+
def async_continue
|
52
|
+
while b = app.options.async_schedules.shift
|
53
|
+
b.call
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def em_async_continue(timeout = 10)
|
58
|
+
timed = false
|
59
|
+
EM.run do
|
60
|
+
async_continue
|
61
|
+
EM.tick_loop { EM.stop unless last_response.async? }
|
62
|
+
EM.add_timer(timeout) { timed = true; EM.stop }
|
63
|
+
end
|
64
|
+
assert !timed, "asynchronous timeout after #{timeout} seconds"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require "sinatra/async/test"
|
3
|
+
|
4
|
+
require 'spec/autorun'
|
5
|
+
require 'spec/interop/test'
|
6
|
+
|
7
|
+
require 'em-http'
|
8
|
+
|
9
|
+
Spec::Runner.configure { |c| }
|
10
|
+
|
11
|
+
def server(base=Sinatra::Base, &block)
|
12
|
+
s = Sinatra.new(base, &block).new
|
13
|
+
s.options.set :environment, :test
|
14
|
+
s
|
15
|
+
end
|
16
|
+
|
17
|
+
def app
|
18
|
+
@app
|
19
|
+
end
|
20
|
+
|
21
|
+
include Sinatra::Async::Test::Methods
|
22
|
+
|
23
|
+
describe "Asynchronous routes" do
|
24
|
+
it "should still work as usual" do
|
25
|
+
@app = server do
|
26
|
+
register Sinatra::Async
|
27
|
+
disable :raise_errors, :show_exceptions
|
28
|
+
|
29
|
+
aget '/' do
|
30
|
+
body "hello async"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
aget '/'
|
34
|
+
last_response.status.should_equal 200
|
35
|
+
last_response.body.should == "hello async"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should correctly deal with raised exceptions" do
|
39
|
+
@app = server do
|
40
|
+
register Sinatra::Async
|
41
|
+
disable :raise_errors, :show_exceptions
|
42
|
+
aget '/' do
|
43
|
+
raise "boom"
|
44
|
+
body "hello async"
|
45
|
+
end
|
46
|
+
error Exception do
|
47
|
+
e = request.env['sinatra.error']
|
48
|
+
"problem: #{e.class.name} #{e.message}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
aget '/'
|
52
|
+
last_response.status.should == 500
|
53
|
+
last_response.body.should == "problem: RuntimeError boom"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should correctly deal with halts" do
|
57
|
+
@app = server do
|
58
|
+
register Sinatra::Async
|
59
|
+
disable :raise_errors, :show_exceptions
|
60
|
+
aget '/' do
|
61
|
+
halt 406, "Format not supported"
|
62
|
+
body "never called"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
aget '/'
|
67
|
+
last_response.status.should == 406
|
68
|
+
last_response.body.should == "Format not supported"
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should correctly deal with halts and pass it to the defined error blocks if any" do
|
72
|
+
@app = server do
|
73
|
+
register Sinatra::Async
|
74
|
+
disable :raise_errors, :show_exceptions
|
75
|
+
aget '/' do
|
76
|
+
halt 406, "Format not supported"
|
77
|
+
body "never called"
|
78
|
+
end
|
79
|
+
error 406 do
|
80
|
+
response['Content-Type'] = "text/plain"
|
81
|
+
"problem: #{response.body.to_s}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
aget '/'
|
85
|
+
last_response.status.should == 406
|
86
|
+
last_response.headers['Content-Type'].should == "text/plain"
|
87
|
+
last_response.body.should == "problem: Format not supported"
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "using EM libraries inside route block" do
|
91
|
+
it "should still work as usual" do
|
92
|
+
@app = server do
|
93
|
+
register Sinatra::Async
|
94
|
+
disable :raise_errors, :show_exceptions
|
95
|
+
aget '/' do
|
96
|
+
url = "http://ruby.activeventure.com/programmingruby/book/tut_exceptions.html"
|
97
|
+
http = EM::HttpRequest.new(url).get
|
98
|
+
http.callback {
|
99
|
+
status http.response_header.status
|
100
|
+
body "ok"
|
101
|
+
}
|
102
|
+
http.errback {
|
103
|
+
body "nok"
|
104
|
+
}
|
105
|
+
end
|
106
|
+
end
|
107
|
+
EM.run { EM.add_timer(1) { EM.stop }; aget '/' }
|
108
|
+
last_response.status.should == 200
|
109
|
+
last_response.body.should == "ok"
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should correctly deal with exceptions raised from within EM callbacks" do
|
113
|
+
@app = server do
|
114
|
+
register Sinatra::Async
|
115
|
+
disable :raise_errors, :show_exceptions
|
116
|
+
aget '/' do
|
117
|
+
url = "http://doesnotexist.local/whatever"
|
118
|
+
http = EM::HttpRequest.new(url).get
|
119
|
+
http.callback {
|
120
|
+
status http.response_header.status
|
121
|
+
body "ok"
|
122
|
+
}
|
123
|
+
http.errback {
|
124
|
+
raise "boom"
|
125
|
+
}
|
126
|
+
end
|
127
|
+
error Exception do
|
128
|
+
e = request.env['sinatra.error']
|
129
|
+
"#{e.class.name}: #{e.message}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
EM.run { EM.add_timer(1) { EM.stop }; aget '/' }
|
133
|
+
last_response.status.should == 500
|
134
|
+
last_response.body.should == "RuntimeError: boom"
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should correctly deal with halts thrown from within EM callbacks" do
|
138
|
+
@app = server do
|
139
|
+
register Sinatra::Async
|
140
|
+
disable :raise_errors, :show_exceptions
|
141
|
+
aget '/' do
|
142
|
+
url = "http://doesnotexist.local/whatever"
|
143
|
+
http = EM::HttpRequest.new(url).get
|
144
|
+
http.callback {
|
145
|
+
status http.response_header.status
|
146
|
+
body "ok"
|
147
|
+
}
|
148
|
+
http.errback {
|
149
|
+
halt 503, "error: #{http.errors.inspect}"
|
150
|
+
}
|
151
|
+
end
|
152
|
+
error 503 do
|
153
|
+
"503: #{response.body.to_s}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
EM.run { EM.add_timer(1) { EM.stop }; aget '/' }
|
157
|
+
last_response.status.should == 503
|
158
|
+
last_response.body.should == "503: error: \"unable to resolve server address\""
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
data/test/test_async.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
gem 'test-unit'
|
2
|
+
require "test/unit"
|
3
|
+
|
4
|
+
require 'eventmachine'
|
5
|
+
|
6
|
+
require "sinatra/async/test"
|
7
|
+
|
8
|
+
class TestSinatraAsync < Test::Unit::TestCase
|
9
|
+
include Sinatra::Async::Test::Methods
|
10
|
+
|
11
|
+
class TestApp < Sinatra::Base
|
12
|
+
set :environment, :test
|
13
|
+
register Sinatra::Async
|
14
|
+
|
15
|
+
error 401 do
|
16
|
+
'401'
|
17
|
+
end
|
18
|
+
|
19
|
+
aget '/hello' do
|
20
|
+
body { 'hello async' }
|
21
|
+
end
|
22
|
+
|
23
|
+
aget '/em' do
|
24
|
+
EM.add_timer(0.001) { body { 'em' }; EM.stop }
|
25
|
+
end
|
26
|
+
|
27
|
+
aget '/em_timeout' do
|
28
|
+
# never send a response
|
29
|
+
end
|
30
|
+
|
31
|
+
aget '/404' do
|
32
|
+
not_found
|
33
|
+
end
|
34
|
+
|
35
|
+
aget '/302' do
|
36
|
+
ahalt 302
|
37
|
+
end
|
38
|
+
|
39
|
+
aget '/em_halt' do
|
40
|
+
EM.next_tick { ahalt 404 }
|
41
|
+
end
|
42
|
+
|
43
|
+
aget '/s401' do
|
44
|
+
halt 401
|
45
|
+
end
|
46
|
+
|
47
|
+
aget '/a401' do
|
48
|
+
ahalt 401
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def app
|
53
|
+
TestApp.new
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_basic_async_get
|
57
|
+
get '/hello'
|
58
|
+
assert_async
|
59
|
+
async_continue
|
60
|
+
assert last_response.ok?
|
61
|
+
assert_equal 'hello async', last_response.body
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_em_get
|
65
|
+
get '/em'
|
66
|
+
assert_async
|
67
|
+
em_async_continue
|
68
|
+
assert last_response.ok?
|
69
|
+
assert_equal 'em', last_response.body
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_em_async_continue_timeout
|
73
|
+
get '/em_timeout'
|
74
|
+
assert_async
|
75
|
+
assert_raises(Test::Unit::AssertionFailedError) do
|
76
|
+
em_async_continue(0.001)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_404
|
81
|
+
get '/404'
|
82
|
+
assert_async
|
83
|
+
async_continue
|
84
|
+
assert_equal 404, last_response.status
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_302
|
88
|
+
get '/302'
|
89
|
+
assert_async
|
90
|
+
async_continue
|
91
|
+
assert_equal 302, last_response.status
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_em_halt
|
95
|
+
get '/em_halt'
|
96
|
+
assert_async
|
97
|
+
em_async_continue
|
98
|
+
assert_equal 404, last_response.status
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_error_blocks_sync
|
102
|
+
get '/s401'
|
103
|
+
assert_async
|
104
|
+
async_continue
|
105
|
+
assert_equal 401, last_response.status
|
106
|
+
assert_equal '401', last_response.body
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_error_blocks_async
|
110
|
+
get '/a401'
|
111
|
+
assert_async
|
112
|
+
async_continue
|
113
|
+
assert_equal 401, last_response.status
|
114
|
+
assert_equal '401', last_response.body
|
115
|
+
end
|
116
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async_sinatra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- James Tucker
|
@@ -9,50 +15,58 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date: 2009-03-24 00:00:00
|
18
|
+
date: 2009-03-24 00:00:00 -03:00
|
13
19
|
default_executable:
|
14
20
|
dependencies:
|
15
21
|
- !ruby/object:Gem::Dependency
|
16
22
|
name: sinatra
|
17
|
-
|
18
|
-
|
19
|
-
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
20
26
|
requirements:
|
21
27
|
- - ">="
|
22
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 57
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 9
|
33
|
+
- 1
|
23
34
|
version: 0.9.1
|
24
|
-
version:
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
|
-
name: thin
|
27
35
|
type: :runtime
|
28
|
-
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 1.2.0
|
34
|
-
version:
|
36
|
+
version_requirements: *id001
|
35
37
|
- !ruby/object:Gem::Dependency
|
36
38
|
name: rdoc
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
40
42
|
requirements:
|
41
43
|
- - ">="
|
42
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 29
|
46
|
+
segments:
|
47
|
+
- 2
|
48
|
+
- 4
|
49
|
+
- 1
|
43
50
|
version: 2.4.1
|
44
|
-
|
51
|
+
type: :development
|
52
|
+
version_requirements: *id002
|
45
53
|
- !ruby/object:Gem::Dependency
|
46
54
|
name: rake
|
47
|
-
|
48
|
-
|
49
|
-
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
50
58
|
requirements:
|
51
59
|
- - ">="
|
52
60
|
- !ruby/object:Gem::Version
|
61
|
+
hash: 57
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
- 8
|
65
|
+
- 3
|
53
66
|
version: 0.8.3
|
54
|
-
|
55
|
-
|
67
|
+
type: :development
|
68
|
+
version_requirements: *id003
|
69
|
+
description: Asynchronous response API for Sinatra
|
56
70
|
email: raggi@rubyforge.org
|
57
71
|
executables: []
|
58
72
|
|
@@ -65,6 +79,9 @@ files:
|
|
65
79
|
- Rakefile
|
66
80
|
- examples/basic.ru
|
67
81
|
- lib/sinatra/async.rb
|
82
|
+
- lib/sinatra/async/test.rb
|
83
|
+
- test/borked_test_crohr.rb
|
84
|
+
- test/test_async.rb
|
68
85
|
has_rdoc: true
|
69
86
|
homepage: http://libraggi.rubyforge.org/async_sinatra
|
70
87
|
licenses: []
|
@@ -80,23 +97,29 @@ rdoc_options:
|
|
80
97
|
require_paths:
|
81
98
|
- lib
|
82
99
|
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
83
101
|
requirements:
|
84
102
|
- - ">="
|
85
103
|
- !ruby/object:Gem::Version
|
104
|
+
hash: 3
|
105
|
+
segments:
|
106
|
+
- 0
|
86
107
|
version: "0"
|
87
|
-
version:
|
88
108
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
89
110
|
requirements:
|
90
111
|
- - ">="
|
91
112
|
- !ruby/object:Gem::Version
|
113
|
+
hash: 3
|
114
|
+
segments:
|
115
|
+
- 0
|
92
116
|
version: "0"
|
93
|
-
version:
|
94
117
|
requirements: []
|
95
118
|
|
96
119
|
rubyforge_project: libraggi
|
97
|
-
rubygems_version: 1.3.
|
120
|
+
rubygems_version: 1.3.7
|
98
121
|
signing_key:
|
99
122
|
specification_version: 2
|
100
|
-
summary: Asynchronous response API for Sinatra
|
101
|
-
test_files:
|
102
|
-
|
123
|
+
summary: Asynchronous response API for Sinatra
|
124
|
+
test_files:
|
125
|
+
- test/test_async.rb
|