[racket] comments on html-template changes? (and preview of web-server integration)
Please let me know if you have any comments on the
non-backward-compatible changes I'm about to make to "html-template"
("http://www.neilvandyke.org/racket-html-template/")."
Most of the visible changes to the "html-template" syntax is completely
changing all the "%"-something parts of the template syntax, to be the
following:
* "(%xexp BODY ...)" and "(%sxml BODY ...)" -- BODY evaluates to an
SXML/xexp value, which is output as HTML in the appropriate context
(e.g., content context vs. attribute value context).
* "(%format BODY ...)" and "(% BODY ...)" -- BODY evaluates to some
value, and this value is formatted for appropriate literal display in
HTML. For example, a string value is displayed as text, an integer
value is displayed as a number, a date object is displayed as a date,
etc. The formatting handler is customizable by the application
programmer. Note that "(% BODY ...)" is changing purposes in the new
version of "html-template" -- it used to be like the new "%xexp", but
now it's a shorthand for "%format" instead.
* "(%verbatim BODY ...)" -- BODY evaluates to bytes, string, or a list
of byteses and/or strings, which are output verbatim as bytes.
* "(%void BODY ...)" -- BODY is evaluated, and any value is ignored.
This is presumably most useful for side-effects, when "#:ordering" is
"evaluation" or "writes-and-evaluation" (not "any").
* "(%write BODY ...)" -- BODY is evaluated, and any writes to
"current-output-port" are added verbatim to the output. Note that
"%write" and "%write/port" are the only "%"-somethings that permit
writing directly to a port the goes to HTML output. (I might even make
writing to current-output-port or current-error-port within a
"%"-something other than "%write" raise an error.)
* "(%write/port VAR BODY ...)" -- Like "%write", except that writing
must be to the output port VAR. Writing to current-output-port within
"%write/var" will raise an error, on the assumption that it's most
likely a bug (like a missing port parameter in a "display" or a nested
"html-template").
Note that there is no "%"-something shorthand for database queries,
iteration, etc. I've about decided that the "%"-something forms should
only be used for evaluating a block Racket code and determining what
happens with the value from that evaluation. Of course, it's possible
to create, say, an "html-template/db" syntax that layers over
"html-template". Or I could make the "%"-something handlers in
"html-template" extensible, but I currently see that as a low priority.
P.S., The examples below show the "response/html-template" form I've
been working on, for using "html-template" even more efficiently with
"web-server". This gives you an idea of what the current version of
"html-template" does, since it's not yet well-documented. If I go with
the above changes to "html-template", I'll probably refine "#:ordering"
to be sensitive to what "%"-somethings you're using, and default to an
appropriate ordering (and warn you if you're explicitly setting an
ordering that doesn't make sense for the "%"-somethings you're using).
I should also have an efficient way to *guarantee* that no output is
written until all dynamic parts are evaluated, for people who want to be
able to send an error response on an error, rather than a partial or
corrupted response (this already happens incidentally, depending on how
"#:ordering" is set, but that's conflating two different options that
people might want to specify separately).
P.P.S., "syntax/parse" is great.
Neil V.
;; No dynamic parts, literal #:code, no #:message.
(response/html-template
#:code 403
(html (body (p "Name: Voltron")
(p "Age: 29"))))
;;=expand=>
(response
403
#"Forbidden"
(current-seconds)
#"text/html; charset=utf-8"
(cons (make-header #"Content-Length" #"60") '())
(lambda (out)
(write-bytes
#"<html><body><p>Name: Voltron</p><p>Age: 29</p></body></html>"
out)))
;; No dynamic expressions except #:code, no #:message, literal #:preamble.
(response/html-template
#:code (some-code-proc)
#:preamble #"<!DOCTYPE html>\n"
(html (body (p "Name: Voltron")
(p "Age: 29"))))
;;=expand=>
(let ((code (some-code-proc)))
(response
code
(hash-ref %web-server-xexp:http-code-to-message-bytes-hash
code
#"Unknown Status Code")
(current-seconds)
#"text/html; charset=utf-8"
(cons (make-header #"Content-Length" #"76") '())
(lambda (out)
(write-bytes
#"<!DOCTYPE html>\n<html><body><p>Name: Voltron</p><p>Age:
29</p></body></html>"
out))))
;; Dynamic parts, #:ordering any, dynamic preamble.
(response/html-template
#:preamble (some-preamble-proc)
(html (body (p "Name: " (% (some-name-proc)))
(p "Age: " (% (some-age-proc)))))))))
;;=expand=>
(response/full
200
#"OK"
(current-seconds)
#"text/html; charset=utf-8"
'()
(list (some-preamble-proc)
#"<html><body><p>Name: "
(html->bytes (some-name-proc))
#"</p><p>Age: "
(html->bytes (some-age-proc))
#"</p></body></html>"))
;; Dynamic parts, #:ordering evaluation, literal preamble.
(response/html-template
#:ordering evaluation
#:preamble #"<!DOCTYPE html>\n"
(html (body (p "Name: " (% (some-name-proc)))
(p "Age: " (% (some-age-proc))))))
;;=expand=>
(let ((dynamic-0 (html->bytes (some-name-proc)))
(dynamic-1 (html->bytes (some-age-proc))))
(response/full
200
#"OK"
(current-seconds)
#"text/html; charset=utf-8"
'()
(list #"<!DOCTYPE html>\n<html><body><p>Name: "
dynamic-0
#"</p><p>Age: "
dynamic-1
#"</p></body></html>")))
;; Dynamic parts, #:ordering evaluation, dynamic preamble.
(response/html-template
#:ordering evaluation
#:preamble (some-preamble-proc)
(html (body (p "Name: " (% (some-name-proc)))
(p "Age: " (% (some-age-proc))))))
;;=expand=>
(let ((dynamic-0 (some-preamble-proc))
(dynamic-1 (html->bytes (some-name-proc)))
(dynamic-2 (html->bytes (some-age-proc))))
(response/full
200
#"OK"
(current-seconds)
#"text/html; charset=utf-8"
'()
(list dynamic-0
#"<html><body><p>Name: "
dynamic-1
#"</p><p>Age: "
dynamic-2
#"</p></body></html>")))
--
http://www.neilvandyke.org/