Hi Thomas - yes, you are right. The example I provided is all pain/no-gain in 
terms of macros. However, future plans will require manipulating the invocation 
of (for example form/text and form/number) before they are evaluated.

Having said all of that, that repeated ‘form’ does bug me a bit :-). I do 
absolutely agree that the cognitive overhead of the macro isn’t justified here.

> On 2 Oct 2015, at 14:29, Thomas Heller <th.hel...@gmail.com> wrote:
> 
> Have you tried NOT using a macro at all? This code does not need to be a 
> macro at all if you ask me.
> 
> Just a little sketch but things could look just about the same without any 
> macros at all:
> 
> (let [form {:editing? true
>             :values form-values
>             :validation validation-report
>             :on-change handle-form-change}]
>   (form/tag form
>     (form/text form :name)
>     (form/number form :age)))
> 
> 
> ;; in-ns 'form
> 
> (defn text [form field]
>   [text-component {:id field
>                    :value (get-in form [:values field])
>                    ...}])
> 
> (defn tag
>   [{:keys [editing?] :as form} & children]
>   (into [:div.form.horizontal
>          {:class (if editing? "editing" "editable")}]
>         children))
> 
> 
> Use macros very sparingly, most of the time data and functions are just 
> better.
> 
> Just my 2 cents,
> /thomas
> 
> On Wednesday, September 30, 2015 at 10:29:30 PM UTC+2, Colin Yates wrote:
> Hi all,
> 
> I am banging my head against the wall - I think it is obvious but I have 
> started too long:
> 
> The use-case is that I want a form which takes a set of children. The form 
> also takes in some form-wide state, like the form-wide validation, the values 
> for each item etc. I want the macro, for each child, to decorate that child 
> by extracting the validation errors and value from the form-wide state.
> 
> So, assuming:
>  - validation looks like {:name "Duplicate name" :age "You must be at least 
> 0"}
>  - form-values looks like {:name "a-duplicate-user" :age -1}
> 
> then my form might look like:
> 
> (form {:editing? true :values form-values :validation validation-report 
> :on-change handle-form-change}
>   [form/text {:id :name}]
>   [form/number {:id :age}])
> 
> After the macro I want the following code:
> 
> [:div.form.horizontal
>   {:class "editing"}
>   [form/text {:id :name :value "a-duplicate-user" :errors "Duplicate name" 
> :on-click (fn [e] (handle-form-change :name (-> e .target .value])]
>   [form/number {:id :age :value "-1" :errors "You must be at least 0" 
> :on-click (fn [e] (handle-form-change :age (-> e .target .value))]]
> 
> However, ideally the macro would _not_ emit the contents of the input as 
> literals but would emit code that inspects the provided parameters at 
> run-time (i.e. rather than :value "a-duplicate-user" I would much prefer 
> :value (-> state values :name) as that will allow me to pass in an atom for 
> example.
> 
> I have tried so many variations and evaluating the state (e.g. (:editing? 
> state)) works fine as the emitted code has the destructured values, but that 
> doesn't work for an atom.
> 
> Here is my attempt at trying to emit code that interrogates the provided 
> parameter.
> 
> (defmacro form [state & elements]
>   (let [state# state]
>     `[:div.form.horizontal
>       {:class (if (:editing? state#) "editing" "editable")}
>       ~@(map (fn [[_ {:keys [id]} :as child]]
>                (update child 1 assoc
>                        :editing? (:editing? state#)
>                        :value `(-> (:values state#) 'deref (get ~id))
>                        :on-change `(fn [e#]
>                                      (js/console.log "E: " (cljs.core/clj->js 
> e#))
>                                      ((:on-change state#) ~id (-> e# .-target 
> .-value)))))
>              elements)]))
> 
> The error I am getting is that there is such var as the gen-sym's state# in 
> the namespace.
> 
> The generic thing I am trying to do is remove the boilerplate from each of 
> the items in the form.
> 
> Any and all suggestions are welcome. 
> 
> Thanks!
> 
> -- 
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your 
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en 
> <http://groups.google.com/group/clojure?hl=en>
> --- 
> You received this message because you are subscribed to the Google Groups 
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to clojure+unsubscr...@googlegroups.com 
> <mailto:clojure+unsubscr...@googlegroups.com>.
> For more options, visit https://groups.google.com/d/optout 
> <https://groups.google.com/d/optout>.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to