Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the clojure equivalent of the Python idiom "if __name__ == '__main__'"?

Tags:

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.

like image 962
Tim Gilbert Avatar asked Jun 10 '09 00:06

Tim Gilbert


2 Answers

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.

like image 187
Brian Carper Avatar answered Oct 13 '22 01:10

Brian Carper


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.

like image 24
Brett Bim Avatar answered Oct 13 '22 00:10

Brett Bim