Dear Clojurians,

I found the following procedure quite useful when
including Tom Faulhaber's cl-format in VimClojure.

I didn't want to depend on it, so I decided to provide
the functionality optionally: if the cl-format.jar is
available use it, otherwise use some sensible default.

The following layout is used by Chouser in clojure.contrib
but should deserve some more spotlight.

To include the functionality I started with providing
some facade which also implements the defaults


(defn pretty-print
"Print the given form in a pretty way. If Tom Faulhaber's pretty printer is
  not installed simply defaults prn."
  [form]
  (prn form))

(defn pretty-print-code
"Print the given form in a pretty way. If Tom Faulhaber's pretty printer is not installed simply defaults prn. Uses the *code-dispatch* formatting."
  [form]
  (prn form))


These functions are pretty straight forward. They
provide the interface used in VimClojure and default
to prn.

Now we have to load the cl-format library. The problem
is, that if the library is not available this will throw an
exception at compile time. So wrapping the require
in try will not help. Here comes Chouser's trick: put the
require in another file and load this file. Using this
technique we can simply catch the Exception, check
with some Voodoo heuristic whether it was because
of the missing jar and re-throw otherwise.


(try
  (load "optional/cl-format")
  (catch Exception exc
    (when-not (re-find #"com/infolace/format__init" (str exc))
      (throw exc))))


In the optional/cl-format.clj file, we finally interface to
the optional library. We require the library and replace
the facade functions we defined before.


(require '[com.infolace.format :as cl-format])

(defoptional pretty-print
  [form]
  (cl-format/pprint form))

(defoptional pretty-print-code
   [form]
   (cl-format/with-pprint-dispatch cl-format/*code-dispatch*
     (cl-format/pprint form)))


To save some work I defined a small helper macro,
which transfers the docstring from the default
implementation to the re-definition.

(defmacro defoptional
  [sym args & body]
  `(let [docstring# (:doc (meta (var ~sym)))]
     (defn ~sym ~args ~...@body)
     (alter-meta! (var ~sym) assoc :doc docstring#)))


Now we have a completely optional dependency
on an external library. In case it's there, it will be
used. Otherwise the system falls back transparently
to the default implementation.

Maybe you find this useful.

Sincerely
Meikel

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to