Writing Leiningen Plugins 101
25 Feb 2010
I'm trying to switch, building my projects using Ant to leiningen. Almost all of them requires customs tasks such as building native executables, move files around etc. Which requires I have to come up with a lein plugin for each ant task, unfortunately not much documentation exists about writing lein plugins, this post collects bits and pieces of information I gathered over the web.
To begin with lein tasks are functions named "your-task" defined in the namespace "leiningen.your-task". They take a project argument containing information defined in defproject and command-line arguments. For simple tasks or quickly testing something, you can simply define them in project.clj after the defproject definition,
(ns leiningen.foo)
(defn foo [project & args] (println "Hello Foo!!"))
Now lein should have a new task named foo, running it should print "Hello Foo!!". Of course for longer tasks, you are not going to want it cluttering your project.clj, they can be placed under leiningen/ folder not src/leiningen/. Since tasks are just functions, making a task depend on another task is as easy as calling depencies on top of the function.
;;leiningen/bar.clj
(ns leiningen.bar)
(defn bar [projects & args]
(apply leiningen.foo/foo projects args)
(println "Hello Bar!!"))
Now running bar task should give you, "Hello Foo!!" and "Hello Bar!!". For sharing plugins across projects create a separate lein project for the plugin, after creating a Jar with "lein jar" you have two options, you can either push it to clojars and add your plugin as a dev-dependency for your project or just move the jar to the lib folder of the project, either way lein will pick it up.
Applescript with Clojure
21 Feb 2010
Today I was experimenting with AppleScript engine thats included with Java 1.6. It makes it much easier to interact with OS X then executing osascript using Runtime.
(let [mngr (javax.script.ScriptEngineManager.)
engine (.getEngineByName mngr "AppleScript")]
(.eval engine "say \"Hello World!\""))
For simple stuff, it is as simple as asking engine manager for the AppleScript engine and running eval on it with your script.
(def tracks (str "tell application \"iTunes\"\n"
"get count of tracks of (get view of front window)\n"
"end tell\n"))
(let [mngr (javax.script.ScriptEngineManager.)
engine (.getEngineByName mngr "AppleScript")]
(.eval engine tracks))
user=> 5229
When eval returns, numbers, strings, and dates are coerced into java.lang.Double, java.lang.String, and java.util.Calendar. Collections like lists and properties are recursively converted into java.util.Lists, and java.util.Maps. Unknown types are usually described as a string.
(def play (str "on playNamedList(thisName)\n"
"tell application \"iTunes\"\n"
"play playlist thisName\n"
"end tell\n"
"end playNamedList\n"))
(let [mngr (javax.script.ScriptEngineManager.)
engine (.getEngineByName mngr "AppleScript")
context (.getContext engine)
bindings (.getBindings context javax.script.ScriptContext/ENGINE_SCOPE)]
(.put bindings "javax_script_function", "playNamedList")
(.put bindings javax.script.ScriptEngine/ARGV "chill")
(.eval engine play))
In order to invoke calls that expects arguments to be set, we need to invoke the AppleScript method using "javax_script_function" engine binding. Overall it beats running osascript and parsing return values, but it still needs more documentation.
net-eval - Dead Simple Distributed Computing for Clojure
16 Feb 2010
newlisp has this function called net-eval which allows you to distribute work across a bunch of remote nodes. Over the weekend I have put together a small library, which more or less works the same way. The idea behind net-eval is simple, you fire up a REPL server on the remote nodes, expressions are transferred through a socket evaluated and results returned.
(deftask ping []
(str "Pong: " (System/getProperty "os.name")))
We begin by defining tasks for code we want to evaluate on the remote nodes, deftask macro takes the body, defines a function and adds body of the task as a list to the functions meta data. You can treat tasks as functions, call them debug them just like any other Clojure function.
(let [response (net-eval [["127.0.0.1" 9999 #'ping]
["10.211.55.3" 9999 #'ping]])]
(println (map deref response)))
net-eval does all the housekeeping required to connect to remote nodes, transfer functions to execute, and collect the results. net-eval takes a sequence of vectors containing host, port and a task to execute if there are arguments to be passed, they are appended to the end. net-eval will return a sequence of future objects, each containing response from one of the nodes.
(Pong: Mac OS X Pong: Windows 2000)
Now, care must be taken. It is not a good idea to have a REPL server listening on a public IP, you are basically giving away unrestricted shell access to anyone. I advise using net-eval behind a firewall or on a segregated network. If you really really need to run commands across the internet tunnel the connection through SSH.
A more useful example other than playing ping-pong with the remotes would be implementing poor man's MapReduce. Following snippet defines a task that will download a file, split it into words and count them, it maps a bunch of nodes to a bunch of documents and sends documents for processing, when all nodes return we sum the word count print total numbers words across documents.
(def docs [;; A Comedy of Masks - Ernest Dowson and Arthur Moore, 547KB
"http://www.gutenberg.org/files/16703/16703.txt"
;; The Adventures of Sherlock Holmes - Conan Doyle, 576KB
"http://www.gutenberg.org/dirs/etext99/advsh12.txt"
;; The tale of Beowulf - anonymous, 219KB
"http://www.gutenberg.org/files/20431/20431-8.txt"])
(def nodes [["127.0.0.1" 9999]
["127.0.0.1" 9999]
["10.211.55.3" 9999]])
(deftask word-count [doc]
(with-open
[stream (.openStream (java.net.URL. doc))]
(let [buf (java.io.BufferedReader.
(java.io.InputStreamReader. stream))]
(count (re-seq #"\w+" (.toLowerCase (apply str (line-seq buf))))))))
(defn map-jobs []
(map #(conj (first %) #'word-count (second %))
(partition 2 (interleave nodes docs))))
(let [response (map deref (net-eval (map-jobs)))]
(println "Total: " (apply + response)))
For processing large files, you can use compojure to transfer files across machines, if you build the library using lein, transferring uberjar to remote nodes is all thats needed, running uberjar will automatically start a REPL server.
A Simple Clojure IRC Client
10 Feb 2010
The other night I was toying with the following script, I was going to thrash it but figured it may help someone or me later on so I am dumping it here. It doesn't do anything other then to sit idle in a channel,
(ns irc
(:import (java.net Socket)
(java.io PrintWriter InputStreamReader BufferedReader)))
(def freenode {:name "irc.freenode.net" :port 6667})
(def user {:name "Nurullah Akkaya" :nick "nakkaya"})
(declare conn-handler)
(defn connect [server]
(let [socket (Socket. (:name server) (:port server))
in (BufferedReader. (InputStreamReader. (.getInputStream socket)))
out (PrintWriter. (.getOutputStream socket))
conn (ref {:in in :out out})]
(doto (Thread. #(conn-handler conn)) (.start))
conn))
(defn write [conn msg]
(doto (:out @conn)
(.println (str msg "\r"))
(.flush)))
(defn conn-handler [conn]
(while
(nil? (:exit @conn))
(let [msg (.readLine (:in @conn))]
(println msg)
(cond
(re-find #"^ERROR :Closing Link:" msg)
(dosync (alter conn merge {:exit true}))
(re-find #"^PING" msg)
(write conn (str "PONG " (re-find #":.*" msg)))))))
(defn login [conn user]
(write conn (str "NICK " (:nick user)))
(write conn (str "USER " (:nick user) " 0 * :" (:name user))))
;;(def irc (connect freenode))
;;(login irc user)
;;(write irc "JOIN #clojure")
;;(write irc "QUIT")
Lots of this code should be self-explanatory, calling connect will open a socket to the server, it will return a ref containing a reader and a writer associated with the socket, it will also spawn a new thread that will handle incoming messages from the server.
conn-handler will keep reading and printing from the socket until exit key in the conn ref is set which happens when we receive a "Closing Link" message from the server, every once in a while server will ping us with "PING :randomstring" we need to reply "PONG :randomstring" else we get disconnected. Thats all there is to it, as I said it doesn't do anything but with a few regexes you can turn it in to client or a bot.
Using Multiple Lisps with Inferior Lisp
07 Feb 2010
I was reading On Lisp which uses Common Lisp through out the book, so I needed a quick way to switch between lisps, following is a quick hack to switch between different lisp programs. When you call na-run-lisp without any prefix it will run the first item in lisp-programs, when called with a prefix you can select which lisp to run.
(setq lisp-programs
(list (list "clojure" clojure-command)
(list "sbcl" "/opt/local/bin/sbcl")))
(defun na-run-lisp (arg)
(interactive "P")
(if (null arg)
(run-lisp (second (first lisp-programs)))
(let (choice)
(setq choice (completing-read "Lisp: " (mapcar 'first lisp-programs)))
(dolist (l lisp-programs)
(if (string= (first l) choice)
(run-lisp (second l)))))))
Etch A Sketch
02 Feb 2010

A small Sunday hack inspired by the classical children's toy, for this project you need two potentiometers, connected to analog pins 0 and 1, you can grab the fritzing file here,

Idea behind the project is simple, we read potentiometers, turn the values read into x and y coordinates for the turtle then command turtle to go to that coordinate.
;;WMath.cpp
(defn map-range [x in-min in-max out-min out-max]
(+ (/ (* (- x in-min) (- out-max out-min)) (- in-max in-min)) out-min))
(defn read-knobs [board]
(let [potx (analog-read board potx-pin)
poty (analog-read board poty-pin)
x (int (map-range
potx 0 1024 (- (/ sketch-width 2)) (/ sketch-width 2)))
y (int (map-range
poty 0 1024 (- (/ sketch-height 2)) (/ sketch-height 2)))]
{:x x :y y}))
Potentiometers returns values between 0 and 1024, assuming our image is 600 by 400, we need to map these values between -300 to 300 on the x axis and -200 to 200 on the y axis, 0,0 being the center of the image.
(defn panel [board turtle]
(proxy [JPanel ActionListener] []
(paintComponent
[g]
(doto g
(.setColor Color/red)
(.fill (RoundRectangle2D$Double.
0 0 window-width window-height 60 60))
(.setColor Color/black)
(.drawImage (:image @turtle) pad pad this)
(.setColor Color/white)
(.fill (Ellipse2D$Double. pad 430 40 40))
(.fill (Ellipse2D$Double. (- sketch-width pad) 430 40 40))))
(actionPerformed
[e]
(let [knobs (read-knobs board)]
(go turtle (:x knobs) (:y knobs)))
(.repaint this))))
With every tick of the timer, we'll read the potentiometers, then command the turtle to goto that position and repaint the panel to reflect changes.
(defn key-listener [board frame timer]
(proxy [KeyAdapter] []
(keyReleased
[e]
(.stop timer)
(close board)
(.setVisible frame false))))
When the sketch window receives a key event, we stop the timer, disconnect arduino and hide the window.
(defn init-arduino []
(let [board (arduino "/dev/tty.usbserial-A6008nhh")]
(Thread/sleep 5000)
(enable-pin board :analog potx-pin)
(enable-pin board :analog poty-pin)
board))
By default pins aren't read, you need to tell arduino which ports you are interested, in this case we are interested in analog 0 and analog 1.
(defn init-turtle [board turtle]
(let [knobs (read-knobs board)]
(doto turtle
(pen-up)
(go (:x knobs) (:y knobs))
(pen-down))))
Since we don't know the position of potentiometers when the application starts, we need to read the values once and position the turtle accordingly. When all the functions wired and timer started, you should have your Etch A Sketch.
(defn sketch []
(let [board (init-arduino)
turtle (turtle sketch-width sketch-height)
panel (panel board turtle)
timer (Timer. 50 panel)
window (JFrame.)]
(doto window
(.add panel)
(.addKeyListener (key-listener board window timer))
(.setBackground (Color. 0 0 0 0))
(.setUndecorated true)
(.setAlwaysOnTop true)
(.setSize (java.awt.Dimension. window-width (+ 25 window-height)))
(.setVisible true))
(init-turtle board turtle)
(.start timer)))