0

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>" )))))
John Lawrence Aspden
  • 17,124
  • 11
  • 67
  • 110
  • 2
    You don't need to do that with a macro. Just compare the incoming path to the names of the symbols passed into the function and then invoke the appropriate function when a match occurs. – BillRobertson42 Jan 31 '13 at 12:57

2 Answers2

3

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>" )))))
Mikita Belahlazau
  • 15,326
  • 2
  • 38
  • 43
  • @JohnLawrenceAspden You mean how to use gensym here? – Mikita Belahlazau Jan 31 '13 at 19:04
  • Well, how to use it "cutely". Ankur's answer shows how to use it "manually", but it doesn't seem so weird to use it like this, and the fact that you can't use the auto-gensym thingy and have to go back to doing it the old way seems a bit broken. – John Lawrence Aspden Feb 02 '13 at 21:18
1

The problem with your macro code is that the dynamic symbol which is part of quasiquoting can't be use outside quoted part i.e in the unquote/unquote-splicing code. However the other way is possible, that is you do gensym in the macro execution part and use that inside quasiquoting part as shown below:

(defmacro def-handler [& addresses]                                                                                                                  
  (let [request (gensym)]                                                                                                                            
  `(defn handler [~request]                                                                                                                          
     (case (~request :uri)                                                                                                                           
       ~@(mapcat (ƒ [x] [(str "/" x) (list x request)]) addresses)                                                                                   
       "/" (home ~request)                                                                                                                           
       (status-response 404 (str "<h1>404 Not Found: " (:uri ~request) "</h1>")))))) 
Ankur
  • 33,367
  • 2
  • 46
  • 72
  • Thanks, I'd forgotten that I could just do it 'by hand'. I'm a bit torn about which answer to accept, but I think Nikita has answered the question I actually asked, whereas you've answered the question I wanted to ask! – John Lawrence Aspden Feb 02 '13 at 21:20
  • My answer was in response to your comment on Nikita answer about how to use gensym, but Nikita answer already solved your problem which was actually about the request symbol rather than gensym – Ankur Feb 03 '13 at 06:11