For my HTTP server project I want the option of configuring it on the command line for at least the port, document root and potentially IP to listen on (or all). I came across Building a Clojure app with a command-line interface? on StackOverflow which informed me that clojure.tools.cli was the right path to take over the with-commmand-line.
Here is an example of using clojure/tools-cli which revealed some Clojure syntax I’d overlooked (more on that later):
1 2 3 4 5 6 7 8 9 10 11 (ns server.core (:gen-class) (:require [clojure.tools.cli :as c])) (defn -main [& args] (let [[options args banner] (c/cli args ["-port" "Port to listen on" :default 5000] ["-root" "Root directory of web server" :default "public"])] (println "port:" (:port options)) (println "root:" (:root options))))
options is a hash-map of the parsed options
args is the other arguments on the command line
banneris a string one can print for command line options – for this program, it would contain:
Switches Default Desc ——– ——- —- -port 5000 Port to listen on -root public Root directory of web server
Note that tools.cli throws an exception when an unrecognized command line option is provided like so:
1 2 Exception in thread "main" java.lang.RuntimeException: java.lang.Exception: '-z' is not a valid argument
I guessed it would default to showing the banner it generates but it does not do so.
Basic Clojure Syntax I wasn’t aware one could take a returned vector and assign its contents to multiple variables with let as done in this line from above:
1 (let [[options args banner] ...
In a prior post, I explained how I was passing back a response to an HTTP request as a hash-map of hash-maps. This can start to get confusing and I think the approach used above can make this simpler – instead of a hash-map of hash-maps consider returning a vector of hash-maps.