Liking cljdoc? Tell your friends :D

defntly

A library that makes the creation of defn like macros in Clojure/Script a commodity.

The problem it addresses

Quite often in an mid size application, we need to apply some patterns to functions.

A pattern could be wrapping the body of a function in a try/catch or adding some instrumentation on this function.

One way to wrap the body of a function f is to create a high order function that wraps it. The code would probably looks like this:


(defn wrapper [f]
  (fn [& args]
     (try 
      (apply f args)
      (catch Throwable e
        (throw (Exception. (str "Exception caught in function " name ": " e))))
        
(defn foo [a b]
  (+ a b))

(def foo-wrapped (wrapper foo))

The major problem with this approach is that the code for foo-wrapped is distant from its effective body.

An attempt to solve this problem is to write foo as an anonymous function.

(defn foo [a b]
  (+ a b))

(def foo-wrapped (wrapper (fn [a b]
                             (+ a b))))

But then the expression that defines foo-wrapped is a def form which is a bit weird.

defntly addresses this issue by making it super easy to write a defn like macro.

For instance, with defntly you could create a defn-try macro and uses it exactly like defn:

(defn-try foo [a b]
    (+ a b))

Writing a defn-try macro is not an easy task if you want to support all the various ways to use defn: docstring, metadata, multi-arity...

With defntly, writing a defn like macro it becomes a commodity!

Usage

Leiningen/Boot: [viebel/defntly "0.0.1"]

Clojure CLI/deps.edn: viebel/defntly {:mvn/version "0.0.1"}

(require '[dfntly.core :refer [defn-update-body]])

Examples

Let's create a defn-try macro that automatically wraps the function body in a try/catch form.

(require '[dfntly.core :refer [defn-update-body]])

(defn wrap-try [name body]
  `((try ~@body
    (catch Throwable ~'e
      (throw (Exception. (str \"Exception caught in function \" ~name \": \" ~'e)))))))

(defmacro defn-try [& args]
  (defn-update-body wrap-try args))

We use defn-try exactly like defn:

(defn-try foo [a b]
    (+ a b))

is macroexpanded into:

 (defn foo [a b]
  (try
    (+ a b)
    (catch
      java.lang.Throwable
      e
      (throw (str "Exception caught in function " "foo" ": " e)))))

We can pass to our freshly created defn-try macro all the args that defn receive (metadata, docstring, multi arity).

For instance, a mutli arity function with a docstring like:

(defn-try foo
    "foo has a docstring"
    ([a] (foo a 42))
    ([a b] (+ a b)))

is macroexpanded into:

(defn foo
  "foo has a docstring"
  ([a]
    (try
      (foo a 42)
      (catch
        java.lang.Throwable
        e
        (throw (str "Exception caught in function " "foo" ": " e)))))
  ([a b]
    (try
      (+ a b)
      (catch
        java.lang.Throwable
        e
        (throw (str "Exception caught in function " "foo" ": " e))))))

How it works

Explanations about you the internals of defn-update-body and how it leverages clojure.spec in this article.

Can you improve this documentation?Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close