[racket] comments on html-template changes? (and preview of web-server integration)

From: Neil Van Dyke (neil at neilvandyke.org)
Date: Sun Mar 18 11:33:48 EDT 2012

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/

Posted on the users mailing list.