A library that makes the creation of defn like macros in Clojure/Script a commodity.
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!
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]])
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))))))
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 builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |