sinatra的filter
来自1.4.7
before和after做的都是将callback保存起来(在filters中)
def before(path = nil, options = {}, &block)
add_filter(:before, path, options, &block)
end
def after(path = nil, options = {}, &block)
add_filter(:after, path, options, &block)
end
def add_filter(type, path = nil, options = {}, &block)
path, options = //, path if path.respond_to?(:each_pair)
filters[type] << compile!(type, path || //, block, options)
end
保存时所做的compile!其实也就是get、post……所用的那个compile!
之后由dispatch!调用这些callback
def dispatch!
invoke do
static! if settings.static? && (request.get? || request.head?)
filter! :before
route!
end
rescue ::Exception => boom
invoke { handle_exception!(boom) }
ensure
begin
filter! :after unless env['sinatra.static_file']
rescue ::Exception => boom
invoke { handle_exception!(boom) } unless @env['sinatra.error']
end
end
与route!不同的是,filter!调process_route是直接传callback的,而route!是另外给block,并在block中用route_eval来调callback。这样就只有route!会halt,而不会让filter! :before直接跳回invoke。当然halt后其实还是会ensure filter! :after的
def filter!(type, base = settings)
filter! type, base.superclass if base.superclass.respond_to?(:filters)
base.filters[type].each { |args| process_route(*args) }
end
# Run routes defined on the class and all superclasses.
def route!(base = settings, pass_block = nil)
if routes = base.routes[@request.request_method]
routes.each do |pattern, keys, conditions, block|
returned_pass_block = process_route(pattern, keys, conditions) do |*args|
env['sinatra.route'] = block.instance_variable_get(:@route_name)
route_eval { block[*args] }
end
# don't wipe out pass_block in superclass
pass_block = returned_pass_block if returned_pass_block
end
end
# Run routes defined in superclass.
if base.superclass.respond_to?(:routes)
return route!(base.superclass, pass_block)
end
route_eval(&pass_block) if pass_block
route_missing
end