[plt-scheme] Formlets in PLT

From: Jay McCarthy (jay.mccarthy at gmail.com)
Date: Tue Sep 16 18:59:22 EDT 2008

The Links group has created formlets:

http://groups.inf.ed.ac.uk/links/formlets/

I have spent the afternoon implementing formlets in PLT.
--

In the latest SVN, there is a web-server/formlets directory with a
'formlets' module.

Here is a simple example:

==== Define some basic functions & structures

#lang scheme
(require web-server/formlets/formlets)

(define-struct date (month day))
(define (date->xml d)
  (format "~a/~a"
          (date-month d)
          (date-day d)))

(define (submit t)
  `(input ([type "submit"]) ,t))

==== Now for the first formlet:

(define date-formlet
  (formlet
   (div
    "Month:" ,{input-int . => . month}
    "Day:" ,{input-int . => . day})
   (make-date month day)))

==== The first part is the display of the formlet, the second is how
it should be processed. The => syntax tells the formlet macro that
month and day should be bound in the processor as the result of
inputing integers.

(formlet-display date-formlet)

==== Displaying this formlet returns the following xexpr forest (list):

((div () "Month:" (input ((name "input_0"))) "Day:" (input ((name "input_1")))))

==== The input names are automatically generated.

==== Formlets can be composed:

(define travel-formlet
  (formlet
   (#%#
    "Name:" ,{input-string . => . name}
    (div
     "Arrive:" ,{date-formlet . => . arrive}
     "Depart:" ,{date-formlet . => . depart})
    ,@(list "1" "2" "3")
    ,(submit "Submit"))
   (list name arrive depart)))

==== The #%# is to note an xexpr forest. Notice that date-formlet is
used to embed the date formlet twice in the travel formlet. The
display portion of a formlet is implicitly in a quasiquote, so ,@ and
, work as before.

(formlet-display travel-formlet)

==== The travel formlet is displayed as follows:

("Name:"
 (input ((name "input_0")))
 (div
  ()
  "Arrive:"
  (div () "Month:" (input ((name "input_1"))) "Day:" (input ((name "input_2"))))
  "Depart:"
  (div () "Month:" (input ((name "input_3"))) "Day:" (input ((name
"input_4")))))
 "1"
 "2"
 "3"
 (input ((type "submit")) "Submit"))

==== Notice the input names are guaranteed to not conflict.

==== Let's embed this formlet into a web page that does the following
with the result:

(define display-itinernary
  (match-lambda
    [(list name arrive depart)
     `(html
       (head (title "Itinerary"))
       (body
        "Itinerary for: " ,name
        "Arriving:" ,(date->xml arrive)
        "Departing:" ,(date->xml depart)))]))

==== This provides send/formlet, which wraps a formlet in send/suspend
(require web-server/formlets/servlet)

(define (start request)
  (display-itinernary
   (send/formlet
    travel-formlet)))

==== embed-formlet is also available to put a formlet inside of
send/suspend/dispatch

--

Currently formlet combinators are provided for input-string,
input-integer, and input-symbol. More will come as the library is
used. I also plan on working on input validation, etc.

Jay

-- 
Jay McCarthy <jay at cs.byu.edu>
Assistant Professor / Brigham Young University
http://jay.teammccarthy.org

"The glory of God is Intelligence" - D&C 93


Posted on the users mailing list.