Checkout Ring Adapter for Jetty 9

The Clojure world has been using Jetty 7 for quite a long time because it’s supported by the Ring development team. However, Jetty 9 brings us exciting features like WebSocket and SPDY. In order to use websocket in my Clojure web application, I built this adapter last weekend.

[info.sunng/ring-jetty9-adapter "0.1.0"]

The API for Clojure is still consistent with the one for jetty 7.

(use 'ring.adapter.jetty9)
(run-jetty app {})

Options supported in jetty 9 are almost same as jetty 7 except the configurator is dropped. And a new “WebSockets” option is added. Accepting a map of context path and websocket class, it enables websocket protocol in your web application.

(use 'ring.adapter.jetty9)
(run-jetty app {:websockets {"/loc" LocationTracker}})

Due to the lack of WebSocket API standards, I don’t spend time on the WebSocket abstraction. Just use Jetty’s internal API for websocket. Here is a typical implementation of websocket listener.

;; sample code
(ns xxx.ws.location
  (:gen-class
   :name xxx.LocationTracker
   :init init
   :state state
   :extends org.eclipse.jetty.websocket.api.WebSocketAdapter
   :prefix ws-
   :exposes-methods {onWebSocketConnect superOnWebSocketConnect})
  (:require [clojure.data.json :as json]
            [clojure.tools.logging :as logging]
            [monger.collection :as mc])
  (:import (org.eclipse.jetty.websocket.api WebSocketAdapter)
           (java.util UUID)))

(defn ws-init []
  [[] {:client-id (str (UUID/randomUUID))}])

(defn ws-onWebSocketConnect [this session]
  (.superOnWebSocketConnect this session)
  (logging/warn "new connection: " (get-client-id this))

(defn ws-onWebSocketText [this message]
  (let [msg (json/read-json message)]
    (case (:type msg)
      ...)))

(defn ws-onWebSocketClose [this status reason]
  (logging/debug "close socket"))

Since Jetty will create new instance of adapter for each connection, it requires heavy usage of “gen-class” . Remember to add the namespace to AOT compilation. Detailed Jetty API spec can be found here.

And also find the project is here.

[ANN] Handlebars Clojure API

The ONLY real-world modern clojure templating system.
I just can’t believe that the clojure world doesn’t build web application with server-side template.
hiccup and enlive are neither **real-world**. So people tends to use single page architecture for a clojure backend. That’s PAINFUL.

Available on clojars [hbs "0.4.1"], code and docs on github. We have been using hbs on readwise.net for a long time.

Adding -var-missing to Clojure Namespace

Motivation

I Just need some mechanism like “methondMissing” in Ruby. When a nonexistent var is called, the lookup system will try to call a “-var-missing” function in the namespace. This function should return a var and clojure compiler assumes this var as the one it was looking for.

For example, in the shake library:

(ns shake.core)

(defn -var-missing [sym]
  (create-executable-var sym))

To support lazy loading, shake 0.3.0 won’t read your path. It will now create vars on demand. So on calling sh/uname, a var named `uname` will be created. And to create a var, just use intern or eval.

(require '[shake.core :as sh])
(sh/uname -a)

How to

I’m sorry there is no way to implement this except hacking into Clojure’s compiler. Fortunately, it’s not too difficult to find out the injection point.

As you may know, there are two phases in Clojure compiler: expanding macros and evaluating forms. Both phases will look up vars to find macros or values. So we should take care both of them.

All code diff is here:

Conclusion

Adding -var-missing is just an attempt to implement lazy loading of vars. And it provides another smooth syntax for writing DSLs. But actually, Clojure’s macro system provides a great metaprogramming mechanism. So in most case, you don’t have to hack into the Compiler like this. Just put your DSL into a top level macro, and you can get them done all in clojure scripts.

New shake syntax

As shake goes public, I received a lot of feedback. The top issue is about using clojure variables in shake macros. Now it has been fixed in 0.2.2. Let me show you the new syntax.

Using vars, local bindings in shake macros:

(require '[shake.core :as sh])

(let [x "/home/nsun"]
  (sh/ls -l $x))

So you have to prefix the clojure variable with a dollar sign. This is quite similar to what we did in shell programming.

And more interesting, you can also use a $ prefixed clojure form in shake:

(sh/curl $(format "https://github.com/%s" "sunng87"))

Thanks to Clojure macro system, it has great flexibility to manipulate symbols and code lists, making inventing new syntax much easier than other languages. Shake can be a great example in describing macro system.

Shake: Every Program Can Be a Clojure Function

You might have heard of sh, which brings python an interface to call subprocesses. The API of sh is pretty cool: Every command can be treated as a python function, and imported from a namespace. Options and arguments are passed in as python string.

But I think in Clojure, things can be even cooler. We dynamically create symbols for every program. We will have a beautiful DSL so you don’t have to quote arguments as string. So when you are using this library, it may look like:

(ls)
(uname -a)
(ip -4 addr)

And actually it’s just like that! I create this library called shake. When you load `shake.core`, it indexes all the executables in your path. Then all programs are available to you in a clojure native way.

(use 'shake.core)
(uname -a) ;; returns a java.lang.Process, that you can send data, read data and wait for termination.

;; for those just need output
(alter-var-root *print-outpt* (fn [_] true))
(uname -a)
;; it prints ...

There’s a lot of fun in implementing this library. First, to be able to use custom symbol in the DSL, you have to make these executables as macros. Second, find a way to programmably create vars which are named by string. The power of Clojure enables all the ideas and makes it possible. Check out the source code if you are interested in: https://github.com/sunng87/shake/.