Creating Compojure Routes from a List

I recently played with Compojure and I have a small basic webapp. For my HTML templates, I use Enlive, and I have a namespace that stores all the simple static pages. The space for these pages is as follows:

(defroutes public-routes (GET "/" [] (info/index-template)) (GET "/about" [] (info/about-template)) (GET "/contact" [] (info/contact-template))) 

I actually have a few more, but this should give an idea of ​​what I'm doing.

Now I thought it was really just a bunch of repetitions on my part, so I thought I would try the following:

 (defroutes info-routes (map #(GET (str "/" %) [] (ns-resolve 'webapp.pages.info (symbol (str % "-template")))) '("about" "contact"))) 

Of course, this does not work, since the map returns a lazy sequence, and not the body (?) Of functions. Does anyone know what I need to do to make this idea work?

Or should I use a completely different approach to shorten the repetition of myself?

+6
source share
2 answers

You can always use the routes function, which is used by defroutes:

 (defroutes info-routes (apply routes (map #(GET (str "/" %) [] (ns-resolve 'webapp.pages.info (symbol (str % "-template")))) '("about" "contact")))) 

But it's still pretty boring, let it be in a hurry !; -)

 (defn templates-for [& nss] (->> nss (map ns-publics) (apply concat) (filter #(->> % first str (re-seq #"-template$"))) (map second))) (defn template-uri [template] (->> template meta :name name (re-seq #"(.*)-template$") first second (str "/"))) (defn template->route [template] (GET (template-uri template) [] template)) (defroutes public-routes (GET "/" [] "foo") (apply routes (map template->route (templates-for 'webapp.pages.info)))) 

Using this code, the templates-for function will look for any functions ending with "-template" in the specified namespaces and write the corresponding route with them. See how I do not use macros, but a lot of composition.

+5
source

defroutes is a macro , so unfortunately you cannot pass it to a function such as a map. You will need to write a macro that would be extended in the defroutes call. or look at the functions that it expands and call them directly.

It will not work to create a list of routes in a call for a U-turn, like this

 (defroutes public-routes (make-list-of-routes) 

will expand to the list of routes:

 (defroutes public-routes ( (GET "/" [] (info/index-template)) (GET "/about" [] (info/about-template)) (GET "/contact" [] (info/contact-template))) ) 

if defroutes where the normal function you would solve with apply

 (apply defroutes (conj 'public-routes (make-list-of-routes))) 

because defroutes is a macro that is fully completed before it can be applied, and the results will not make much sense. You really can't compose macros as functions. macros are not first-class citizens in clojure (or any lisp I know) When some kluurs (usually not me) say "Macros are evil", they often think of situations where you are faced with the fact that something is a macro when you try to compose it and cannot.

the solution is to not use the defroutes macro and directly call the routes function.

+1
source

Source: https://habr.com/ru/post/886843/


All Articles