summary refs log tree commit
diff options
context:
space:
mode:
authorJeremy Kemper <jeremy@bitsweat.net>2009-05-14 09:28:11 +0800
committerJoshua Peek <josh@joshpeek.com>2009-05-16 00:29:56 +0800
commit0ab6b6c96dc43bec8a02d72ad5c6b944ad30df91 (patch)
treeeb5691d2d9d3aa410f88af3519ae7d14e32ab145
parent01c17705195577c2df955a606ccd9f4f4026756d (diff)
downloadrack-0ab6b6c96dc43bec8a02d72ad5c6b944ad30df91.tar.gz
Allow empty cascades. Reduce #call object allocation overhead. Speed up #include?
Signed-off-by: Joshua Peek <josh@joshpeek.com>
-rw-r--r--lib/rack/cascade.rb29
-rw-r--r--test/spec_rack_cascade.rb8
2 files changed, 20 insertions, 17 deletions
diff --git a/lib/rack/cascade.rb b/lib/rack/cascade.rb
index a038aa11..14c3e54d 100644
--- a/lib/rack/cascade.rb
+++ b/lib/rack/cascade.rb
@@ -4,31 +4,36 @@ module Rack
   # status codes).
 
   class Cascade
+    NotFound = [404, {}, []]
+
     attr_reader :apps
 
     def initialize(apps, catch=404)
-      @apps = apps
-      @catch = [*catch]
+      @apps = []; @has_app = {}
+      apps.each { |app| add app }
+
+      @catch = {}
+      [*catch].each { |status| @catch[status] = true }
     end
 
     def call(env)
-      status = headers = body = nil
-      raise ArgumentError, "empty cascade"  if @apps.empty?
-      @apps.each { |app|
-        begin
-          status, headers, body = app.call(env)
-          break  unless @catch.include?(status.to_i)
-        end
-      }
-      [status, headers, body]
+      result = NotFound
+
+      @apps.each do |app|
+        result = app.call(env)
+        break unless @catch.include?(result[0].to_i)
+      end
+
+      result
     end
 
     def add app
+      @has_app[app] = true
       @apps << app
     end
 
     def include? app
-      @apps.include? app
+      @has_app.include? app
     end
 
     alias_method :<<, :add
diff --git a/test/spec_rack_cascade.rb b/test/spec_rack_cascade.rb
index 3c0f3be3..cf3c29b4 100644
--- a/test/spec_rack_cascade.rb
+++ b/test/spec_rack_cascade.rb
@@ -28,15 +28,13 @@ context "Rack::Cascade" do
     Rack::MockRequest.new(cascade).get("/cgi/../bla").should.be.not_found
   end
 
-  specify "should fail if empty" do
-    lambda { Rack::MockRequest.new(Rack::Cascade.new([])).get("/") }.
-      should.raise(ArgumentError)
+  specify "should return 404 if empty" do
+    Rack::MockRequest.new(Rack::Cascade.new([])).get('/').should.be.not_found
   end
 
   specify "should append new app" do
     cascade = Rack::Cascade.new([], [404, 403])
-    lambda { Rack::MockRequest.new(cascade).get('/cgi/test') }.
-      should.raise(ArgumentError)
+    Rack::MockRequest.new(cascade).get('/').should.be.not_found
     cascade << app2
     Rack::MockRequest.new(cascade).get('/cgi/test').should.be.not_found
     Rack::MockRequest.new(cascade).get('/cgi/../bla').should.be.not_found