Adding formlets
svn: r11782
This commit is contained in:
parent
6d228898ee
commit
b1a0d785ba
63
collects/web-server/formlets/date.ss
Normal file
63
collects/web-server/formlets/date.ss
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
#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))
|
||||||
|
|
||||||
|
(define date-formlet
|
||||||
|
(formlet
|
||||||
|
(div
|
||||||
|
"Month:" ,{input-int . => . month}
|
||||||
|
"Day:" ,{input-int . => . day})
|
||||||
|
(make-date month day)))
|
||||||
|
|
||||||
|
(formlet-display date-formlet)
|
||||||
|
|
||||||
|
(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)))
|
||||||
|
|
||||||
|
(formlet-display travel-formlet)
|
||||||
|
|
||||||
|
(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)))]))
|
||||||
|
|
||||||
|
(require net/url
|
||||||
|
web-server/servlet)
|
||||||
|
(formlet-process travel-formlet
|
||||||
|
(make-request 'get (string->url "http://test.com")
|
||||||
|
empty
|
||||||
|
(list (make-binding:form #"input_0" #"Jay")
|
||||||
|
(make-binding:form #"input_1" #"10")
|
||||||
|
(make-binding:form #"input_2" #"6")
|
||||||
|
(make-binding:form #"input_3" #"10")
|
||||||
|
(make-binding:form #"input_4" #"8"))
|
||||||
|
#f "127.0.0.1" 80 "127.0.0.1"))
|
||||||
|
|
||||||
|
(require web-server/formlets/servlet)
|
||||||
|
|
||||||
|
(define (start request)
|
||||||
|
(display-itinernary
|
||||||
|
(send/formlet
|
||||||
|
travel-formlet)))
|
||||||
|
|
52
collects/web-server/formlets/formlets.ss
Normal file
52
collects/web-server/formlets/formlets.ss
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#lang scheme
|
||||||
|
(require (for-syntax scheme)
|
||||||
|
"lib.ss"
|
||||||
|
(for-syntax "lib.ss"))
|
||||||
|
|
||||||
|
(define-for-syntax (cross-of stx)
|
||||||
|
(syntax-case stx (unquote unquote-splicing => #%#)
|
||||||
|
[s (string? (syntax->datum #'s))
|
||||||
|
(syntax/loc stx empty)]
|
||||||
|
[,(formlet . => . name) (syntax/loc stx name)]
|
||||||
|
[,e (syntax/loc stx empty)]
|
||||||
|
[,@e (syntax/loc stx empty)]
|
||||||
|
[(#%# n ...)
|
||||||
|
(quasisyntax/loc stx (list #,@(map cross-of (syntax->list #'(n ...)))))]
|
||||||
|
[(t ([k v] ...) n ...)
|
||||||
|
(quasisyntax/loc stx (list #,@(map cross-of (syntax->list #'(n ...)))))]
|
||||||
|
[(t n ...)
|
||||||
|
(quasisyntax/loc stx (list #,@(map cross-of (syntax->list #'(n ...)))))]))
|
||||||
|
|
||||||
|
(define-for-syntax (circ-of stx)
|
||||||
|
(syntax-case stx (unquote unquote-splicing => #%#)
|
||||||
|
[s (string? (syntax->datum #'s))
|
||||||
|
(syntax/loc stx (text s))]
|
||||||
|
[,(formlet . => . name) (syntax/loc stx formlet)]
|
||||||
|
[,e (syntax/loc stx (xml e))]
|
||||||
|
[,@e (syntax/loc stx (xml-forest e))]
|
||||||
|
[(#%# n ...)
|
||||||
|
(let ([n-cross (map cross-of (syntax->list #'(n ...)))])
|
||||||
|
(quasisyntax/loc stx
|
||||||
|
(cross*
|
||||||
|
(pure (match-lambda*
|
||||||
|
[(list #,@n-cross)
|
||||||
|
(list #,@n-cross)]))
|
||||||
|
#,@(map circ-of (syntax->list #'(n ...))))))]
|
||||||
|
[(t ([k v] ...) n ...)
|
||||||
|
(quasisyntax/loc stx
|
||||||
|
(tag-xexpr 't '([k v] ...)
|
||||||
|
#,(circ-of (syntax/loc stx (#%# n ...)))))]
|
||||||
|
[(t n ...)
|
||||||
|
(quasisyntax/loc stx
|
||||||
|
(tag-xexpr 't empty
|
||||||
|
#,(circ-of (syntax/loc stx (#%# n ...)))))]))
|
||||||
|
|
||||||
|
(define-syntax (formlet stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ q e)
|
||||||
|
(quasisyntax/loc stx
|
||||||
|
(cross (pure (match-lambda [#,(cross-of #'q) e]))
|
||||||
|
#,(circ-of #'q)))]))
|
||||||
|
|
||||||
|
(provide (all-defined-out)
|
||||||
|
(all-from-out "lib.ss"))
|
126
collects/web-server/formlets/lib.ss
Normal file
126
collects/web-server/formlets/lib.ss
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
#lang scheme
|
||||||
|
(require web-server/private/request-structs
|
||||||
|
xml)
|
||||||
|
|
||||||
|
; Combinators
|
||||||
|
(define (const x) (lambda _ x))
|
||||||
|
(define (id x) x)
|
||||||
|
|
||||||
|
; Formlets
|
||||||
|
(define (pure x)
|
||||||
|
(lambda (i)
|
||||||
|
(values empty (const x) i)))
|
||||||
|
|
||||||
|
(define (cross f p)
|
||||||
|
(lambda (i)
|
||||||
|
(let*-values ([(x1 g i) (f i)]
|
||||||
|
[(x2 q i) (p i)])
|
||||||
|
(values (append x1 x2)
|
||||||
|
(lambda (env)
|
||||||
|
(let ([ge (g env)]
|
||||||
|
[qe (q env)])
|
||||||
|
(ge qe)))
|
||||||
|
i))))
|
||||||
|
|
||||||
|
;; This is gross because OCaml auto-curries
|
||||||
|
(define (cross* f . gs)
|
||||||
|
(lambda (i)
|
||||||
|
(let*-values ([(fx fp fi) (f i)]
|
||||||
|
[(gs-x gs-p gs-i)
|
||||||
|
(let loop ([gs gs]
|
||||||
|
[xs empty]
|
||||||
|
[ps empty]
|
||||||
|
[i fi])
|
||||||
|
(if (empty? gs)
|
||||||
|
(values (reverse xs) (reverse ps) i)
|
||||||
|
(let-values ([(gx gp gi) ((first gs) i)])
|
||||||
|
(loop (rest gs) (list* gx xs) (list* gp ps) gi))))])
|
||||||
|
(values (apply append fx gs-x)
|
||||||
|
(lambda (env)
|
||||||
|
(let ([fe (fp env)]
|
||||||
|
[gs-e (map (lambda (g) (g env)) gs-p)])
|
||||||
|
(apply fe gs-e)))
|
||||||
|
gs-i))))
|
||||||
|
|
||||||
|
(define (xml x)
|
||||||
|
(lambda (i)
|
||||||
|
(values (list x) (const id) i)))
|
||||||
|
|
||||||
|
(define (xml-forest x)
|
||||||
|
(lambda (i)
|
||||||
|
(values x (const id) i)))
|
||||||
|
|
||||||
|
(define (text x)
|
||||||
|
(xml x))
|
||||||
|
|
||||||
|
(define (tag-xexpr t ats f)
|
||||||
|
(lambda (i)
|
||||||
|
(let-values ([(x p i) (f i)])
|
||||||
|
(values (list (list* t ats x)) p i))))
|
||||||
|
|
||||||
|
(define (next-name i)
|
||||||
|
(values (format "input_~a" i) (add1 i)))
|
||||||
|
(define (input i)
|
||||||
|
(let-values ([(w i) (next-name i)])
|
||||||
|
(values (list `(input ([name ,w])))
|
||||||
|
(lambda (env) (bindings-assq (string->bytes/utf-8 w) env))
|
||||||
|
i)))
|
||||||
|
|
||||||
|
; Helpers
|
||||||
|
(define (formlet-display f)
|
||||||
|
(let-values ([(x p i) (f 0)])
|
||||||
|
x))
|
||||||
|
|
||||||
|
(define (formlet-process f r)
|
||||||
|
(let-values ([(x p i) (f 0)])
|
||||||
|
(p (request-bindings/raw r))))
|
||||||
|
|
||||||
|
; Input Formlets
|
||||||
|
(define input-string
|
||||||
|
(cross
|
||||||
|
(pure (lambda (bf)
|
||||||
|
(bytes->string/utf-8 (binding:form-value bf))))
|
||||||
|
input))
|
||||||
|
|
||||||
|
(define input-int
|
||||||
|
(cross
|
||||||
|
(pure string->number)
|
||||||
|
input-string))
|
||||||
|
|
||||||
|
(define input-symbol
|
||||||
|
(cross
|
||||||
|
(pure string->symbol)
|
||||||
|
input-string))
|
||||||
|
|
||||||
|
; Contracts
|
||||||
|
(define xexpr-forest/c
|
||||||
|
(listof xexpr?))
|
||||||
|
|
||||||
|
(define (formlet/c c)
|
||||||
|
(integer? . -> .
|
||||||
|
(values xexpr-forest/c
|
||||||
|
((listof binding?) . -> . (coerce-contract 'formlet/c c))
|
||||||
|
integer?)))
|
||||||
|
|
||||||
|
(define alpha any/c)
|
||||||
|
(define beta any/c)
|
||||||
|
|
||||||
|
(provide/contract
|
||||||
|
[formlet/c (any/c . -> . contract?)]
|
||||||
|
[pure (alpha
|
||||||
|
. -> . (formlet/c alpha))]
|
||||||
|
[cross ((formlet/c (alpha . -> . beta))
|
||||||
|
(formlet/c alpha)
|
||||||
|
. -> . (formlet/c beta))]
|
||||||
|
[cross* (((formlet/c (() () #:rest (listof alpha) . ->* . beta)))
|
||||||
|
() #:rest (listof (formlet/c alpha))
|
||||||
|
. ->* . (formlet/c beta))]
|
||||||
|
[xml (xexpr? . -> . (formlet/c procedure?))]
|
||||||
|
[xml-forest (xexpr-forest/c . -> . (formlet/c procedure?))]
|
||||||
|
[text (string? . -> . (formlet/c procedure?))]
|
||||||
|
[tag-xexpr (symbol? (listof (list/c symbol? string?)) (formlet/c alpha) . -> . (formlet/c alpha))]
|
||||||
|
[input-string (formlet/c string?)]
|
||||||
|
[input-int (formlet/c integer?)]
|
||||||
|
[input-symbol (formlet/c symbol?)]
|
||||||
|
[formlet-display ((formlet/c alpha) . -> . xexpr-forest/c)]
|
||||||
|
[formlet-process ((formlet/c alpha) request? . -> . alpha)])
|
24
collects/web-server/formlets/servlet.ss
Normal file
24
collects/web-server/formlets/servlet.ss
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#lang scheme
|
||||||
|
(require web-server/servlet
|
||||||
|
xml
|
||||||
|
"lib.ss")
|
||||||
|
|
||||||
|
(provide/contract
|
||||||
|
[send/formlet ((formlet/c any/c) . -> . any/c)])
|
||||||
|
|
||||||
|
(define (send/formlet f)
|
||||||
|
(formlet-process
|
||||||
|
f
|
||||||
|
(send/suspend
|
||||||
|
(lambda (k-url)
|
||||||
|
`(form ([action ,k-url])
|
||||||
|
,@(formlet-display f))))))
|
||||||
|
|
||||||
|
(provide/contract
|
||||||
|
[embed-formlet (embed/url/c (formlet/c any/c) . -> . xexpr?)])
|
||||||
|
|
||||||
|
(define (embed-formlet embed/url f)
|
||||||
|
`(form ([action ,(embed/url
|
||||||
|
(lambda (r)
|
||||||
|
(formlet-process f r)))])
|
||||||
|
,@(formlet-display f)))
|
Loading…
Reference in New Issue
Block a user