When Planck was first created, the primary purpose was to explore how quickly a bootstrapped ClojureScript REPL could be started on the desktop. But it was also clear that low-latency startup would be great for scripting.
With that in mind, some pragmatic aspects are being developed, specifically in support of scripting, outside of the normal use as a REPL.
All of the command line arguments that are supported by the regular Clojure REPL have been implemented. This lends great flexibility in how you start up Planck, having it load a ClojureScript file prior to anything else (
--init) or evaluate a form directly inline (
You can run a ClojureScript by specifying its path as the first argument to Planck, and you can even have Plank run CloureScript code that is read in via standard input (by passing in
- where you would normally specify a path to a file).
And, if your code is a bit more structured, you can call into a
-main entry point as is covered in ClojureScript Mainia.
#!/usr/local/bin/planck (println "Hello world!")
if you make the file executable then, voilà:
$ ./hello.cljs Hello world!
This works because the reader supports the
#! syntax as a comment specifically for this purpose. Woot!
In fact, your shebang scripts can use the full power of ClojureScript's namespace and dependency management. The following riff on ClojureScript Mainia works just fine:
#!/usr/local/bin/planck -c /path/to/src (ns calculate.core (:require [pythag.core :refer [dist]])) (println (dist 3 4))
Of course, if you need to pass arguments to your script,
--main is your friend.
spit, but what if you want to process more data than can fit into memory, or you want to write scripts that can participate in the Unix pipes architecture?
To that end, with the help of Ryan Fowler, Planck has been revised to support
$ planck cljs.user=> (require 'planck.io) nil cljs.user=> (planck.io/read-line) abc "abc" cljs.user=>
In the above, I typed
abc and hit return after calling
read-line, and it returned the string
Given this primitive, let's see if we can write the equivalent of a classic “count distinct lines” pipeline:
cat /etc/services | sort | uniq | wc -l 13697
First, let me create a little helper function in
src/helper/core.cljs to generate a line sequence using
(ns helper.core (:require planck.io)) (defn line-seq  (take-while identity (repeatedly planck.io/read-line)))
Then it is simple to write equivalents of
wc -l in terms of the core
#!/usr/local/bin/planck (ns sort.core (:require helper.core)) (run! println (sort (helper.core/line-seq)))
#!/usr/local/bin/planck (ns uniq.core (:require helper.core)) (run! println (dedupe (helper.core/line-seq)))
#!/usr/local/bin/planck (ns wc-l.core (:require helper.core)) (println (count (helper.core/line-seq)))
Now you can construct the pipeline:
cat /etc/services | ./sort.cljs | ./uniq.cljs | ./wc_l.cljs 13697
Of course, there is much more you can typically do with scripts. I'm thinking that porting more of Clojure's I/O facilities and a port of
clojure.java.sh would be very useful.