Создание Compojure маршрутов из списка - PullRequest
7 голосов
/ 28 апреля 2011

Я недавно играл в Compojure, и у меня есть небольшое базовое веб-приложение. Для моих HTML-шаблонов я использую Enlive, и у меня есть пространство имен, которое содержит все простые статические страницы. Вызов defroute для этих страниц выглядит следующим образом:

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

У меня действительно есть кое-что еще, но это должно дать представление о том, что я делаю.

Теперь, я подумал, это действительно просто повторение с моей стороны, поэтому я решил попробовать следующее:

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

Конечно, это не работает, поскольку карта возвращает ленивую последовательность, а не тело (?) Функций. Кто-нибудь знает, что мне нужно сделать, чтобы эта идея заработала?

Или я должен использовать совершенно другой подход, чтобы сократить повторение?

Ответы [ 2 ]

6 голосов
/ 28 апреля 2011

Вы всегда можете использовать функцию routes, которую используют defroutes:

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

Но это все еще довольно скучно, давайте оживим!; -)

(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))))

С этим кодом функция templates-for будет искать все функции, заканчивающиеся на "-template" в заданных пространствах имен, и записывать с ними соответствующий маршрут.Посмотрите, как я не использую никакой макрос, но много композиции.

1 голос
/ 28 апреля 2011

defroutes - это макрос , поэтому, к сожалению, вы не сможете передать его такой функции, как map.Вам нужно написать макрос, который расширится до вызова defroutes.или посмотрите на функции, в которые он расширяется, и вызовите их напрямую.

Не будет работать создание списка маршрутов в вызове к defroutes, подобного этому

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

развернется в список маршрутов:

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

если defroutes где нормальная функция, вы решите это с помощью apply

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

, поскольку defroutes - это макрос, который полностью завершен до того, как может быть применено применение, и результаты не будут иметь большого смысла.Вы действительно не можете создавать макросы как функции.макросы не являются первоклассными гражданами в скрытой форме (или в каком-то другом известном мне слове). Когда некоторые клоюрцы (обычно не я) говорят: «Макросы злые», они часто думают о таких ситуациях, когда вы сталкиваетесь с тем, чточто-то - это макрос, когда вы пытаетесь его скомпоновать и не можете.

решение состоит в том, чтобы не использовать макрос defroutes и напрямую вызывать функцию маршрутов.

...