Search code examples
clojure

evaluate a function binds to current namespace using read-string


I struggle to evaluate a string contains a function call. The function is defined in the same namespace where the evaluation happens. Everything works well if a symbol comes from a library referring inside ns body like: (ns myname.myapp (:require [clj-time.core])).

My goal is to load a file (edn format) that interops with custom symbols. Here is a bare minimum setup to reproduce the issue:

(ns myname.myapp
  (:import [java.time Instant])
  (:gen-class))

(defn time-now []
  (->
   (Instant/now)
   (.toString)))

(defn -main [& args]
  (prn (eval (read-string "{:now (time-now)}"))))

If I evaluate sexp by sexp inside the source file buffer everything ok, but cli execution clj -m myname/myapp leads to Unable to resolve symbol: time-now in this context. Any ideas? Thank you in advance.


Solution

  • The thing is that when the code is evaluating inside IDE/text editor the current namespace is pointing to the last evaluated namespace, and in the example above it is myname.myapp, so that's why the code works.

    But with the complied jar or cli module running, the active namespace has another name (ether clojure.core or user). The solution is to rebind the namespace when the evaluation is taking place:

    (ns myname.myapp
      (:import [java.time Instant])
      (:gen-class))
    
    (defn time-now []
      (->
       (Instant/now)
       (.toString)))
    
    (defn -main [& args]
      (binding [*ns* (find-ns 'myname.myapp)]
        (prn (eval (read-string "{:now (time-now)}")))))