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 is a website building & hosting documentation for Clojure/Script libraries
× close