首页 文章

从列表创建Compojure路由

提问于
浏览
7

我最近刚刚和Compojure一起玩,而且我有一个小的基本webapp . 对于我的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 返回一个懒惰的序列而不是函数的主体(?) . 有人知道我需要做些什么来让这个想法发挥作用吗?

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

2 回答

  • 6

    您始终可以使用defroutes使用的 routes 函数:

    (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

    defroutes is a macro所以不幸的是你无法将它传递给像 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 是一个宏,它在应用运行之前完全完成,结果不会有多大意义 . 你真的不能把宏作为函数 . 在clojure(或任何我知道的任何口齿不清)的情况下,当一些Clojurians(通常不是我)说"Macroes are evil"时,他们经常会想到这样的情况,当你试图编写它时,你会遇到一个宏是一个宏而不能 .

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

相关问题