Setting Up a Command Line Clojure App
It’s tic-tac-toe time for me again, except this round will be in Clojure. Mike gave me the option of doing the app in either Joodo or on the command line, and since I’m working with Joodo for our internal project I decided to try out a command line app. There was just one problem, I had no idea how to create a Clojure command line app. The whole idea of compiling and using a JAR is pretty foreign to me and it’s one of those “basic” steps that most of the tutorials gloss over. I just kept coming across commands like this, without any idea what it did or how to get there:
java -cp lib/clojure.jar clojure.main main.clj
I asked around and surmised that this statement essentially tells the system to use java, and that the “classpath” (-cp) is in the ‘lib’ directory of this project, and then dig into the clojure JAR (java archive). Then with that jar you should have everything you need to run the “main” file.
This started to make sense, but before I went too far down a rabbit hole I came across Leiningen’s 'uberjar’ command and this post by Brad Lucas. Armed with these two resources I was able to create a very simple command line app up that used a 'runner’ file to run a class that greeted a user, asked for some input, and printed that input back out. So, here goes…
Create your project folder and call it something like “hello_clojure”. Inside of that create a file called 'project.clj’ and a directory called 'src’. The contents of your project.clj file will look like this:
(defproject helloworld "0.0"
:description "hello world application"
:dependencies [[org.clojure/clojure "1.4.0"]]
:main helloworld.runner
:java-source-path "src/")
You’ll note in the fourth line that we are explicitly declaring our :main
in the namespace helloworld.runner. You can call it anything you want, in which case you’d define main as :main helloworld.anything-you-want
.
Now, as long as you have Leiningen 2 installed, you can run 'lein deps’. This will install your dependencies and create a directory called 'target’ alongside your 'src’ directory and the project.clj file.
Next up, inside of your 'src’ directory create another directory called 'helloworld’ and inside that one create a file called 'runner.clj’. (To recap, this file officially resides at hello_clojure/src/helloworld/runner.clj). The contents of runner.clj will look like this:
(ns helloworld.runner
(:require [helloworld.welcome :refer [greeting]])
(:gen-class :main true))
(defn -main []
greeting)
The first line is the namespace for our file. The second is requiring the file and function that we will fire off our greeting. The third line says that this is in fact our main file (which we set up in project.clj). The last two lines define the 'main’ function.
Now we can create the greeting inside a file at 'hello_clojure/src/helloworld/welcome.clj’, and the contents look like this:
(ns helloworld.welcome)
(defn greeting []
(println "Hello from inside the app.")
(println "Enter a phrase: ")
(let [phrase (read-line)]
(println (str "You typed " phrase)))
(println "Goodbye."))
This function simply prints two opening lines, then uses the clojure.core 'read-line’ function to get some input, and then prints it back for the user.
Now it’s time to package and run our program. Make sure you are at the root directory of the 'hello_clojure’ project in your terminal and type 'lein uberjar’. The output should look something like this:
Created .../projects/hello_clojure/target/helloworld-0.0.jar
Including hello-world-0.0.jar
Including clojure-1.4.0.jar
Created .../projects/hello_clojure/target/helloworld-0.0-standalone.jar
All you need to do to run this app is type the following into your terminal:
java -jar target/helloworld-0.0-standalone.jar
And hopefully there you have it. When you are through your 'hello_clojure’ directory structure should look like the one below. If anyone has any problems or suggestions please let me know.