Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic handler update in Clojure Ring/Compojure REPL

I've created a new Compojure Leiningen project using lein new compojure test. Web server is run by lein repl and then

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

Routes and app handler specification is trivial:

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

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

Now, after changing anything in app-routes definition (e.g. changing "Dynamic page" text to anything else, or modifying URI matching string), i do not get the updated text/routes in the browser. But, when changing app-routes definition slightly to

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

i do get dynamic updates when changing the return value of dynfn. Also, following the advice from this article and modifying the app definition to

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

(note the #' that transparently creates a var for app-routes) also helps!

Why is that so? Is there any other way one could get a truly dynamic behaviour in defroutes?

Thanks!

like image 298
siphiuel Avatar asked Sep 21 '25 03:09

siphiuel


1 Answers

#'app-routes is a reader macro that expands to (var app-routes). When a var is used as if it were a function, it is dereferenced anew on each invocation, and then the value returned by that deref is called.

If you were to supply app-routes as the argument, the compiler would give the dereferenced value to wrap-defaults, and when the var is updated, the previous value is not changed, so changing the var does not change the behavior of app.

The following repl transcript might be instructive:

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"
like image 101
noisesmith Avatar answered Sep 23 '25 07:09

noisesmith