async-rack 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,10 +13,17 @@ module AsyncRack
13
13
  module ExtensionMixin
14
14
  ::AsyncRack.extend self
15
15
  def autoload(class_name, path)
16
- if Rack.const_defined? class_name
16
+ mod = Rack
17
+ mod_path = self.name.split("::")
18
+ mod_path.shift
19
+ while (mod_ = mod_path.shift)
20
+ mod = mod.const_get(mod_.to_sym)
21
+ end
22
+ # already loaded ? override.
23
+ if mod.autoload?(class_name) == nil
17
24
  require path
18
25
  else
19
- Rack.autoload class_name, path
26
+ mod.autoload class_name, path
20
27
  super
21
28
  end
22
29
  end
@@ -4,9 +4,9 @@ module AsyncRack
4
4
  class Runtime < AsyncCallback(:Runtime)
5
5
  def async_callback(result)
6
6
  status, headers, body =result
7
- request_time = Time.now - start_time
7
+ request_time = Time.now - @start_time
8
8
  headers[@header_name] = "%0.6f" % request_time if !headers.has_key?(@header_name)
9
- [status, headers, body]
9
+ super [status, headers, body]
10
10
  end
11
11
 
12
12
  def call(env)
@@ -1,8 +1,8 @@
1
- require "rack/cookie"
1
+ require "rack/session/cookie"
2
2
 
3
3
  module AsyncRack
4
4
  module Session
5
- class Cookie < AsyncCallback(:Cookie, Rack::Session)
5
+ class Cookie < AsyncRack::AsyncCallback(:Cookie, Rack::Session)
6
6
  def async_callback(result)
7
7
  super commit_session(env, *result)
8
8
  end
@@ -1,8 +1,8 @@
1
- require "rack/memcache"
1
+ require "rack/session/memcache"
2
2
 
3
3
  module AsyncRack
4
4
  module Session
5
- class Memcache < AsyncCallback(:Memcache, Rack::Session)
5
+ class Memcache < AsyncRack::AsyncCallback(:Memcache, Rack::Session)
6
6
  def async_callback(result)
7
7
  super commit_session(env, *result)
8
8
  end
@@ -1,8 +1,8 @@
1
- require "rack/pool"
1
+ require "rack/session/pool"
2
2
 
3
3
  module AsyncRack
4
4
  module Session
5
- class Pool < AsyncCallback(:Pool, Rack::Session)
5
+ class Pool < AsyncRack::AsyncCallback(:Pool, Rack::Session)
6
6
  def async_callback(result)
7
7
  super commit_session(env, *result)
8
8
  end
@@ -0,0 +1,26 @@
1
+ require 'rack'
2
+
3
+ module Rack
4
+ fail 'Rack version mismatch' if release != '1.2'
5
+ ASYNC_RESPONSE = [-1, {}, []].freeze
6
+
7
+ module Async
8
+ # Tools used to wrap sync middleware
9
+ autoload :AutoloadHook, 'rack/async/autoload_hook'
10
+ autoload :Original, 'rack/async/original'
11
+ autoload :Wrapper, 'rack/async/wrapper'
12
+ end
13
+
14
+ extend Async::AutoloadHook
15
+
16
+ # Wrapped middleware
17
+ autoload :ConditionalGet, 'rack/async/conditional_get'
18
+ autoload :Lint, 'rack/async/lint'
19
+
20
+ # New middleware
21
+ autoload :ReplaceableResponse, 'rack/replaceable_response'
22
+
23
+ module Session
24
+ extend Async::AutoloadHook
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ module Rack
2
+ module Async
3
+ module AutoloadHook
4
+ ##
5
+ # Hooks into Rack.autoload to allow replacing already defined autoload
6
+ # paths with the paths to the async counterparts but avoids accidentally
7
+ # overwriting them with the old paths, for instance if Rack::Reloader is
8
+ # used.
9
+ #
10
+ # If the middleware is already loaded, +require+ the counterpart.
11
+ def autoload(const_name, path)
12
+ if const_defined?(const_name) and not autoload?(const_name)
13
+ require path
14
+ elsif autoload?(const_name) !~ /^rack\/async/
15
+ @autoloaded = false
16
+ super
17
+ end
18
+ end
19
+
20
+ ##
21
+ # Module#autoload is not thread-safe.
22
+ # Use Rack.autoload! to preload all middleware in order to avoid race conditions.
23
+ def autoload!
24
+ return if @autoloaded
25
+ @autoloaded = true
26
+ constants.each do |const_name|
27
+ const = const_get(const_name)
28
+ const.autoload! if const.respond_to? :autoload!
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ require 'rack/conditionalget'
2
+
3
+ module Rack
4
+ module Async
5
+ module ConditionalGet < Original::ConditionalGet
6
+ include Wrapper
7
+ end
8
+ end
9
+
10
+ const_remove :ConditionalGet
11
+ ConditionalGet = Async::ConditionalGet
12
+ end
@@ -0,0 +1,22 @@
1
+ require 'rack/lint'
2
+
3
+ module Rack
4
+ module Async
5
+ class Lint < Original::Lint
6
+ def check_status(status) super unless status.to_i < 0 end
7
+ def check_content_type(status, headers) super unless status.to_i < 0 end
8
+ def check_content_length(status, headers) super unless status.to_i < 0 end
9
+
10
+ def _call(env)
11
+ status, *rest = catch(:async) { super } || ASYNC_RESPONSE
12
+ assert "async response detected without the handler supporting async.callback" do
13
+ status.to_i < 0 and not env.include?('async.callback')
14
+ end
15
+ [status, *rest]
16
+ end
17
+ end
18
+ end
19
+
20
+ const_remove :Lint
21
+ Lint = Async::Lint
22
+ end
@@ -0,0 +1,28 @@
1
+ module Rack
2
+ module Session; end
3
+ module Async
4
+ ##
5
+ # This module is used as a bucket to keep a reference
6
+ # to old middleware in case it was replaced by a new implementation.
7
+ #
8
+ # Rack::Foo might get replaced by Rack::Async::Foo. The old Rack::Foo
9
+ # is still accessable as Rack::Original::Foo, if Rack::Async::Foo is
10
+ # subclassing it (recommended).
11
+ module Original
12
+ module Store
13
+ attr_accessor :base
14
+ def const_missing(name)
15
+ const_set name, base.const_get(name)
16
+ end
17
+ end
18
+
19
+ extend Store
20
+ self.base = ::Rack
21
+
22
+ module Session
23
+ extend Store
24
+ self.base = ::Rack::Session
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,22 @@
1
+ module Rack
2
+ module Async
3
+ module Wrapper
4
+ def initialize(app, *args, &block)
5
+ super(CachedResponse.new(app), *args, &block)
6
+ end
7
+
8
+ def call(env)
9
+ return super unless callback = env['async.callback']
10
+ env['async.callback'] = proc do |result|
11
+ app.set_response_for(env, result)
12
+ async_call(env)
13
+ end
14
+ catch(:async) { super } || ASYNC_RESPONSE
15
+ end
16
+
17
+ def async_call(env)
18
+ call(env)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ module Rack
2
+ ##
3
+ # Middleware that allows setting a predefined response for a request.
4
+ # If response is set, it will be returned instead of handing env on to
5
+ # the next middleware/endpoint. Response is stored in env, so it will be
6
+ # eaten by the GC as soon as possible.
7
+ #
8
+ # @example
9
+ # class Wrapper < Wrapped
10
+ # def call(env)
11
+ # @app.response_for(env, some_response) if some_condition
12
+ # super
13
+ # end
14
+ # end
15
+ #
16
+ # use Wrapper
17
+ # use ReplaceableResponse
18
+ # run SomeApp
19
+ class ReplaceableResponse
20
+ def initialize(app) @app = app end
21
+ def response_for(env, result = nil) (env['cached.responses'] ||= {})[self] = result end
22
+ def call(env) response_for(env) or @app.call(env) end
23
+ alias set_response_for response_for
24
+ end
25
+ end
@@ -0,0 +1,39 @@
1
+ require 'time'
2
+ require 'rack/async'
3
+ require 'rack/mock'
4
+
5
+ describe Rack::ConditionalGet do
6
+ should "set a 304 status and truncate body when If-Modified-Since hits" do
7
+ timestamp = Time.now.httpdate
8
+ app = Rack::ConditionalGet.new(lambda { |env|
9
+ [200, {'Last-Modified'=>timestamp}, ['TEST']] })
10
+
11
+ response = Rack::MockRequest.new(app).
12
+ get("/", 'HTTP_IF_MODIFIED_SINCE' => timestamp)
13
+
14
+ response.status.should.equal 304
15
+ response.body.should.be.empty
16
+ end
17
+
18
+ should "set a 304 status and truncate body when If-None-Match hits" do
19
+ app = Rack::ConditionalGet.new(lambda { |env|
20
+ [200, {'Etag'=>'1234'}, ['TEST']] })
21
+
22
+ response = Rack::MockRequest.new(app).
23
+ get("/", 'HTTP_IF_NONE_MATCH' => '1234')
24
+
25
+ response.status.should.equal 304
26
+ response.body.should.be.empty
27
+ end
28
+
29
+ should "not affect non-GET/HEAD requests" do
30
+ app = Rack::ConditionalGet.new(lambda { |env|
31
+ [200, {'Etag'=>'1234'}, ['TEST']] })
32
+
33
+ response = Rack::MockRequest.new(app).
34
+ post("/", 'HTTP_IF_NONE_MATCH' => '1234')
35
+
36
+ response.status.should.equal 200
37
+ response.body.should.equal 'TEST'
38
+ end
39
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-rack
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 9
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 5
9
- - 0
10
- version: 0.5.0
9
+ - 1
10
+ version: 0.5.1
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-07-09 00:00:00 +02:00
18
+ date: 2011-02-07 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -79,7 +79,15 @@ files:
79
79
  - lib/async_rack/showstatus.rb
80
80
  - lib/async_rack/throw_async.rb
81
81
  - lib/async_rack.rb
82
+ - lib/rack/async/autoload_hook.rb
83
+ - lib/rack/async/conditional_get.rb
84
+ - lib/rack/async/lint.rb
85
+ - lib/rack/async/original.rb
86
+ - lib/rack/async/wrapper.rb
87
+ - lib/rack/async.rb
88
+ - lib/rack/replaceable_response.rb
82
89
  - spec/async_rack/async_callback_spec.rb
90
+ - spec/spec_conditional_get_sync.rb
83
91
  - spec/spec_helper.rb
84
92
  - README.md
85
93
  - LICENSE