Reputation: 40500
I've created a macro whose definition looks like this:
(defmacro my-macro
[strategy & body]
...)
You can call this macro like this:
(my-macro {:strategy "some"}
(do-something ..))
Now I'd like the macro to optionally accept bindings. Something like this:
(my-macro [my-value (load-value ..)]
{:strategy my-value}
(do-something ..))
So I've tried extending the macro to look like this:
(defmacro my-macro
([strategy & body] `(my-macro [] ~routes ~body))
([bindings strategy & body]
...))
But this fails with:
java.lang.RuntimeException: Can't have more than 1 variadic overload
Is there a good way to workaround this or what's the recommended approach?
Upvotes: 2
Views: 876
Reputation: 17859
i would propose this one:
(defmacro my-macro
{:arglists '([bindings? strategy & body])}
[bindings-or-strategy & more-args]
(let [[bindings strategy body] (if (vector? bindings-or-strategy)
[bindings-or-strategy
(first more-args)
(rest more-args)]
[[] bindings-or-strategy more-args])]
`(let ~bindings
(println :strategy ~strategy)
~@body)))
user> (my-macro [a 1] {:aaa :bbb} a)
:strategy {:aaa :bbb}
1
user> (my-macro {:aaa :bbb} 10)
:strategy {:aaa :bbb}
10
although it looks more verbose than @superkonduktr's answer, to me it seems to be more usable: it ensures that at least one argument is passed, and also documents the usage of this macro with :arglists
Upvotes: 3
Reputation: 655
My typical workaround would be to just examine the entire list of arguments passed to my-macro
and decide whether to use bindings or not:
(defmacro my-macro
[& body]
(let [bindings (if (vector? (first body)) (first body) [])
[strategy body*] (if (seq bindings) (rest body) body)]
`(let ~bindings
(do-something-with ~body* ~strategy))))
Upvotes: 4