ruricolist/spinneret

Functional version of `with-html`?

Closed this issue · 5 comments

I have a bunch of methods that produce HTML s-expressions for the specialized classes, e.g.

(defmethod object-expression ((progress-bar progress-bar))
  `(:div :class "progress-bar-base"
         (:div :class "progress-bar-fill"
               :id ,(id progress-bar)
               ;; empty string to force markup to make closing :div tag
               "")))

Then at the call site, I can do

(eval `(spinneret:with-html-string
           ,(object-expression element)))

but obviously the eval is not ideal here.

If spinneret:with-html-string were not a macro, that would not be a problem. Are we missing a functional version? Or is there a better way around this problem?

Normally I just write functions/methods using with-html, and let the (dynamically) surrounding with-html-string capture their output into a string.

I'm open to the possibility of adding an interpreter (it wouldn't be that hard given that we already support dynamic tags and attributes) but I don't see what's being done here that wouldn't work if the methods were writing to *html*.

A use case were the current macros don't seem to suffice: the HTML rendering of a tree.

A walker usually accepts a "collector" function as argument. This function takes 2 argument: the current node and the further results. But we can't spinneret:with-html here because it returns nil and we would lose the tree structure upon building the result.

Does that make sense?

If spinneret had a function that accepts s-exp, this problem would have a trivial solution.

I've added an experimental interpreter in the interpret-html-tree branch. This exports a function, interpret-html-tree, that interprets a subset of Spinneret syntax (building on existing support for dynamic tags and attributes).

If you want to give it a try and tell me how it works for you I can merge it.

I've tested and it seems to work perfectly, thanks!