Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use `clojure.tools.macro/name-with-attributes`?

Tags:

macros

clojure

I see what promises to be a nifty tool for anybody writing defn-like macros in the clojure.tools.macro library: the name-with-attributes function. The docstring says:

To be used in macro definitions. Handles optional docstrings and attribute maps for a name to be defined in a list of macro arguments. If the first macro argument is a string, it is added as a docstring to name and removed from the macro argument list. If afterwards the first macro argument is a map, its entries are added to the name's metadata map and the map is removed from the macro argument list. The return value is a vector containing the name with its extended metadata map and the list of unprocessed macro arguments.

But I can't seem to find an example that uses this function anywhere.

So, how can I use this function to define, say, a defn2 macro, which should be a clone of clojure.core/defn that contains all the same features, including:

  • docstrings
  • attribute maps
  • preconditions
  • multi-arities
like image 361
Jeff Terrell Ph.D. Avatar asked Aug 25 '14 02:08

Jeff Terrell Ph.D.


1 Answers

Here is defn2:

(require '[clojure.tools.macro :as ctm])

(defmacro defn2
  "A clone of `defn`."
  [symb & defn-args]
  (let [[symb body] (ctm/name-with-attributes symb defn-args)]
    `(defn ~symb ~@body)))

Looking at the metadata we can see that it gets properly attached:

(defn2 ^:private add
       "Docstring"
       ([] :foo)
       ([a b] {:pre [(= 1 1)]} (+ a b)))

(pprint (meta #'add))

...yields:

{:arglists ([] [a b]),
 :ns #<Namespace user>,
 :name add,
 :column 1,
 :private true,
 :doc "Docstring",
 :line 1,
 :file
 "/private/var/folders/30/v73zyld1359d7jb2xtlc_kjm0000gn/T/form-init8938188655190399857.clj"}

Using defn2 above created an add function that works like so:

(add)     ; => :foo
(add 1 2) ; => 3
like image 94
3 revs, 2 users 58% Avatar answered Oct 14 '22 16:10

3 revs, 2 users 58%