ruricolist/spinneret

composing html with macros

boogsbunny opened this issue · 4 comments

I'm still wrapping around my head composing macros correctly including order of evaluation, so I would appreciate your input here please. For example, I have this code:

(defclass accordion-component (component)
  ((trigger :accessor trigger
            :initarg :trigger
            :initform "")
   (content :accessor content
            :initarg :content
            :initform "")))

(defmethod render-html ((accordion accordion-component))
  (with-slots (trigger content) accordion
    (check-type trigger string)
    (spinneret:with-html
             (:div
              (:h3 (:button (:span trigger)))
              (:div content)))))

(defmacro accordion (&rest slots)
  `(let ((accordion (make-instance 'accordion-component ,@slots)))
     (render-html accordion)))

and I'd like to be able to call accordion like so:

(spinneret:with-html-string (accordion :trigger "what" :content (:p "this is it")))

where trigger is just a string and content would be some spinneret code.

How would I go on about just placing that content inside the div correctly?

The current output is this:

<p>this is it
<div>
 <h3>
  <button><span>what</span></button>
 </h3>
 <div>
 </div>
</div>

but I'm looking for this:

<div>
 <h3>
  <button><span>what</span></button>
 </h3>
 <div>
  <p>this is it
 </div>
</div>

I came up with this solution, though I'm not sure if it's bad practice to use eval?

(defmethod render-html ((accordion accordion-component))
  (with-slots (trigger content) accordion
    (check-type trigger string)
    (eval `(spinneret:with-html
             (:div
              (:h3 (:button (:span ,trigger)))
              (:div ,content))))))

(spinneret:with-html-string (accordion :trigger "what" :content '(:p "hi")))

I haven't had the chance to look over your question in detail, but I'm sure we can do better than eval. There is a section in the README on how to use deftag to solve order-of-evaluation issues; that might be helpful.

Yeah, I see that. I actually don't care about defining a particular tag here per se.

I just want to be able to call the accordion macro, place arbitrary html inside the spinneret:with-html macro, and get the evaluation back.

Curious to hear what you think is best practices when you get a chance to look over this!

It seems this exact challenge came up before and has been resolved with interpret-html-tree.

It seems that I initially skipped over the documentation here because I somehow didn't make the connection to how that would solve my problem.

Thank you so much!