2

I'm trying to load and/or compile a .clj file from within another .clj file. I'm doing this because the file I'm trying to load just contains a bunch of maps, and I intend eventually to replace these with an xml file. I could just :use the file and it'll work, but I'm trying to go through the exercise of loading an external bunch of data.

Through some random hacking around the repl (via emacs etc) I was able to (load "default_libs") as well as (compile...) it somehow (using different combinations of namespace qualifiers, ', and ") and get access to the maps, but after restarting the repl it didn't work any more, and anyway I had to use the full namespace name to get to the data.

This is lib_manager.clj:

(ns mycad.lib-manager
  (:use [clojure repl]
        [mycad utils]))

(compile 'mycad.default-libs)
(println mycad.default-libs/default-symbols) 

This is the file I'm trying to load, default_libs.clj. The data here will eventually be some xml file, but I'm still pretty new at this, so for now I've just written a bunch of clojure maps directly.

(ns mycad.default-libs)
(def default-symbols {.... })

So the question is how can I load a bunch of data from a .clj file without really loading it into the namespace with (ns...) but instead treating it as a source of data using either load or compile?

Thanks for any help

Sonicsmooth
  • 2,673
  • 2
  • 22
  • 35

2 Answers2

2

Change the compile in your example into a load as you described it earlier in your question. Then the example will work.

compile is used for AOT compilation of a namespace. So it is not what you need here.

In case there is just a single map defined you can use load-file.

(def default-symbols (load-file "/file/path.clj"))

In case the "file" is actually somewhere on the classpath or by some other non-local stream, there is load-string.

(def default-symbols (load-string (slurp (io/reader stream))))
kotarak
  • 17,099
  • 2
  • 49
  • 39
0

Lisps are very dynamic languages. Clojure, being Lisp, allows you to do the following:

user=> (eval (read-string "(def a 10)"))
#'user/a
user=> a
10

So you can load your file e.g. with a function read-all from here, and then (eval all forms:

(use 'clojure.java.io) ; for (reader ..) function
(import 'java.io.PushbackReader)
....
(doseq [f (read-all (PushbackReader. (reader "your/file.clj")))] (eval f))

Then if your file.clj contains (definitions only, they will be in your current namespace then you can use them as simple variables. If, though, your file.clj contained some namespace-changing forms ((ns..), (in-ns ..)), then things may be complicated, because current namespace will change. If such declarations are mandatory and cannot be deleted in the file itself, you can try and filter them, (evaling a form only if it is a definition.

Update: hm, I found out that (eval + (read-all is equivalent in some sense to (load-file:

(load-file "your/file.clj")

But in the case of load-file the namespace does not change even if there were namespace-changing commands - these namespaces are just loaded into memory, and you can refer to symbols in them as usual. It seems that this is what you need.

Community
  • 1
  • 1
Vladimir Matveev
  • 120,085
  • 34
  • 287
  • 296