Welcome! Please see the About page for a little more info on how this works.

0 votes
in REPL by
edited by

When using a socket repl, the output from the test runner is bound to the *out* of binding which first loads clojure.test:

(def ^:dynamic *test-out* *out*)

This means that when connecting a socket-repl the test output will go to the console rather than the *out* of the repl session.

clojure.main/repl has an :init option that I was hoping to be able to set this dynamic var.

In a repl, if I manually use with-bindings it correctly binds *test-out*. But trying to use the :init option of clojure.main/repl seems to fail to bind the var.

user=> (with-bindings {#'clojure.test/*test-out* *out*}
         (identical? clojure.test/*test-out* *out*))
user=> (clojure.main/repl
         :read server/repl-read
         :init (fn [] {#'clojure.test/*test-out* *out*}))
user=> (identical? clojure.test/*test-out* *out*)

I work around this with

user=> (clojure.main/repl
         :read server/repl-read
         :eval (fn [f] (binding [clojure.test/*test-out* *out*] (eval f))))
user=> (identical? clojure.test/*test-out* *out*)

But I would prefer to use the :init as it is intended and not have to hijack each eval. I'm not sure I understand why the binding doesn't take effect.

I'm not sure i'm able to make the init work at all:

user=> (def ^:dynamic *foo*)
user=> (with-bindings ((fn [] {#'*foo* 3}))
user=> (clojure.main/repl
         :read server/repl-read
         :init (fn [] {#'*foo* 3}))
user=> *foo*
#object[clojure.lang.Var$Unbound 0x6dcfc7b9 "Unbound: #'user/*foo*"]

I see why now. The with-bindings used in clojure.main is not clojure.core/with-bindings.

1 Answer

0 votes

Answer: a misunderstanding. clojure.main/repl uses (with-bindings (init) ...) but this is not clojure.core/with-bindings but clojure.main/with-bindings.