如何在 Compojure 视图中调用已解析的函数?
How do I invoke a resolved function in a Compojure view?
我有以下代码作为测试:
(defn test-fn [] (println "This is a test"))
(def my-test "test")
((resolve (symbol (str my-test "-fn"))))
按我的预期运行,生成 This is a test
。
所以我把它放在一个单独的视图中,如下所示:
(ns my-test.template-views
(:require
[hiccup.core :refer :all]
[hiccup.page :refer :all]
[my-test.home-views :refer :all]
[my-test.page1-views :refer :all]))
(defn template-body
[uri]
(html5 {:lang "en"}
[:body
(let [the-page (if (> (count uri) 1)
(clojure.string/replace uri #"/" "")
"home")]
((resolve (symbol (str the-page "-body")))))]))
从 Compojure 调用的是这样的:
(ns the-test.reporting-dashboard
(:gen-class)
(:require
[the-test.template-views :refer :all]
[compojure.core :refer [defroutes GET POST context]]
[compojure.route :as route]
[org.httpkit.server :refer [run-server]]
))
(defn wrap-request
[handler]
(fn [request]
(let [{remote-addr :remote-addr uri :uri scheme :scheme request-method :request-method} request]
(println (str "REQUEST: " request)))
(handler request)))
(defroutes app
(wrap-request
(GET "/" request
{:status 200
:headers {"Content-Type" "text/html"}
:body (home-views/home-body (:uri request))}))
(wrap-request
(GET "/foo" request
{:status 200
:headers {"Content-Type" "text/html"}
:body (template-body (:uri request))}))
(route/resources "/")
(route/not-found {:status 404
:headers {"Content-Type" "text/html"}
:body "<h1>Not Found</h1>"}))
当我调用 https//mydomain.tld/foo 我得到一个 java.lang.NullPointerException:
user=> Sat Apr 24 17:59:16 MDT 2021 [worker-2] ERROR - GET /foo
java.lang.NullPointerException
at the-test.template_views$template_body.invokeStatic(template_views.clj:14)
at the-test.template_views$template_body.invoke(template_views.clj:12)
at the-test.my_test$fn__269541.invokeStatic(my_test.clj:49)
at the-test.my_test$fn__269541.invoke(my_test.clj:46)
at compojure.core$wrap_response$fn__269102.invoke(core.clj:158)
at compojure.core$wrap_route_middleware$fn__269086.invoke(core.clj:128)
at compojure.core$wrap_route_info$fn__269091.invoke(core.clj:137)
at compojure.core$wrap_route_matches$fn__269095.invoke(core.clj:146)
at the-test.my_test$wrap_request$fn__269531.invoke(my_test.clj:22)
at compojure.core$routing$fn__269110.invoke(core.clj:185)
at clojure.core$some.invokeStatic(core.clj:2705)
at clojure.core$some.invoke(core.clj:2696)
at compojure.core$routing.invokeStatic(core.clj:185)
at compojure.core$routing.doInvoke(core.clj:182)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invokeStatic(core.clj:669)
at clojure.core$apply.invoke(core.clj:662)
at compojure.core$routes$fn__269114.invoke(core.clj:192)
at org.httpkit.server.HttpHandler.run(RingHandler.java:117)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
在 Compojure 中无法再调用此函数是怎么回事?
不确定根本原因,但我能够找到类似的最小示例和解决方法。
我用 lein new app demo
创建了一个简单的项目,然后将 core.clj
的代码替换为:
(ns demo.core
(:require [clojure.string :refer :all]))
(defn -main
[& args]
(println ((resolve 'capitalize) "hello")))
运行 lein run
崩溃:
$ lein run
WARNING: reverse already refers to: #'clojure.core/reverse in namespace: demo.core, being replaced by: #'clojure.string/reverse
WARNING: replace already refers to: #'clojure.core/replace in namespace: demo.core, being replaced by: #'clojure.string/replace
Syntax error (NullPointerException) compiling at (/tmp/form-init1769060018979063159.clj:1:73).
null
Full report at:
/tmp/clojure-17609112051049758700.edn
错误报告显示了一些关于 Compiler.java 中的错误,所以可能是一些惰性初始化问题或只是一个错误。在我看来,当您尝试将它作为函数调用时,var 无法解析,因此出现 NullPointerException。
解决方法是使用 ns-resolve
代替:
(ns demo.core
(:require [clojure.string :refer :all]))
(defn -main
[& args]
(println ((ns-resolve 'clojure.string 'capitalize) "hello")))
以上按预期工作:
$ lein run
WARNING: reverse already refers to: #'clojure.core/reverse in namespace: demo.core, being replaced by: #'clojure.string/reverse
WARNING: replace already refers to: #'clojure.core/replace in namespace: demo.core, being replaced by: #'clojure.string/replace
Hello
如果您知道需要查找符号的命名空间,看看是否可以将视图中的 resolve
替换为 ns-resolve
。
我有以下代码作为测试:
(defn test-fn [] (println "This is a test"))
(def my-test "test")
((resolve (symbol (str my-test "-fn"))))
按我的预期运行,生成 This is a test
。
所以我把它放在一个单独的视图中,如下所示:
(ns my-test.template-views
(:require
[hiccup.core :refer :all]
[hiccup.page :refer :all]
[my-test.home-views :refer :all]
[my-test.page1-views :refer :all]))
(defn template-body
[uri]
(html5 {:lang "en"}
[:body
(let [the-page (if (> (count uri) 1)
(clojure.string/replace uri #"/" "")
"home")]
((resolve (symbol (str the-page "-body")))))]))
从 Compojure 调用的是这样的:
(ns the-test.reporting-dashboard
(:gen-class)
(:require
[the-test.template-views :refer :all]
[compojure.core :refer [defroutes GET POST context]]
[compojure.route :as route]
[org.httpkit.server :refer [run-server]]
))
(defn wrap-request
[handler]
(fn [request]
(let [{remote-addr :remote-addr uri :uri scheme :scheme request-method :request-method} request]
(println (str "REQUEST: " request)))
(handler request)))
(defroutes app
(wrap-request
(GET "/" request
{:status 200
:headers {"Content-Type" "text/html"}
:body (home-views/home-body (:uri request))}))
(wrap-request
(GET "/foo" request
{:status 200
:headers {"Content-Type" "text/html"}
:body (template-body (:uri request))}))
(route/resources "/")
(route/not-found {:status 404
:headers {"Content-Type" "text/html"}
:body "<h1>Not Found</h1>"}))
当我调用 https//mydomain.tld/foo 我得到一个 java.lang.NullPointerException:
user=> Sat Apr 24 17:59:16 MDT 2021 [worker-2] ERROR - GET /foo
java.lang.NullPointerException
at the-test.template_views$template_body.invokeStatic(template_views.clj:14)
at the-test.template_views$template_body.invoke(template_views.clj:12)
at the-test.my_test$fn__269541.invokeStatic(my_test.clj:49)
at the-test.my_test$fn__269541.invoke(my_test.clj:46)
at compojure.core$wrap_response$fn__269102.invoke(core.clj:158)
at compojure.core$wrap_route_middleware$fn__269086.invoke(core.clj:128)
at compojure.core$wrap_route_info$fn__269091.invoke(core.clj:137)
at compojure.core$wrap_route_matches$fn__269095.invoke(core.clj:146)
at the-test.my_test$wrap_request$fn__269531.invoke(my_test.clj:22)
at compojure.core$routing$fn__269110.invoke(core.clj:185)
at clojure.core$some.invokeStatic(core.clj:2705)
at clojure.core$some.invoke(core.clj:2696)
at compojure.core$routing.invokeStatic(core.clj:185)
at compojure.core$routing.doInvoke(core.clj:182)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invokeStatic(core.clj:669)
at clojure.core$apply.invoke(core.clj:662)
at compojure.core$routes$fn__269114.invoke(core.clj:192)
at org.httpkit.server.HttpHandler.run(RingHandler.java:117)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
在 Compojure 中无法再调用此函数是怎么回事?
不确定根本原因,但我能够找到类似的最小示例和解决方法。
我用 lein new app demo
创建了一个简单的项目,然后将 core.clj
的代码替换为:
(ns demo.core
(:require [clojure.string :refer :all]))
(defn -main
[& args]
(println ((resolve 'capitalize) "hello")))
运行 lein run
崩溃:
$ lein run
WARNING: reverse already refers to: #'clojure.core/reverse in namespace: demo.core, being replaced by: #'clojure.string/reverse
WARNING: replace already refers to: #'clojure.core/replace in namespace: demo.core, being replaced by: #'clojure.string/replace
Syntax error (NullPointerException) compiling at (/tmp/form-init1769060018979063159.clj:1:73).
null
Full report at:
/tmp/clojure-17609112051049758700.edn
错误报告显示了一些关于 Compiler.java 中的错误,所以可能是一些惰性初始化问题或只是一个错误。在我看来,当您尝试将它作为函数调用时,var 无法解析,因此出现 NullPointerException。
解决方法是使用 ns-resolve
代替:
(ns demo.core
(:require [clojure.string :refer :all]))
(defn -main
[& args]
(println ((ns-resolve 'clojure.string 'capitalize) "hello")))
以上按预期工作:
$ lein run
WARNING: reverse already refers to: #'clojure.core/reverse in namespace: demo.core, being replaced by: #'clojure.string/reverse
WARNING: replace already refers to: #'clojure.core/replace in namespace: demo.core, being replaced by: #'clojure.string/replace
Hello
如果您知道需要查找符号的命名空间,看看是否可以将视图中的 resolve
替换为 ns-resolve
。