       (list match)
       match)))
 
-(defn- placeholder
-  [s]
-  (when-let [p (second (re-find PLACEHOLDER s))]
-    (keyword p)))
+(defrecord Route [method pattern segments names target]
+  Dispatchable
+  (dispatch [this state dn method path hdrs body]
+    (if-let [pattern (.pattern this)]
+      (when (or (nil? (.method this)) (= method (.method this)))
+        (when-let [[matched & vals] (re-match pattern path)]
+          (let [path (subs path (count matched))
+                hdrs (assoc hdrs
+                       :params      (zipmap (.names this) vals)
+                       :path-info   path
+                       :script-name matched)]
+            (dispatch (.target this) state dn method path hdrs body))))
+      (throw (Exception. "Route is not finalized")))))
+
+(defn- compile-pattern
+  [segments]
+  (loop [[segment & more] segments compiled "^"]
+    (if segment
+      (recur more (str compiled "/+" segment))
+      (re-pattern (str compiled "/*$")))))
+
+(defn- finalize
+  [route]
+  (cond
+   (instance? Route route)
+   (assoc route :pattern (compile-pattern (.segments route)))
+
+   (coll? route)
+   (map finalize (flatten route))
+
+   :else
+   route))
 
 (defn- parse
-  [path]
-  (map
-   (fn [segment]
-     (if-let [[_ type name :as match] (re-find PLACEHOLDER segment)]
-       (if (= ":" type)
-         {:pattern CAPTURE :name (keyword name)}
-         {:pattern GLOB    :name (keyword name)})
-       {:pattern segment}))
-   (re-seq SEGMENT path)))
-
-(defn- finalize-path
-  [{pattern :pattern :as path}]
-  (assoc path :pattern (re-pattern (str "^" pattern "/*$"))))
-
-(defn- compile-path
-  [segments]
-  (finalize-path
-   (reduce
-    (fn [{:keys [pattern names]} {p :pattern name :name}]
-      {:pattern (str pattern "/+" p)
-       :names   (if name (conj names name) names)})
-    {:pattern "" :names []} segments)))
-
-(defn- compile-route
-  [expected-method {:keys [pattern names]} target]
-  (reify Route
-    (route [_ state dn method path hdrs body]
-      ;; Only match the method if there is a method requirement
-      (when (or (nil? expected-method) (= expected-method method))
-        ;; Match the path
-        (when-let [[matched & vals] (re-match pattern path)]
-          ;; There was a match, deconstruct the values
-          (let [params (zipmap names vals)
-                path   (subs path (count matched))
-                hdrs   (assoc hdrs
-                         :params      params
-                         :path-info   path
-                         :script-name matched)]
-            (route target state dn method path hdrs body)))))))
+  [base path]
+  (reduce
+   (fn [{:keys [segments names] :as base} segment]
+     (conj
+      base
+      (if-let [[_ type name :as match] (re-find PLACEHOLDER segment)]
+        {:segments (conj segments (if (= ":" type) CAPTURE GLOB))
+         :names    (conj names (keyword name))}
+        {:segments (conj segments segment) :names names})))
+   base (re-seq SEGMENT path)))
 
 (defn match
   ([path target] (match nil path target))
   ([method path target]
-     (compile-route method (compile-path (parse path)) target)))
-
-(defn- not-found
-  [dn]
-  (fn [evt val]
-    (when (= :request evt)
-      (dn :response [404 {"content-length" "9"} (buffer "Not found")]))))
+     (map->Route
+      (parse
+       {:method method :segments [] :names [] :target target}
+       path))))
 
 (defn- handle-request
   [state routes dn [{path :path-info method :request-method :as hdrs} body]]
   (loop [[r & more] routes]
-    (when-not (route r state dn method path hdrs body)
+    (when-not (dispatch r state dn method path hdrs body)
       (if more
-        (recur more)
-        (let [upstream (not-found dn)]
-          (reset! state upstream)
-          (upstream :request [hdrs body]))))))
+        (recur more)))))
 
+;; Probably should add a cascade feature
 (defn routing
   [& routes]
-  (let [routes (flatten routes)]
+  (let [routes (finalize (conj (vec routes) not-found))]
     (fn [dn]
       (let [state (atom nil)]
         (fn [evt val]

(def GLOB        #"(.*?)")
(def PLACEHOLDER #"^(:|\*)([a-z0-9*+!-+?]+)$")

(defprotocol Route
  (^{:private true} route [this state dn method path hdrs body]))

(extend-type Object
  Route
  (route [this state dn method path hdrs body]
    (let [upstream (this dn)]
      (reset! state upstream)
      (upstream :request [hdrs body])

            (if-let [upstream @state]
              (upstream evt val)
              (throw (Exception. "Invalid state")))))))))
