任何人都可以解释为什么Compojure的路由宏只接受文字向量作为路由描述参数?

时间:2013-08-30 23:42:27

标签: clojure compojure

compojure.core / GET接受描述URI的字符串或描述正则表达式的向量作为路由定义参数,该正则表达式除了URI本身之外还要与从URI中提取的参数匹配。您可以在此处找到文档Routes in Detail

来自我的REPL(从头开始,leiningen的project.clj在这个问题的最后)

user> (use '[compojure.core :only [GET]])
nil
user> (def h (GET "/" [] "hello"))
#'user/h
user> (h {:uri "/" :request-method :get})
{:status 200, :headers {"Content-Type" "text/html; charset=utf-8"}, :body "hello"}

到目前为止,这么好的普通香草路线

以下是使用向量进行路由的示例:

user> (def h2 (GET ["/foo/:id" :id #"[0-9]+"] [] "hello from foo"))
#'user/h2
user> (h2 {:uri "/foo/123" :request-method :get})
{:status 200, :headers {"Content-Type" "text/html; charset=utf-8"}, :body "hello from foo"}
user> (h2 {:uri "/foo/abc" :request-method :get})
nil

仍然一切都很好;你可以看到它只匹配数字请求:id's

现在这里出现了我不明白的部分:

user> (def v ["/foo/:id" :id #"[0-9]+"])
#'user/v
user> (def h3 (GET v [] "hello again from foo"))
#'user/h3
user> (h3 {:uri "/foo/abc" :request-method :get})
IllegalArgumentException No implementation of method: :route-matches of protocol: #'clout.core/Route found for class: clojure.lang.PersistentVector  clojure.core/-cache-protocol-fn (core_deftype.clj:541)

当有人使用变量而不是文字向量定义处理程序时,是否可以解释处理程序在评估时失败的原因?

如果您想要复制确切的环境,这是我的leiningen项目文件project.clj:

(defproject cljlab "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.5.1"]
                 [org.clojure/clojure-contrib "1.2.0"]
                 [compojure "1.1.5"]])

1 个答案:

答案 0 :(得分:3)

问题在于,compojure的GET是一个宏,而不是一个函数。宏在编译时运行,因此无法查看“v”的值是什么。查看为h2和h3生成的代码之间的区别:

user> (pprint (macroexpand-1 '(GET ["/foo/:id" :id #"[0-9]+"] [] "hello from foo")))
      (compojure.core/make-route
      :get
      (clout.core/route-compile "/foo/:id" {:id #"[0-9]+"})
      (clojure.core/fn
         [request__1858__auto__]
         (compojure.core/let-request
           [[] request__1858__auto__]
           "hello from foo")))

user> (pprint (macroexpand-1 '(GET v [] "hello again from foo")))
      (compojure.core/make-route
      :get
      (if (clojure.core/string? v) (clout.core/route-compile v) v)
      (clojure.core/fn
        [request__1858__auto__]
        (compojure.core/let-request
          [[] request__1858__auto__]
          "hello again from foo")))

在第一种情况下,宏能够将路径分成其成分并对其进行转换。在第二种情况下,宏只看到“v”符号。