async-rack 0.4.0.c → 0.4.0.d

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.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