Clojure Ring/Compojure REPL 中的动态处理程序更新

Dynamic handler update in Clojure Ring/Compojure REPL

我使用 lein new compojure test 创建了一个新的 Compojure Leiningen 项目。 Web 服务器由 lein repl 运行 然后

user=> (use 'ring.adapter.jetty)
user=> (run-jetty test.handler/app {:port 3000})

路由和应用程序处理程序规范很简单:

(defroutes app-routes
  (GET "/*.do" [] "Dynamic page")
  (route/not-found "Not Found"))

(def app
  (wrap-defaults app-routes site-defaults))

现在,在更改 app-routes 定义中的任何内容后(例如,将 "Dynamic page" 文本更改为其他任何内容,或修改 URI 匹配字符串),我没有在浏览器。但是,将 app-routes 定义稍微更改为

(defn dynfn [] "Dynamic page fn")
(defroutes app-routes
  (GET "/*.do" [] (dynfn))
  (route/not-found "Not Found"))

我确实在更改 dynfn 的 return 值时获得动态更新。此外,遵循 this article 的建议并将 app 定义修改为

(def app
  (wrap-defaults #'app-routes site-defaults))

(注意 #' 透明地为 app-routes 创建了一个变量)也有帮助!

为什么会这样?有没有其他方法可以在 defroutes 中获得真正的动态行为?

谢谢!

#'app-routes 是一个扩展为 (var app-routes) 的 reader 宏。当将 var 用作函数时,它会在每次调用时重新取消引用,然后调用该取消引用返回的值。

如果您提供 app-routes 作为参数,编译器会将取消引用的值赋予 wrap-defaults,并且当更新 var 时,先前的值不会改变,因此更改var 不会改变 app.

的行为

以下 repl 记录可能具有指导意义:

user=> (defn foo [] "original")
#'user/foo
user=> (defn caller [f] #(f))
#'user/caller
user=> (def call-foo-value (caller foo))
#'user/call-foo-value
user=> (call-foo-value)
"original"
user=> (def call-foo-var (caller #'foo))
#'user/call-foo-var
user=> (call-foo-var)
"original"
user=> (defn foo [] "changed")
#'user/foo
user=> (call-foo-value)
"original"
user=> (call-foo-var)
"changed"