来自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