Question

(Sorry this is so long. It's long to rule out misunderstandings, not because I want you to figure out what my question should be.)

I understand the basics of Clojure namespaces, and that the namespaces listed in my ns statements at the beginnings of files have to match locations of files in a directory hierarchy. I have figured out part of what Leiningen is doing automatically to set up search load, and part of what it is loading automatically, but ... it's still driving me crazy. The problem is that there are things that Leiningen seems to set up implicitly, that are also not well documented in the obvious places like the Leiningen tutorial and the sample project file. (Maybe the information is there, but I haven't found it/interpreted it.)

I've got things set up so that when I do lein repl, the main source files are loaded (popco.clj and acme.clj below), but loading other files causes trouble. I want to make the MWE as minimal possible, and the question short, but I want to make it clear that I am not asking simpler questions that have been answered already (e.g. this one).

Here's where source files are, with ns statements from the same files listed over on the right:

src/popco/sims/sim1/sim1propns.clj  (ns popco.sims.sim1.sim1propns)
src/utils/general.clj               (ns utils.general)
src/popco/core/acme.clj             (ns popco.core.acme)
src/popco/core/popco.clj            (ns popco.core.popco
                                      [:use popco.core.acme]
                                      [:import [popco.core.acme Propn Obj]]
                                      (:gen-class)) ; not sure what this does yet

Here's the project.clj file:

(defproject popco-x "0.0.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.5.1"]]
  :main popco.core.popco
  :profiles {:dev {:dependencies []
                   :source-paths ["src"] }})

When I run lein repl, I see that I'm in the popco.core.popco namespace:

popco.core.popco=>

and I find that both functions and record types defined in acme.clj are available. I have learned (by trial and error) that ":main popco.core.popco" in project.clj is causing popco.clj to run, and that results in the the REPL being left in the popco.core.popco namespace. So far, so good.

Here are my questions:

What if I want to load src/utils/general.clj, or src/popco/sims/sim1/sim1propns.clj ? I can load them with load-file, but I'd like to use load in the REPL, and more importantly, I'd like to be able to require or use these source files from other source files. How can I reference the functions in general.clj from inside acme.clj, for example? I think the answer might be to add entries to the sequence after :source-paths in project.clj, but I'm confused about what should go there.

Feel free to recommend anything. Other directory structures, radical changes to project.clj, whatever.

Was it helpful?

Solution

Everything about your project structure and project.clj looks entirely normal.

  • What if I want to load src/utils/general.clj:
    This is almost always done through a require or use expression. While it is possible to load a file with load-file this requires you to specify the path (relative to where you started the JVM) to the file. load loads it relative to the class-path though in practice these are almost never used when the files being loaded are part of the project. In that case you can simply require them.

  • I'd like to be able to require or use these source files from other source files:
    The expected way of doing this is to put a (:require [popco.core.acme :as acme]) statement in the ns form at the top of the namespace that wants to use functions from that namespace.

  • How can I reference the functions in general.clj from inside acme.clj:
    (ns popco.core.acme
    (:require [utils.general :refer [function1 function2] :as general))

  • I think the answer might be to add entries to the sequence after :source-paths in project.clj:
    You will most likely never need to put anything there. require and use are the appropriate tool for this. They will already be able to find all the files under /src/ because those files will be in the classpath when the leiningen starts java. You can see the class path used with the lein classpath function.

ps: You can also call require and use as functions (form the REPL for instance), though doing this in the ns form is generally preferred.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top