Search code examples
macrosclojureringgensym

How do I write this macro in clojure?


I've got this function:

(defn handler [request]
  (case (request :uri)
    "/" (home request)
    "/good" (good request)
    "/evil" (evil request)
    "/neutral" (neutral request)
    (status-response 404 (str "<h1>404 Not Found: " (:uri request) "</h1>" ))))

but I keep changing the list of pages-which-resolve-to-functions-with-the-same-name and I'd like to be able to write:

(def-handler good evil neutral)

instead:

But I am stuck. My best shot so far looks like:

(defmacro def-handler [& addresses]
  `(defn handler [request#]
     (case (request# :uri)
       ~@(mapcat (fn[x] [(str "/" x) (list x 'request)]) addresses)
       "/" (home request#)
       (status-response 404 (str "<h1>404 Not Found: " (:uri request#) "</h1>" )))))

But it does not quite work because the request in the generated calls is not the gensym, and I am at a loss how to get the gensym in there.

This looked promising until I noticed it made a new gensym:

(defmacro def-handler [& addresses]
  `(defn handler [request#]
     (case (request# :uri)
       ~@(mapcat (fn[x] [(str "/" x) `( ~x request#)]) addresses)
       "/" (home request#)
       (status-response 404 (str "<h1>404 Not Found: " (:uri request#) "</h1>" )))))

Solution

  • I think you can avoid gensym here at all. I don't see how you can "pollute" environment by not using gensym. Example without gensym:

    (defmacro def-handler [& addresses]
      `(defn handler [~'request]
         (case (~'request :uri)
           ~@(mapcat (fn[x] [(str "/" x) (list x 'request)]) addresses)
           "/" (home ~'request)
           (status-response 404 (str "<h1>404 Not Found: " (:uri ~'request) "</h1>" )))))