tags:

views:

97

answers:

1

Simple question. I'm new to Clojure.

How can I use one file from my project in another file? Basically how can I include, import, or require another file? Not from libraries but fro my own code.

Thanks, Alex

+4  A: 

Normally you'll want to use the same method that you use with library code, which is to use / require your namespaces (through an ns form at the top of the file and sometimes the use / require functions at the REPL). For this to work, you have to make sure they are on the classpath. A short guide to that:

  1. Follow the usual Clojure project structure: a src/ directory containing all your source files, where file src/foo/bar/baz.clj defines a namespace called foo.bar.baz. Note that you must maintain the directory structure / namespace name structure correspondence; things won't work otherwise. Also note that you must not use the _ character in namespace names or the - character (the hyphen) in filenames and whenever you use _ in filenames you must use a - in namespace names (and the other way around.) Finally, the directory hierarchy will be slightly more complicated with Maven projects, but don't worry about this for now (unless you're already a proficient user of Maven, in which case this won't be a problem for you).

    Also see this answer of mine to an earlier SO question about Java classpath handling with Clojure for a more detailed step-by-step explanation of the filesystem hierarchy / classpath hierarchy correspondence.

  2. If your code from the foo.bar namespace needs to use code from the foo.quux.baz namespace, do something like (ns foo.bar (:require [foo.quux.baz :as baz])) in foo/bar.clj and call functions from baz as baz/some-function. Or you can put (:use foo.quux.baz) in the ns form instead to call them directly (without the namespace qualifier, e.g. some-function). That's exactly the same thing as what you'd do for library code.

When working with your project's code from the REPL, make sure you include the src/ directory (the directory itself, not any of the files therein) on the classpath. You should probably consider using some tool to automate the REPL setup (including classpath management) for you; Leiningen is very popular with Clojurians and there are plugins for using Maven with Clojure too.

Warning: Your JVM-launching command might (in fact, probably will) recognise an environment variable called $CLASSPATH. As for its relationship to your Clojure projects, well, basically there should be none. More likely than not, your projects will require a different classpath each, with some possibly using versions of certain jars incompatible with those required by others (notably if you're using Clojure 1.1 -- latest stable release -- for some projects, while experimenting with 1.2 snapshots with others). Thus the correct way of managing the classpath is to prepare a minimal version for each project and pass that to the JVM launching command. As mentioned previously, you should invest some time in learning to use a good tool (like the above mentioned Leiningen) to set up the classpath for you as soon as possible so you don't need to care about this yourself.

(As a side note, you might have to add more than just the src/ directory and your jars to the classpath in some scenarios, e.g. if you plan on calling compile to produce .class files, you'll have to put the target directory on the classpath too. That's beyond the scope of this question, though.)

BTW, I've started this answer with the word "normally", because you could also use things like load & in-ns to split a single namespace into multiple files. Most of the time this won't be what you really want to do, though; just use a well thought out namespace layout instead.

Michał Marczyk
You might also mention something about CLASSPATH, I think it's one of the more confusing bits for new users.
Brian Carper
@Brian: Thanks for the suggestion! It took me a while to realise you're referring to `$CLASSPATH`-the-environment-variable (which you are, aren't you? :-)), but I've edited the answer to include some info on it (adding in a few unrelated bits while I was at it).
Michał Marczyk