Permalink
Browse files

More docs, quick bugfix, rolling on...

  • Loading branch information...
1 parent 51d7e37 commit 70628940d9df18ba3d7544c673edfdfa58c40e95 @raggi committed Mar 26, 2009
Showing with 82 additions and 43 deletions.
  1. +4 −0 README.rdoc
  2. +3 −1 Rakefile
  3. +75 −42 lib/sinatra/async.rb
View
@@ -14,6 +14,8 @@ asynchronous patterns is recommended.
== SYNOPSIS:
+A quick example:
+
require 'sinatra/async'
class AsyncTest < Sinatra::Base
@@ -29,6 +31,8 @@ asynchronous patterns is recommended.
end
+See Sinatra::Async for more details.
+
== REQUIREMENTS:
* Sinatra (>= 0.9)
View
@@ -36,7 +36,9 @@ df = begin; require 'rdoc/generator/darkfish'; true; rescue LoadError; end
rdtask = Rake::RDocTask.new do |rd|
rd.title = spec.name
rd.main = spec.extra_rdoc_files.first
- rd.rdoc_files.include(*[manifest.grep(/\.rb$|\.rdoc$/), *spec.extra_rdoc_files].uniq)
+ lib_rexp = spec.require_paths.map { |p| Regexp.escape p }.join('|')
+ rd.rdoc_files.include(*manifest.grep(/^(?:#{lib_rexp})/))
+ rd.rdoc_files.include(*spec.extra_rdoc_files)
rd.template = 'darkfish' if df
end
View
@@ -1,53 +1,86 @@
require 'sinatra'
-# Normally Sinatra::Base expects that the completion of a request is
-# determined by the block exiting, and returning a value for the body.
-#
-# In an async environment, we want to tell the webserver that we're not going
-# to provide a response now, but some time in the future.
-#
-# The a* methods provide a method for doing this, by informing the server of
-# our asynchronous intent, and then scheduling our action code (your block)
-# as the next thing to be invoked by the server.
-#
-# This code can then do a number of things, including waiting (asynchronously)
-# for external servers, services, and whatnot to complete. When ready to send
-# the real response, simply setup your environment as you normally would for
-# sinatra (using #content_type, #headers, etc). Finally, you complete your
-# response body by calling the #body method. This will push your body into the
-# response object, and call out to the server to actually send that data.
-module Sinatra::Async
- module ClassMethods
- def aget(path, opts={}, &block)
- conditions = @conditions.dup
- aroute('GET', path, opts, &block)
+module Sinatra #:nodoc:
- @conditions = conditions
- aroute('HEAD', path, opts, &block)
- end
+ # See Async::ClassMethods for the DSL
+ #
+ # Normally Sinatra::Base expects that the completion of a request is
+ # determined by the block exiting, and returning a value for the body.
+ #
+ # In an async environment, we want to tell the webserver that we're not going
+ # to provide a response now, but some time in the future.
+ #
+ # The a* methods provide a method for doing this, by informing the server of
+ # our asynchronous intent, and then scheduling our action code (your block)
+ # as the next thing to be invoked by the server.
+ #
+ # This code can then do a number of things, including waiting (asynchronously)
+ # for external servers, services, and whatnot to complete. When ready to send
+ # the real response, simply setup your environment as you normally would for
+ # sinatra (using #content_type, #headers, etc). Finally, you complete your
+ # response body by calling the #body method. This will push your body into the
+ # response object, and call out to the server to actually send that data.
+ #
+ # == Example
+ # require 'sinatra/async'
+ #
+ # class AsyncTest < Sinatra::Base
+ # include Sinatra::Async
+ #
+ # aget '/' do
+ # body "hello async"
+ # end
+ #
+ # aget '/delay/:n' do |n|
+ # EM.add_timer(n.to_i) { body { "delayed for #{n} seconds" } }
+ # end
+ #
+ # end
+ module Async
+ module ClassMethods
+ # Similar to Sinatra::Base#get, but the block will be scheduled to run
+ # during the next tick of the EventMachine reactor. In the meantime,
+ # Thin will hold onto the client connection, awaiting a call to
+ # Async#body with the response.
+ def aget(path, opts={}, &block)
+ conditions = @conditions.dup
+ aroute('GET', path, opts, &block)
+
+ @conditions = conditions
+ aroute('HEAD', path, opts, &block)
+ end
- def aput(path, opts={}, &bk); aroute 'PUT', path, opts, &bk; end
- def apost(path, opts={}, &bk); aroute 'POST', path, opts, &bk; end
- def adelete(path, opts={}, &bk); aroute 'DELETE', path, opts, &bk; end
- def ahead(path, opts={}, &bk); aroute 'HEAD', path, opts, &bk; end
+ # See #aget.
+ def aput(path, opts={}, &bk); aroute 'PUT', path, opts, &bk; end
+ # See #aget.
+ def apost(path, opts={}, &bk); aroute 'POST', path, opts, &bk; end
+ # See #aget.
+ def adelete(path, opts={}, &bk); aroute 'DELETE', path, opts, &bk; end
+ # See #aget.
+ def ahead(path, opts={}, &bk); aroute 'HEAD', path, opts, &bk; end
- private
- def aroute(*args, &block)
- self.send :route, *args do |*bargs|
- mc = class << self; self; end
- mc.send :define_method, :__async_callback, &block
- EM.next_tick { send(:__async_callback, *bargs) }
- throw :async
+ private
+ def aroute(*args, &block) #:nodoc:
+ self.send :route, *args do |*bargs|
+ mc = class << self; self; end
+ mc.send :define_method, :__async_callback, &block
+ EM.next_tick { send(:__async_callback, *bargs) }
+ throw :async
+ end
end
end
- end
- def self.included(klass)
- klass.extend ClassMethods
- end
+ def self.included(klass) #:nodoc:
+ klass.extend ClassMethods
+ end
- def body(*args, &blk)
- super
- request.env['async.callback'][[response.status, response.headers, response.body]]
+ # Send the given body or block as the final response to the asynchronous
+ # request.
+ def body(*args, &blk)
+ super
+ request.env['async.callback'][
+ [response.status, response.headers, response.body]
+ ] if respond_to?(:__async_callback)
+ end
end
end

0 comments on commit 7062894

Please sign in to comment.