add pattern matching to before/after filters.
Filter now optionally take a pattern, causing them to be evaluated only if the request path matches that pattern: before("/protected/*") { authenticate! } after("/create/:slug") { |slug| session[:last_slug] = slug } Signed-off-by: Simon Rozet <simon@rozet.name>
This commit is contained in:
parent
d3a401e66c
commit
da047d3d4c
11
README.rdoc
11
README.rdoc
|
@ -331,6 +331,17 @@ set in before filters and routes are accessible by after filters:
|
|||
puts response.status
|
||||
end
|
||||
|
||||
Filters optionally taking a pattern, causing them to be evaluated only if the request
|
||||
path matches that pattern:
|
||||
|
||||
before '/protected/*' do
|
||||
authenticate!
|
||||
end
|
||||
|
||||
after '/create/:slug' do |slug|
|
||||
session[:last_slug] = slug
|
||||
end
|
||||
|
||||
== Halting
|
||||
|
||||
To immediately stop a request within a filter or route use:
|
||||
|
|
|
@ -455,16 +455,10 @@ module Sinatra
|
|||
end
|
||||
|
||||
private
|
||||
# Run before filters defined on the class and all superclasses.
|
||||
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) }
|
||||
# Run filters defined on the class and all superclasses.
|
||||
def filter!(type, base = self.class)
|
||||
filter! type, base.superclass if base.superclass.respond_to?(:filters)
|
||||
base.filters[type].each { |block| instance_eval(&block) }
|
||||
end
|
||||
|
||||
# Run routes defined on the class and all superclasses.
|
||||
|
@ -597,14 +591,14 @@ module Sinatra
|
|||
# Dispatch a request with error handling.
|
||||
def dispatch!
|
||||
static! if settings.static? && (request.get? || request.head?)
|
||||
before_filter!
|
||||
filter! :before
|
||||
route!
|
||||
rescue NotFound => boom
|
||||
handle_not_found!(boom)
|
||||
rescue ::Exception => boom
|
||||
handle_exception!(boom)
|
||||
ensure
|
||||
after_filter! unless env['sinatra.static_file']
|
||||
filter! :after unless env['sinatra.static_file']
|
||||
end
|
||||
|
||||
def handle_not_found!(boom)
|
||||
|
@ -654,13 +648,12 @@ module Sinatra
|
|||
end
|
||||
|
||||
class << self
|
||||
attr_reader :routes, :before_filters, :after_filters, :templates, :errors
|
||||
attr_reader :routes, :filters, :templates, :errors
|
||||
|
||||
def reset!
|
||||
@conditions = []
|
||||
@routes = {}
|
||||
@before_filters = []
|
||||
@after_filters = []
|
||||
@filters = {:before => [], :after => []}
|
||||
@errors = {}
|
||||
@middleware = []
|
||||
@prototype = nil
|
||||
|
@ -673,6 +666,14 @@ module Sinatra
|
|||
end
|
||||
end
|
||||
|
||||
def before_filters
|
||||
@filters[:before]
|
||||
end
|
||||
|
||||
def after_filters
|
||||
@filters[:after]
|
||||
end
|
||||
|
||||
# Extension modules registered on this class and all superclasses.
|
||||
def extensions
|
||||
if superclass.respond_to?(:extensions)
|
||||
|
@ -781,15 +782,25 @@ module Sinatra
|
|||
# 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)
|
||||
@before_filters << block
|
||||
def before(path = nil, &block)
|
||||
add_filter(:before, path, &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
|
||||
def after(path = nil, &block)
|
||||
add_filter(:after, path, &block)
|
||||
end
|
||||
|
||||
# add a filter
|
||||
def add_filter(type, path = nil, &block)
|
||||
return filters[type] << block unless path
|
||||
unbound_method, pattern = compile!(type, path, &block)
|
||||
add_filter(type) do
|
||||
next unless match = pattern.match(request.path_info)
|
||||
unbound_method.bind(self).call(*match.captures.to_a)
|
||||
end
|
||||
end
|
||||
|
||||
# Add a route condition. The route is considered non-matching when the
|
||||
|
@ -853,11 +864,9 @@ module Sinatra
|
|||
|
||||
options.each {|option, args| send(option, *args)}
|
||||
|
||||
pattern, keys = compile(path)
|
||||
unbound_method, pattern, keys = compile!(verb, path, &block)
|
||||
conditions, @conditions = @conditions, []
|
||||
|
||||
define_method "#{verb} #{path}", &block
|
||||
unbound_method = instance_method("#{verb} #{path}")
|
||||
block =
|
||||
if block.arity != 0
|
||||
proc { unbound_method.bind(self).call(*@block_params) }
|
||||
|
@ -875,6 +884,14 @@ module Sinatra
|
|||
extensions.each { |e| e.send(name, *args) if e.respond_to?(name) }
|
||||
end
|
||||
|
||||
def compile!(verb, path, &block)
|
||||
method_name = "#{verb} #{path}"
|
||||
define_method(method_name, &block)
|
||||
unbound_method = instance_method method_name
|
||||
remove_method method_name
|
||||
[unbound_method, *compile(path)]
|
||||
end
|
||||
|
||||
def compile(path)
|
||||
keys = []
|
||||
if path.respond_to? :to_str
|
||||
|
|
|
@ -121,6 +121,29 @@ class BeforeFilterTest < Test::Unit::TestCase
|
|||
assert_equal File.read(__FILE__), body
|
||||
assert !ran_filter
|
||||
end
|
||||
|
||||
it 'takes an optional route pattern' do
|
||||
ran_filter = false
|
||||
mock_app do
|
||||
before("/b*") { ran_filter = true }
|
||||
get('/foo') { }
|
||||
get('/bar') { }
|
||||
end
|
||||
get '/foo'
|
||||
assert !ran_filter
|
||||
get '/bar'
|
||||
assert ran_filter
|
||||
end
|
||||
|
||||
it 'generates block arguments from route pattern' do
|
||||
subpath = nil
|
||||
mock_app do
|
||||
before("/foo/:sub") { |s| subpath = s }
|
||||
get('/foo/*') { }
|
||||
end
|
||||
get '/foo/bar'
|
||||
assert_equal subpath, 'bar'
|
||||
end
|
||||
end
|
||||
|
||||
class AfterFilterTest < Test::Unit::TestCase
|
||||
|
@ -218,4 +241,27 @@ class AfterFilterTest < Test::Unit::TestCase
|
|||
assert_equal File.read(__FILE__), body
|
||||
assert !ran_filter
|
||||
end
|
||||
|
||||
it 'takes an optional route pattern' do
|
||||
ran_filter = false
|
||||
mock_app do
|
||||
after("/b*") { ran_filter = true }
|
||||
get('/foo') { }
|
||||
get('/bar') { }
|
||||
end
|
||||
get '/foo'
|
||||
assert !ran_filter
|
||||
get '/bar'
|
||||
assert ran_filter
|
||||
end
|
||||
|
||||
it 'generates block arguments from route pattern' do
|
||||
subpath = nil
|
||||
mock_app do
|
||||
after("/foo/:sub") { |s| subpath = s }
|
||||
get('/foo/*') { }
|
||||
end
|
||||
get '/foo/bar'
|
||||
assert_equal subpath, 'bar'
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue