This is an HTML generator. This library is similar to cl-who or spinneret, but with two interesting differences.
The first distinction is that print-html
is written in the literate
programmings style and have very succinct code which can be read in 5-10
minutes.
The second distinction is that print-html
is based on generics and you can
define a method to print some classes into HTML.
Let’s try this!
POFTHEDAY> (print-html:print-html-to-string
(print-html:html
(:article
((:section :class "intro")
(:p "Hello Lisp World!")))))
"<article>
<section class=\"intro\">
<p>Hello Lisp World!</p>
</section>
</article>
"
Now I’ll create a class of user which can be serialized into HTML:
;; This is our buisiness logic:
POFTHEDAY> (defclass user ()
((name :initarg :name
:reader get-name)))
POFTHEDAY> (defparameter *user*
(make-instance 'user
:name "Sponge Bob"))
POFTHEDAY> (defun get-profile-uri (user)
(format nil "/user/~A"
(get-name user)))
;; Here is the method to transform business logic
;; object into its HTML representation.
POFTHEDAY> (defmethod print-html:render ((user user))
(print-html:html
((:a :href (get-profile-uri user))
(get-name user))))
;; Note, it returns HTML nodes, not
POFTHEDAY> (print-html:render *user*)
(#S(PRINT-HTML::TAG
:NAME :A
:ATTRS (:HREF "/user/Sponge Bob")
:CHILDREN ("Sponge Bob")))
;; Now we can use this kind of objects
;; directly when rendering HTML pages:
POFTHEDAY> (print-html:print-html-to-string
(print-html:html
(:article
((:section :class "intro")
(:p "Hello"
*user*)))))
"<article>
<section class=\"intro\">
<p>Hello
<a href=\"/user/Sponge Bob\">Sponge Bob</a>
</p>
</section>
</article>
"
Seems this is an interesting approach to render HTML. What do you think?
Added performance test to compare with other template renderers. Main post with comparison is here.
POFTHEDAY> (defun render (title items)
(print-html:print-html-to-string
(print-html:html
(:h1 title
(:ul
(loop for item in items
collect (print-html:html
(:li item))))))))
POFTHEDAY> (render "Foo Bar"
'("One" "Two" "Tree"))
"<h1>Foo Bar
<ul>
<li>One</li>
<li>Two</li>
<li>Tree</li>
</ul>
</h1>
"
POFTHEDAY> (time
(loop repeat 1000000
do (render "Foo Bar"
'("One" "Two" "Three"))))
Evaluation took:
3.259 seconds of real time
3.280993 seconds of total run time (3.226489 user, 0.054504 system)
[ Run times consist of 0.258 seconds GC time, and 3.023 seconds non-GC time. ]
100.68% CPU
7,195,206,822 processor cycles
2,560,006,112 bytes consed