 
 (defn- set-session-cookie
   "Set the session cookie on the response if required."
-  [request response session]
+  [repository request response session]
   (let [new?   (:new-session? request)
-        cookie (session-cookie new? session)
-        update (set-cookie :compojure-session cookie, :path "/")]
+        cookie (session-cookie repository new? session)
+        update (set-cookie :compojure-session cookie
+                           :path (repository :path "/"))]
     (if cookie
       (update-response request response update)
       response)))
 
 (defn- save-handler-session
   "Save the session for a handler if required."
-  [request response session]
+  [repository request response session]
   (when (and (contains? response :session)
              (nil? (response :session)))
-    (destroy-session session))
+    (destroy-session repository session))
   (when (or (:session response)
-            (contains? *session-repo* :expires)
+            (contains? repository :expires)
             (:new-session? request)
             (not-empty (:flash request)))
-    (write-session session)))
+    (write-session repository session)))
+
+(defn- keyword->repository
+  "If the argument is a keyword, expand it into a repository map."
+  [repository]
+  (if (keyword? repository)
+    {:type repository}
+    repository))
 
 (defn with-session
   "Wrap a handler in a session of the specified type. Session type defaults to
   :memory if not supplied."
   ([handler]
     (with-session handler :memory))
-  ([handler session-repo]
+  ([handler repository]
     (fn [request]
-      (binding [*session-repo* session-repo]
-        (let [request  (-> request assoc-cookies
-                                   assoc-request-session
-                                   assoc-request-flash)
-              response (handler request)
-              session  (or (:session response) (:session request))]
-          (when response
-            (save-handler-session request response session)
-            (set-session-cookie   request response session)))))))
-
-;; User functions for modifying the session
+      (let [repo     (keyword->repository repository)
+            request  (-> request (assoc-cookies)
+                                 (assoc-request-session repo)
+                                 (assoc-request-flash))
+            response (handler request)
+            session  (or (:session response) (:session request))]
+        (when response
+          (save-handler-session repo request response session)
+          (set-session-cookie   repo request response session))))))
+
+;; Useful functions for modifying the session
 
 (defn set-session
   "Return a response map with the session set."

  (:use compojure.crypto)
  (:use clojure.contrib.except))

;; Global session store type

(declare *session-repo*)

;; Override these mulitmethods to create your own session storage.
;; Uses the Compojure repository pattern.

(defn- repository-type
  [repository]
  (:type repository repository))

(defmulti create-session
  "Create a new session map. Should not attempt to save the session."
  (fn [] (repository-type *session-repo*)))

(defmulti read-session
  "Read in the session using the supplied data. Usually the data is a key used
  to find the session in a store."
  (fn [data] (repository-type *session-repo*)))

(defmulti write-session
  "Write a new or existing session to the session store."
  (fn [session] (repository-type *session-repo*)))

(defmulti destroy-session
  "Remove the session from the session store."
  (fn [session] (repository-type *session-repo*)))

(defmulti session-cookie
  "Return the session data to be stored in the cookie. This is usually the
  session ID."
  (fn [new? session] (repository-type *session-repo*)))

;; Default implementations of create-session and set-session-cookie

(defmethod create-session :default
  []
  {:id (gen-uuid)})

(defmethod session-cookie :default
  [new? session]
  (if new?
    (session :id)))


(defn- assoc-expiry
  "Associate an :expires-at key with the session if the session repository
  contains the :expires key."
  [repository session]
  (if-let [expires (:expires repository)]
    (assoc session :expires-at (timestamp-after expires))
    session))

