Building a Clojure app with a command-line interface?
ClojureClojure ContribClojure Problem Overview
I just started w/ Clojure (coming from Ruby) and I would like to build an small app with a command-line interface. How do I handle input/output to a CL?
I noticed that there is a clojure.contrib.command-line, but documentation is slim.
Clojure Solutions
Solution 1 - Clojure
Here is an example of using its with-command-line
macro. The following code specifies a trivial class with a main method that does nothing but print out the values of its command line arguments.
(ns cmd-line-demo
(:gen-class)
(:use clojure.contrib.command-line))
(defn -main [& args]
(with-command-line args
"Command line demo"
[[foo "This is the description for foo" 1]
[bar "This is the description for bar" 2]
[boolean? b? "This is a boolean flag."]
remaining]
(println "foo: " foo)
(println "bar: " bar)
(println "boolean?: " boolean?)
(println "remaining: " remaining)))
Compile the class at the REPL:
user> (compile 'cmd-line-demo)
cmd-line-demo
Example usage
-
Executing with no command line arguments will cause the help info to be displayed. The help info can also be displayed with
--help
or-h
flags. Note that the help info is automatically generated from your cmdspec.$ java -classpath . cmd_line_demo Command line demo Options --foo
This is the description for foo [default 1] --bar This is the description for bar [default 2] --boolean, -b This is a boolean flag. -
Unspecified arguments receive the default value as specified in the cmdspec binding. For example,
bar
has a default value of2
.$ java -classpath . cmd_line_demo --foo "changed value" foo: changed value bar: 2 boolean?: nil remaining: []
-
Boolean flags are denoted by the suffix "?" in the cmdspec. Note that the flag itself does not include the "?" as part of its name.
$ java -classpath . cmd_line_demo -boolean foo: 1 bar: 2 boolean?: true remaining: []
-
Also note that you may specify flag aliases by specifying multiple symbols in the cmdspec. I have done this with the
boolean?
andb?
flags. -
Finally, I've specified that
remaining
capture all remaining arguments without associated flags.$ java -classpath . cmd_line_demo -foo test file1 file2 file3 foo: test bar: 2 boolean?: nil remaining: [file1 file2 file3]
Solution 2 - Clojure
The old clojure.contrib.command-line has been replaced with tools.cli.
https://github.com/clojure/tools.cli
tools.cli used to be called clargon. Below are two blog posts that give examples of using tools.cli (simple replace any reference to clargon with tools.cli. Posts are out of date).
This shows a few methods ways, including old clojure.contrib.command-line
Solution 3 - Clojure
I'd like to add that you can do
(apply -main *command-line-args*)
below the (defn -main ...)
to make it work in interpreted mode.
Solution 4 - Clojure
Long time after the question was raised I can suggest to use docopt
libraries when it comes to build CLI interface. There is one for Clojure - docopt.clj
> docopt is based on conventions that are used for decades in help messages and man pages for program interface description. Interface description in docopt is such a help message, but formalized
So you can declare your interface and document it in the same time - that is amazing and easy to do.
For more details I recommend to check http://docopt.org/
Also there is a online app to check your interface http://try.docopt.org/
And finally here is my example how the Clojure lib can be used.
Solution 5 - Clojure
Maybe try jark. Jark is a tool to run clojure programs on a persistent JVM. It has some useful command-line utilities.
jark ns load file.clj
jark <namespace>.<function> <args>
jark if cli-json <namespace><function> args