I don't write macros particularly often. I have never been in this situation, where I would like to defn a number of functions based on information known at compile time, from a vector. The use case is creating a wrapper lib in clojurescript for a JS library, where there are a number of methods on a JS object which I'd like to wrap with more idiomatic cljs functions.
Unlike clojure macro to generate functions this question hinges on the macro being called with a non-literal argument, which is passed into the macro as a form (not evaluated), which must then be evaluated before the macro can return a code form.
Below, the individual call to defevent works as expected, creating a function in the core ns for on-x. However, when called in the map, operating on events, a vector of keywords, it fails with:
WARNING: Use of undeclared Var foo.core/defevent at line 1 <cljs repl>
#object[TypeError TypeError: Cannot read property 'cljs$core$IFn$_invoke$arity$1' of undefined
I suspect this is because macros receive arguments as unevaluated forms, and somewhere in the map source, my defevent is called with a form more-or-less like (defevent (rest foo)) or somesuch... So how would I rewrite defevent, or the the (map defevent events) code to enable defn'ing functions based on the values in events?
macros.clj:
(ns foo.macros)
(defmacro defevent
[event-kw]
`(defn ~(symbol (str "on-" (name event-kw)))
[~'this ~'keyvec ~'cb]
(.call (aget ~'this ~(name event-kw))
~'this
~'keyvec
~'cb)))
core.cljs:
(ns foo.core
(:require-macros [foo.macros :refer [defevent]])
(defevent :x) ;; works
(def events [:a :b :c])
(doall (map defevent events)) ;; fails