async-rack 0.5.0 → 0.5.1

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