I have a collection of functions packaged into a Clojure library that I am working on for a bigger application. It occurred to me that many of these Clojure functions would be very useful if I could call them from my bash shell, not just from a REPL. I don’t care about the three second startup time of the JVM, and I don’t want to make a new jar for each little ‘application’ that I am making, since most of these are throw-away scripts or one-liners used for development purposes anyway. How can I start a JVM, load the appropriate libraries, and run a function that I want from the command line or a shell script?
The approach I took was to leverage leiningen to manage dependencies, start up the JVM, load appropriate libraries, and call the appropriate function.
You may be familiar with the acronym REPL, which stands for ‘Read Eval Print Loop”. For this type of task, what we really need is just a ‘Read Eval’ function defined somewhere, since we don’t want to loop. I wrote this stupid function, “Read-eval”, and threw it into one of my libraries.
(defn read-eval "Read and evaluate an expression contained in string." [string] (eval (read-string string)))
Assuming that I put that into the ‘mylib.util’ namespace, I then run this command in my bash shell:
$ lein run -m mylib.util/read-eval '(+ 1 2 3)' # Add numbers $ lein run -m mylib.util/read-eval "(mylib.math/std-dev [1 2 3])" # variance
If I need to type more than a one-liner, it’s easier just to use ‘load’:
$ echo "(+ 1 2 3)" > ~/test.clj $ lein run -m clojure.core/load-file ~/test.clj
It’s kind of neat how BASH replaces ‘~/’ with the proper home directory before sending it to leiningen.
Anyone got a better way of doing this?
October 21st, 2011 on 7:53 pm
Consider running a daemon webserver and sending requests to it via curl?
October 25th, 2011 on 6:31 pm
You should look into jark — it’s got a nailgun server that keeps clojure fired up all the time. Should be good for this sort of thing. http://icylisper.in/jark/