async-rack 0.4.0.c → 0.4.0.d

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # AsyncRack
2
2
 
3
+ ## Note upfront
4
+ Still experimental. Feel free to play around.
5
+
6
+ ## Introduction
3
7
  So, have you been amazed by thin's `async.callback`? If not, [go](http://macournoyer.com/blog/2009/06/04/pusher-and-async-with-thin/) [check](http://github.com/raggi/async_sinatra) [it](http://github.com/raggi/thin/blob/async_for_rack/example/async_app.ru) [out](http://m.onkey.org/2010/1/7/introducing-cramp). Come back here when you start missing your middleware.
4
8
 
5
9
  So what is the issue with Rack and `async.callback`? Currently there are two ways of triggering a async responds. The first is to `throw :async`, the latter to return a status code of -1 (even though thin and ebb do disagree on that). Opposed to what others say, I would recommend using `throw`, as it simply skips middleware not able to handle `:async`. Also, it works on all servers supporting `async.callback` – thin, ebb, rainbows! and zbatery – about the same and copes better with middleware that is unable to handle an async respond.
@@ -30,6 +34,45 @@ How does that work? Simple, whenever necessary, `async-rack` will replace `async
30
34
 
31
35
  Note: This library only 'fixes' the middleware that ships with rack, not other rack middleware. However, you can use the included helper classes to easily make other libraries handle `async.callback`.
32
36
 
37
+ ## What's in this package?
38
+
39
+ ### Rack middleware made async-proof
40
+ This middleware now works well with `throw :async`:
41
+
42
+ * Rack::Chunked
43
+ * Rack::CommonLogger
44
+ * Rack::ConditionalGet
45
+ * Rack::ContentLength
46
+ * Rack::ContentType
47
+ * Rack::Deflater
48
+ * Rack::ETag
49
+ * Rack::Head
50
+ * Rack::Logger
51
+ * Rack::Runtime
52
+ * Rack::Sendfile
53
+ * Rack::ShowStatus
54
+
55
+ ### Middleware that is async-proof out of the box
56
+ No changes where necessary for:
57
+
58
+ * Rack::Cascade
59
+ * Rack::Config
60
+ * Rack::Directory
61
+ * Rack::File
62
+ * Rack::MethodOverride
63
+ * Rack::Mime
64
+ * Rack::NullLogger
65
+ * Rack::Recursive
66
+ * Rack::Reloader
67
+ * Rack::Static
68
+ * Rack::URLMap
69
+
70
+ ### Middleware not (yet) made async-proof
71
+
72
+ * Rack::Lint (might not check async responses)
73
+ * Rack::ShowExceptions (might not show exceptions for async responses)
74
+ * Rack::Lock (might raise an exception)
75
+
33
76
  ## How to make a middleware async-proof?
34
77
  There are three types of middleware:
35
78
 
data/lib/async_rack.rb CHANGED
@@ -13,13 +13,19 @@ module AsyncRack
13
13
  module ExtensionMixin
14
14
  ::AsyncRack.extend self
15
15
  def autoload(class_name, path)
16
- super
17
- if Rack.autoload? class_name then Rack.autoload(class_name, path)
18
- elsif Rack.const_defined? class_name then require path
16
+ if Rack.const_defined? class_name
17
+ require path
18
+ else
19
+ Rack.autoload class_name, path
20
+ super
19
21
  end
20
22
  end
21
23
  end
22
24
 
25
+ # New middleware
26
+ autoload :CatchAsync, "async_rack/catch_async"
27
+ autoload :ThrowAsync, "async_rack/throw_async"
28
+
23
29
  # Wrapped rack middleware
24
30
  autoload :Chunked, "async_rack/chunked"
25
31
  autoload :CommonLogger, "async_rack/commonlogger"
@@ -31,7 +37,6 @@ module AsyncRack
31
37
  autoload :Head, "async_rack/head"
32
38
  autoload :Lock, "async_rack/lock"
33
39
  autoload :Logger, "async_rack/logger"
34
- # autoload :Recursive, "async_rack/recursive"
35
40
  autoload :Runtime, "async_rack/runtime"
36
41
  autoload :Sendfile, "async_rack/sendfile"
37
42
  autoload :ShowStatus, "async_rack/showstatus"
@@ -27,6 +27,10 @@ module AsyncRack
27
27
  # Rack::FancyMiddleware # => AsyncRack::FancyMiddleware
28
28
  # AsyncRack::FancyMiddleware.ancestors # => [AsyncRack::AsyncCallback::Mixin, Rack::FancyMiddleware, ...]
29
29
  module AsyncCallback
30
+ def self.included(mod)
31
+ mod.send :include, Mixin
32
+ super
33
+ end
30
34
 
31
35
  ##
32
36
  # Aliases a subclass on subclassing, but only once.
@@ -82,9 +86,9 @@ module AsyncRack
82
86
  private
83
87
  def setup_late_initialize(klass)
84
88
  class << klass
85
- alias create new
86
89
  def new(*args, &block)
87
- proc { |env| create(*args, &block).call(env) }
90
+ return super if File.expand_path(caller.first[/^[^:]+/]) == File.expand_path(__FILE__)
91
+ proc { |env| new(*args, &block).call(env) }
88
92
  end
89
93
  end
90
94
  end
@@ -92,6 +96,7 @@ module AsyncRack
92
96
 
93
97
  module Mixin
94
98
  extend LateInitializer
99
+ attr_accessor :env
95
100
 
96
101
  def async_callback(result)
97
102
  @async_callback.call result
@@ -0,0 +1,16 @@
1
+ require 'rack'
2
+ module AsyncRack
3
+ class CatchAsync
4
+ Rack::CatchAsync = self unless defined? Rack::CatchAsync
5
+
6
+ def initialize(app, async_response = [-1, {}, []])
7
+ @app, @async_response = app, async_response
8
+ end
9
+
10
+ def call(env)
11
+ response = @async_response
12
+ catch(:async) { response = @app.call env }
13
+ response
14
+ end
15
+ end
16
+ end
@@ -4,7 +4,7 @@ module AsyncRack
4
4
  module Session
5
5
  class Cookie < AsyncCallback(:Cookie, Rack::Session)
6
6
  def async_callback(result)
7
- super commit_session(@env, *result)
7
+ super commit_session(env, *result)
8
8
  end
9
9
  end
10
10
  end
@@ -4,7 +4,7 @@ module AsyncRack
4
4
  module Session
5
5
  class Memcache < AsyncCallback(:Memcache, Rack::Session)
6
6
  def async_callback(result)
7
- super commit_session(@env, *result)
7
+ super commit_session(env, *result)
8
8
  end
9
9
  end
10
10
  end
@@ -4,7 +4,7 @@ module AsyncRack
4
4
  module Session
5
5
  class Pool < AsyncCallback(:Pool, Rack::Session)
6
6
  def async_callback(result)
7
- super commit_session(@env, *result)
7
+ super commit_session(env, *result)
8
8
  end
9
9
  end
10
10
  end
@@ -0,0 +1,17 @@
1
+ require 'rack'
2
+
3
+ module AsyncRack
4
+ class ThrowAsync
5
+ Rack::ThrowAsync = self unless defined? Rack::ThrowAsync
6
+
7
+ def initialize(app, throw_on = [-1, 0])
8
+ @app, @throw_on = app, throw_on
9
+ end
10
+
11
+ def call(env)
12
+ response = @app.call env
13
+ throw :async if @throw_on.include? response.first
14
+ response
15
+ end
16
+ end
17
+ end
@@ -28,7 +28,6 @@ describe AsyncRack::AsyncCallback do
28
28
  before do
29
29
  @class = Class.new do
30
30
  include AsyncRack::AsyncCallback::SimpleWrapper
31
- attr_accessor :app, :env
32
31
  class << self
33
32
  attr_accessor :instance
34
33
  end
@@ -44,8 +43,7 @@ describe AsyncRack::AsyncCallback do
44
43
  end
45
44
 
46
45
  it "runs #call again on async callback, replacing app" do
47
- middleware = @class.create
48
- middleware.app = proc { throw :async }
46
+ middleware = @class.create proc { throw :async }
49
47
  catch(:async) do
50
48
  middleware.call "async.callback" => proc { |x| x + 10 }
51
49
  raise "should not get here"
metadata CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
6
6
  - 0
7
7
  - 4
8
8
  - 0
9
- - c
10
- version: 0.4.0.c
9
+ - d
10
+ version: 0.4.0.d
11
11
  platform: ruby
12
12
  authors:
13
13
  - Konstantin Haase
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-03-12 00:00:00 +01:00
18
+ date: 2010-03-14 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -57,6 +57,7 @@ extra_rdoc_files: []
57
57
  files:
58
58
  - lib/async-rack.rb
59
59
  - lib/async_rack/async_callback.rb
60
+ - lib/async_rack/catch_async.rb
60
61
  - lib/async_rack/chunked.rb
61
62
  - lib/async_rack/commonlogger.rb
62
63
  - lib/async_rack/conditionalget.rb
@@ -73,6 +74,7 @@ files:
73
74
  - lib/async_rack/session/memcache.rb
74
75
  - lib/async_rack/session/pool.rb
75
76
  - lib/async_rack/showstatus.rb
77
+ - lib/async_rack/throw_async.rb
76
78
  - lib/async_rack.rb
77
79
  - spec/async_rack/async_callback_spec.rb
78
80
  - spec/spec_helper.rb