Adds after filters

Originally by jschementi (http://bit.ly/1RTt2H)
Updated for Sinatra 1.0 by rtomayko
This commit is contained in:
Jimmy Schementi 2008-12-21 18:36:14 -08:00 committed by Ryan Tomayko
parent f3755308b9
commit 4e50ddbc79
3 changed files with 131 additions and 23 deletions

View File

@ -297,9 +297,17 @@ filters are accessible by routes and templates:
params[:splat] #=> 'bar/baz'
end
After filter are evaluated after each request within the context of the
require and can also modify the request and response. Instance variables
set in before filters and routes are accessible by after filters:
after do
puts response.status
end
== Halting
To immediately stop a request during a before filter or route use:
To immediately stop a request within a filter or route use:
halt

View File

@ -65,7 +65,7 @@ module Sinatra
def code ; 404 ; end
end
# Methods available to routes, before filters, and views.
# Methods available to routes, before/after filters, and views.
module Helpers
# Set or retrieve the response status code.
def status(value=nil)
@ -432,9 +432,15 @@ module Sinatra
private
# Run before filters defined on the class and all superclasses.
def filter!(base=self.class)
filter!(base.superclass) if base.superclass.respond_to?(:filters)
base.filters.each { |block| instance_eval(&block) }
def before_filter!(base=self.class)
before_filter!(base.superclass) if base.superclass.respond_to?(:before_filters)
base.before_filters.each { |block| instance_eval(&block) }
end
# Run after filters defined on the class and all superclasses.
def after_filter!(base=self.class)
after_filter!(base.superclass) if base.superclass.respond_to?(:after_filters)
base.after_filters.each { |block| instance_eval(&block) }
end
# Run routes defined on the class and all superclasses.
@ -564,12 +570,14 @@ module Sinatra
# Dispatch a request with error handling.
def dispatch!
static! if settings.static? && (request.get? || request.head?)
filter!
before_filter!
route!
rescue NotFound => boom
handle_not_found!(boom)
rescue ::Exception => boom
handle_exception!(boom)
ensure
after_filter!
end
def handle_not_found!(boom)
@ -623,16 +631,17 @@ module Sinatra
end
class << self
attr_reader :routes, :filters, :templates, :errors
attr_reader :routes, :before_filters, :after_filters, :templates, :errors
def reset!
@conditions = []
@routes = {}
@filters = []
@errors = {}
@middleware = []
@prototype = nil
@extensions = []
@conditions = []
@routes = {}
@before_filters = []
@after_filters = []
@errors = {}
@middleware = []
@prototype = nil
@extensions = []
if superclass.respond_to?(:templates)
@templates = Hash.new { |hash,key| superclass.templates[key] }
@ -748,11 +757,18 @@ module Sinatra
Rack::Mime::MIME_TYPES[type] = value
end
# Define a before filter. Filters are run before all requests
# within the same context as route handlers and may access/modify the
# request and response.
# Define a before filter; runs before all requests within the same
# context as route handlers and may access/modify the request and
# response.
def before(&block)
@filters << block
@before_filters << block
end
# Define an after filter; runs after all requests within the same
# context as route handlers and may access/modify the request and
# response.
def after(&block)
@after_filters << block
end
# Add a route condition. The route is considered non-matching when the
@ -1098,8 +1114,8 @@ module Sinatra
end
end
delegate :get, :put, :post, :delete, :head, :template, :layout, :before,
:error, :not_found, :configure, :set, :mime_type,
delegate :get, :put, :post, :delete, :head, :template, :layout,
:before, :after, :error, :not_found, :configure, :set, :mime_type,
:enable, :disable, :use, :development?, :test?,
:production?, :use_in_file_templates!, :helpers
end

View File

@ -1,6 +1,6 @@
require File.dirname(__FILE__) + '/helper'
class FilterTest < Test::Unit::TestCase
class BeforeFilterTest < Test::Unit::TestCase
it "executes filters in the order defined" do
count = 0
mock_app do
@ -21,7 +21,7 @@ class FilterTest < Test::Unit::TestCase
assert_equal 'Hello World', body
end
it "allows filters to modify the request" do
it "can modify the request" do
mock_app {
get('/foo') { 'foo' }
get('/bar') { 'bar' }
@ -44,7 +44,7 @@ class FilterTest < Test::Unit::TestCase
assert_equal 'bar', body
end
it "allows redirects in filters" do
it "allows redirects" do
mock_app {
before { redirect '/bar' }
get('/foo') do
@ -109,3 +109,87 @@ class FilterTest < Test::Unit::TestCase
assert_equal 'hello from superclass', body
end
end
class AfterFilterTest < Test::Unit::TestCase
it "executes filters in the order defined" do
invoked = 0
mock_app do
before { invoked = 2 }
get('/') { invoked += 2 }
after { invoked *= 2 }
end
get '/'
assert ok?
assert_equal 8, invoked
end
it "executes filters in the order defined" do
count = 0
mock_app do
get('/') { 'Hello World' }
after {
assert_equal 0, count
count = 1
}
after {
assert_equal 1, count
count = 2
}
end
get '/'
assert ok?
assert_equal 2, count
assert_equal 'Hello World', body
end
it "allows redirects" do
mock_app {
get('/foo') { 'ORLY' }
after { redirect '/bar' }
}
get '/foo'
assert redirect?
assert_equal '/bar', response['Location']
assert_equal '', body
end
it "does not modify the response with its return value" do
mock_app {
get('/foo') { 'cool' }
after { 'Hello World!' }
}
get '/foo'
assert ok?
assert_equal 'cool', body
end
it "does modify the response with halt" do
mock_app {
get '/foo' do
"should not be returned"
end
after { halt 302, 'Hi' }
}
get '/foo'
assert_equal 302, response.status
assert_equal 'Hi', body
end
it "runs filters defined in superclasses" do
count = 2
base = Class.new(Sinatra::Base)
base.after { count *= 2 }
mock_app(base) {
get('/foo') { count += 2 }
}
get '/foo'
assert_equal 8, count
end
end