6

我最近一直在玩 Compojure,并且我有一个小的基本 web 应用程序。对于我的 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")))

当然,这是行不通的,因为 map 返回的是惰性序列,而不是函数体 (?)。有人知道我需要做什么才能让这个想法发挥作用吗?

还是我应该使用完全不同的方法来减少重复自己?

4

2 回答 2

5

您始终可以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”结尾的任何函数,并使用它们编写适当的路由。看看我如何不使用任何宏,而是使用大量组合。

于 2011-04-28T17:30:10.627 回答
1

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它是一个宏,所以它在 apply 可以运行之前就已经完全完成了,结果没有多大意义。你真的不能将宏组合成函数。宏不是 clojure(或我知道的任何 lisp)中的一等公民当一些 Clojurians(通常不是我)说“宏是邪恶的”时,他们经常会想到这样的情况,当你遇到某些东西是宏的事实时尝试撰写它,但不能。

解决方案是不使用 defroutes 宏,直接调用 routes 函数。

于 2011-04-28T00:44:24.433 回答