           word #(keyword (.group % 1))
           path nil)))))
  
-(defn match-route
+(defn- match-route
   "Match a path against a parsed route. Returns a map of keywords and their
   matching path values."
   [route path]

          (route :keywords)
          (rest (re-groups matcher)))))))
 
;;;; Response ;;;;
 
(defn update-response
  "Destructively update a HttpServletResponse using a Clojure datatype:
    string - Adds to the response body
    seq - Adds all containing elements to the response body

            "Content-Type" (context-mimetype context (str update)))
       (pipe-stream in out))))
 
(defn- apply-http-handler
  "Finds and evaluates the handler that matches the HttpServletRequest. If the
  handler returns :next, the next matching handler is evaluated."
  [handlers context request response]
  (let [method (find-method request)
        path     (.getPathInfo request)
        method= #(or (nil? %) (= method %))
        route?   (fn [handler]
                   (if (method= (handler :method))
                     (match-route (handler :route) path)))
        response? (fn [handler]
                    (if-let route-params (route? handler)
                      (let [func (handler :function)
                            resp (func route-params
                                       context
                                       request)]
                        (if (not= :next resp)
                          (or resp [])))))]
    (update-response response context
      (some response? handlers))))

;;;; Public macros ;;;;

(defmacro GET "Creates a GET handler."
  [route & body]
  `(struct http-handler "GET" (compile-route ~route) (handler-fn ~@body)))
 
(defmacro PUT "Creates a PUT handler."
  [route & body]
  `(struct http-handler "PUT" (compile-route ~route) (handler-fn ~@body)))
 
(defmacro POST "Creates a POST handler."
  [route & body]
  `(struct http-handler "POST" (compile-route ~route) (handler-fn ~@body)))
 
(defmacro DELETE "Creates a DELETE handler."
  [route & body]
  `(struct http-handler "DELETE" (compile-route ~route) (handler-fn ~@body)))
 
(defmacro HEAD "Creates a HEAD handler."
  [route & body]
  `(struct http-handler "HEAD" (compile-route ~route) (handler-fn ~@body)))
 
(defmacro ANY "Creates a handler that responds to any HTTP method."
  [route & body]
  `(struct http-handler nil (compile-route ~route) (handler-fn ~@body)))

;;;; Helper functions ;;;;

(defn redirect-to
  "A shortcut for a '302 Moved' HTTP redirect."
  [location]
  [302 {"Location" location}])
 
(defn page-not-found
  "A shortcut to create a '404 Not Found' HTTP response."
  ([]         (page-not-found "public/404.html"))
  ([filename] [404 (file filename)]))
 
(defn serve-file
  "Attempts to serve up a static file from a directory. Nil is returned if the
  file does not exist."
  ([path]
    (serve-file "public" path))
  ([root path]
    (let [static-file (file root path)]
      (if (.isFile static-file)
        static-file))))
 
;;;; Servlet creation ;;;;
 
(defn servlet
  "Create a servlet from a sequence of handlers."
  [& handlers]
  (proxy [HttpServlet] []
    (service [request response]
      (.setCharacterEncoding response "UTF-8")
      (apply-http-handler handlers
                          (.getServletContext this)
                          request
                          response))))
 
(defmacro defservlet
  "Shortcut for (def name (servlet handlers))"
  [name doc & handlers]
  (if (string? doc)
    `(def
       ~(with-meta name (assoc (meta name) :doc doc))
        (servlet ~@handlers))
    `(def ~name (servlet ~doc ~@handlers))))
