I'm dabbling in clojure and am having a little trouble trying to determine the clojure (and / or Lisp) equivalent of this common python idiom.
The idiom is that at the bottom of a python module there is often a bit of test code, and then a statement which runs the code, for example:
# mymodule.py class MyClass(object): """Main logic / code for the library lives here""" pass def _runTests(): # Code which tests various aspects of MyClass... mc = MyClass() # etc... assert 2 + 2 == 4 if __name__ == '__main__': _runTests()
This is useful for simple, ad-hoc testing. One would normally use this module by writing from mymodule import MyClass
, in which case _runTests()
is never called, but with the snippet at the end, one can also run it by typing python mymodule.py
directly from the command line.
Is there an equivalent idiom in Clojure (and/or common lisp)? I'm not after a full-blown unit testing library (well, I am, but not in this question), I'd just like to include some code in a module which will only be run under some circumstances, so I can have a quick way to run code I've been working on but still allow my file to be imported like a normal module / namespace.
It's not idiomatic to run Clojure scripts over and over from the command line. The REPL is a better command line. Clojure being a Lisp, it's common to fire up Clojure and leave the same instance running forever, and interact with it rather than restart it. You can change functions in the running instance one at a time, run them and poke them as needed. Escaping the tedious and slow traditional edit/compile/debug cycle is a great feature of Lisps.
You can easily write functions to do things like run unit tests, and just call those functions from the REPL whenever you want to run them and ignore them otherwise. It's common in Clojure to use clojure.contrib.test-is
, add your test functions to your namespace, then use clojure.contrib.test-is/run-tests
to run them all.
Another good reason not to run Clojure from the commandline is that the startup time of the JVM can be prohibitive.
If you really want to run a Clojure script from the command line, there are a bunch of ways you can do it. See the Clojure mailing list for some discussion.
One way is to test for the presence of command line arguments. Given this foo.clj
in the current directory:
(ns foo) (defn hello [x] (println "Hello," x)) (if *command-line-args* (hello "command line") (hello "REPL"))
You'll get different behavior depending how you start Clojure.
$ java -cp ~/path/to/clojure.jar:. clojure.main foo.clj -- Hello, command line $ java -cp ~/path/to/clojure.jar:. clojure.main Clojure 1.1.0-alpha-SNAPSHOT user=> (use 'foo) Hello, REPL nil user=>
See src/clj/clojure/main.clj
in the Clojure source if you want to see how this is working.
Another way is to compile your code into .class
files and invoke them from the Java command line. Given a source file foo.clj
:
(ns foo (:gen-class)) (defn hello [x] (println "Hello," x)) (defn -main [] (hello "command line"))
Make a directory to store the compiled .class
files; this defaults to ./classes
. You must make this folder yourself, Clojure won't create it. Also make sure you set $CLASSPATH
to include ./classes
and the directory with your source code; I'll assume foo.clj
is in the current directory. So from the command line:
$ mkdir classes $ java -cp ~/path/to/clojure.jar:./classes:. clojure.main Clojure 1.1.0-alpha-SNAPSHOT user=> (compile 'foo) foo
In the classes
directory you will now have a bunch of .class
files. To invoke your code from the command line (running the -main
function by default):
$ java -cp ~/path/to/clojure.jar:./classes foo Hello, command line.
There's a lot of information about compiling Clojure code on clojure.org.
I'm very new to Clojure but I think this discussion on the Clojure groups may be a solution and/or workaround, specifically the post by Stuart Sierra on April 17th at 10:40 PM.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With