从列表创建 Compojure 路由

发布于 2024-11-03 21:30:41 字数 683 浏览 6 评论 0原文

我最近刚刚开始使用 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")))

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

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

I've just been playing with Compojure recently, and I've got a small basic webapp. For my HTML templates I'm using Enlive, and I've got a namespace that holds all the simple, static pages. The defroute call for these pages looks like this:

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

I've actually got a few more than that, but that should give the idea of what I'm doing.

Now, I thought, that's really just bunch of repetition 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 doesn't work, as the map is returning a lazy sequence and not a body (?) of functions.
Does someone know what I need to do to get this idea to work?

Or should I be using a completely different approach to cut down on repeating myself?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

别靠近我心 2024-11-10 21:30:41

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

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 that's still quite boring, let's spice it up! ;-)

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

With this code, the templates-for function will look for any functions finishing with "-template" in the namespaces given and write the appropriate route with them. Look how I'm not using any macro, but plenty of composition.

涫野音 2024-11-10 21:30:41

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)中的一等公民
当一些 Clojurian 人(通常不是我)说“宏是邪恶的”时,他们经常会想到这样的情况:当你试图编写某个东西却无法编写它时,你会遇到这样一个事实:某个东西是宏。

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

defroutes is a macro so unfortunately you wont be able to pass it to a function like map. You would need to write a macro that expanded into a call to defroutes. or look at the functions that it expands into and call them directly.

It wont work to create a list of routes within the call to defroutes like this

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

would expand into a list of routes:

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

if defroutes where a normal function you would solve this with apply

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

because defroutes is a macro it is completely finished before apply could run and the results would not make a lot of sense. You really can't compose macroes as functions. macroes are not first class citizens in clojure (or any lisp i know of)
When some Clojurians (not usually me) say "Macroes are evil" they often think about situations like this where you run into the fact that something is a macro when you try to compose it and can't.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文