Lots of documentation formatting.

Started as fixing misindented definitions, then more indentations, then
a bunch of similar things (square brackets, huge spaces at end-of-lines,
etc).
This commit is contained in:
Eli Barzilay 2011-08-15 07:50:04 -04:00
parent d3d9514b1c
commit d61eb53686
113 changed files with 1081 additions and 923 deletions

View File

@ -8,7 +8,8 @@
(require (for-label racket/serialize)) (require (for-label racket/serialize))
(define id (racket define-serializable-struct)) (define id (racket define-serializable-struct))
(define id2 (racket define-serializable-struct/versions)))) (define id2 (racket define-serializable-struct/versions))))
(bind racket-define-serializable-struct racket-define-serializable-struct/versions)) (bind racket-define-serializable-struct
racket-define-serializable-struct/versions))
@mzlib[#:mode title serialize] @mzlib[#:mode title serialize]

View File

@ -110,11 +110,11 @@ Raised for errors when handling cookies.}
@subsection{Creating a cookie} @subsection{Creating a cookie}
@racketblock[ @racketblock[
(let ((c (cookie:add-max-age (let ([c (cookie:add-max-age
(cookie:add-path (cookie:add-path
(set-cookie "foo" "bar") (set-cookie "foo" "bar")
"/servlets") "/servlets")
3600))) 3600)])
(print-cookie c)) (print-cookie c))
] ]

View File

@ -199,8 +199,8 @@ the bounds of the image, returns a transparent color.}
[f (-> natural-number/c natural-number/c color?)]) [f (-> natural-number/c natural-number/c color?)])
image?]{ image?]{
Builds an image of the specified size and shape by calling the specified function Builds an image of the specified size and shape by calling the specified
on the coordinates of each pixel. For example, function on the coordinates of each pixel. For example,
@codeblock|{ @codeblock|{
; fuzz : image -> image ; fuzz : image -> image
(define (fuzz pic) (define (fuzz pic)

View File

@ -229,7 +229,6 @@ The @racket[pkg] argument must end with @racket[".plt"].
} }
@defproc[(get-package-spec [owner string?] @defproc[(get-package-spec [owner string?]
[pkg (and/c string? #rx"[.]plt$")] [pkg (and/c string? #rx"[.]plt$")]
[maj (or/c #f natural-number/c) #f] [maj (or/c #f natural-number/c) #f]
@ -284,7 +283,8 @@ See also @racket[build-scribble-docs?] and @racket[force-package-building?]
} }
@defparam[force-package-building? b boolean?]{ @defparam[force-package-building? b boolean?]{
Determines if @racket[make-planet-archive] is more strict and thus aborts more often. Determines if @racket[make-planet-archive] is more strict and thus
aborts more often.
} }
@defproc[(download-package [pkg-spec pkg-spec?]) @defproc[(download-package [pkg-spec pkg-spec?])
@ -418,7 +418,8 @@ produces a list corresponding to its name and version, exactly like
} }
@defproc[(pkg? [v any/c]) boolean?]{ @defproc[(pkg? [v any/c]) boolean?]{
Determines if its argument is a pkg, the representation of an installed package. Determines if its argument is a pkg, the representation of an
installed package.
} }
@section[#:tag "version.rkt"]{Package Version} @section[#:tag "version.rkt"]{Package Version}

View File

@ -181,15 +181,15 @@ function, we could do the following:
#:segments [segments 20] #:segments [segments 20]
#:color [color 'red] #:color [color 'red]
#:width [width 1]) #:width [width 1])
(let* ((dash-size (/ (- x-max x-min) segments)) (let* ([dash-size (/ (- x-max x-min) segments)]
(x-lists (build-list [x-lists (build-list
(/ segments 2) (/ segments 2)
(lambda (index) (lambda (index)
(x-values (x-values
(/ samples segments) (/ samples segments)
(+ x-min (* 2 index dash-size)) (+ x-min (* 2 index dash-size))
(+ x-min (* (add1 (* 2 index)) (+ x-min (* (add1 (* 2 index))
dash-size))))))) dash-size)))))])
(lambda (2dview) (lambda (2dview)
(send 2dview set-line-color color) (send 2dview set-line-color color)
(send 2dview set-line-width width) (send 2dview set-line-width width)

View File

@ -399,7 +399,7 @@ Dispatching-related bindings:
@racketblock[ @racketblock[
(define (ttref) (define (ttref)
(let ((url (get-arg)) (text (get-arg))) (let ([url (get-arg)] [text (get-arg)])
(list "<a href=\"" url "\">@tt{" text "}</a>"))) (list "<a href=\"" url "\">@tt{" text "}</a>")))
] ]

View File

@ -76,7 +76,7 @@ cases. Here's a simple test case written using the
@racketblock[ @racketblock[
(test-begin (test-begin
(let ((lst (list 2 4 6 9))) (let ([lst (list 2 4 6 9)])
(check = (length lst) 4) (check = (length lst) 4)
(for-each (for-each
(lambda (elt) (lambda (elt)
@ -111,7 +111,7 @@ we're testing. We can give a test case a name with the
@racketblock[ @racketblock[
(test-case (test-case
"List has length 4 and all elements even" "List has length 4 and all elements even"
(let ((lst (list 2 4 6 9))) (let ([lst (list 2 4 6 9)])
(check = (length lst) 4) (check = (length lst) 4)
(for-each (for-each
(lambda (elt) (lambda (elt)
@ -133,7 +133,7 @@ group them into a test suite:
(test-case (test-case
"List has length 4 and all elements even" "List has length 4 and all elements even"
(let ((lst (list 2 4 6 9))) (let ([lst (list 2 4 6 9)])
(check = (length lst) 4) (check = (length lst) 4)
(for-each (for-each
(lambda (elt) (lambda (elt)

View File

@ -62,7 +62,7 @@ racket
(r (f lov) (r (f lov)
(lambda (r) (lambda (r)
(define f@r (f r)) (define f@r (f r))
(for/and ((v lov)) (>= f@r (f v))))))]) (for/and ([v lov]) (>= f@r (f v))))))])
] ]
It is a @emph{dependent} contract that names the two arguments and uses It is a @emph{dependent} contract that names the two arguments and uses
the names to impose a predicate on the result. This predicate computes the names to impose a predicate on the result. This predicate computes
@ -84,9 +84,8 @@ racket
(r (f lov) (r (f lov)
(lambda (r) (lambda (r)
(define f@r (f r)) (define f@r (f r))
(and (and (memq r lov)
(memq r lov) (for/and ([v lov]) (>= f@r (f v)))))))])
(for/and ((v lov)) (>= f@r (f v)))))))])
] ]
The @racket[memq] function ensures that @racket[r] is @emph{intensionally equal} The @racket[memq] function ensures that @racket[r] is @emph{intensionally equal}
@margin-note*{That is, "pointer equality" for those who prefer to think at @margin-note*{That is, "pointer equality" for those who prefer to think at
@ -113,7 +112,7 @@ racket
(r (f lov) (r (f lov)
(lambda (r) (lambda (r)
(define f@r (f r)) (define f@r (f r))
(and (for/and ((v lov)) (>= f@r (f v))) (and (for/and ([v lov]) (>= f@r (f v)))
(eq? (first (memf (lambda (v) (= (f v) f@r)) lov)) (eq? (first (memf (lambda (v) (= (f v) f@r)) lov))
r)))))]) r)))))])
] ]
@ -157,7 +156,7 @@ racket
@code:comment{@#,dominates1} @code:comment{@#,dominates1}
(define (dominates-all f@r f lov) (define (dominates-all f@r f lov)
(for/and ((v lov)) (>= (f v) f@r))) (for/and ([v lov]) (>= (f v) f@r)))
@code:comment{@#,first?1} @code:comment{@#,first?1}
(define (is-first-max? r f@r f lov) (define (is-first-max? r f@r f lov)
@ -199,7 +198,7 @@ racket
@code:comment{@#,dominates2} @code:comment{@#,dominates2}
(define (dominates-all f@r flov) (define (dominates-all f@r flov)
(for/and ((f@v flov)) (>= f@r f@v))) (for/and ([f@v flov]) (>= f@r f@v)))
@code:comment{@#,first?2} @code:comment{@#,first?2}
(define (is-first-max? r f@r lov+flov) (define (is-first-max? r f@r lov+flov)

View File

@ -82,8 +82,7 @@ streams like this:
#:eval e #:eval e
(define stream/c (define stream/c
(promise/c (promise/c
(or/c (or/c null?
null?
(cons/c number? stream/c)))) (cons/c number? stream/c))))
] ]
@close-eval[e] @close-eval[e]
@ -99,8 +98,7 @@ Instead, use
(promise/c (promise/c
(or/c (or/c
null? null?
(cons/c 1 (cons/c 1 (recursive-contract stream/c)))))
(recursive-contract stream/c)))))
] ]
The use of @racket[recursive-contract] delays the evaluation of the The use of @racket[recursive-contract] delays the evaluation of the

View File

@ -261,7 +261,7 @@ resulting iteration can be performed more efficiently than plain
@racket[for/vector] or @racket[for*/vector]: @racket[for/vector] or @racket[for*/vector]:
@interaction[ @interaction[
(let ((chapters '("Intro" "Details" "Conclusion"))) (let ([chapters '("Intro" "Details" "Conclusion")])
(for/vector #:length (length chapters) ([i (in-naturals 1)] (for/vector #:length (length chapters) ([i (in-naturals 1)]
[chapter chapters]) [chapter chapters])
(string-append (number->string i) ". " chapter))) (string-append (number->string i) ". " chapter)))

View File

@ -64,18 +64,18 @@ Consider the following core of a Mandelbrot-set computation:
@racketblock[ @racketblock[
(define (mandelbrot iterations x y n) (define (mandelbrot iterations x y n)
(let ((ci (- (/ (* 2.0 y) n) 1.0)) (let ([ci (- (/ (* 2.0 y) n) 1.0)]
(cr (- (/ (* 2.0 x) n) 1.5))) [cr (- (/ (* 2.0 x) n) 1.5)])
(let loop ((i 0) (zr 0.0) (zi 0.0)) (let loop ([i 0] [zr 0.0] [zi 0.0])
(if (> i iterations) (if (> i iterations)
i i
(let ((zrq (* zr zr)) (let ([zrq (* zr zr)]
(ziq (* zi zi))) [ziq (* zi zi)])
(cond (cond
((> (+ zrq ziq) 4.0) i) [(> (+ zrq ziq) 4.0) i]
(else (loop (add1 i) [else (loop (add1 i)
(+ (- zrq ziq) cr) (+ (- zrq ziq) cr)
(+ (* 2.0 zr zi) ci))))))))) (+ (* 2.0 zr zi) ci))]))))))
] ]
The expressions @racket[(mandelbrot 10000000 62 500 1000)] and The expressions @racket[(mandelbrot 10000000 62 500 1000)] and
@ -110,8 +110,8 @@ first the problem:
@racketblock[ @racketblock[
(define (mandelbrot iterations x y n) (define (mandelbrot iterations x y n)
(let ((ci (- (/ (* 2.0 (->fl y)) (->fl n)) 1.0)) (let ([ci (- (/ (* 2.0 (->fl y)) (->fl n)) 1.0)]
(cr (- (/ (* 2.0 (->fl x)) (->fl n)) 1.5))) [cr (- (/ (* 2.0 (->fl x)) (->fl n)) 1.5)])
....)) ....))
] ]
@ -128,18 +128,18 @@ much less allocation:
@racketblock[ @racketblock[
(define (mandelbrot iterations x y n) (define (mandelbrot iterations x y n)
(let ((ci (fl- (fl/ (* 2.0 (->fl y)) (->fl n)) 1.0)) (let ([ci (fl- (fl/ (* 2.0 (->fl y)) (->fl n)) 1.0)]
(cr (fl- (fl/ (* 2.0 (->fl x)) (->fl n)) 1.5))) [cr (fl- (fl/ (* 2.0 (->fl x)) (->fl n)) 1.5)])
(let loop ((i 0) (zr 0.0) (zi 0.0)) (let loop ([i 0] [zr 0.0] [zi 0.0])
(if (> i iterations) (if (> i iterations)
i i
(let ((zrq (fl* zr zr)) (let ([zrq (fl* zr zr)]
(ziq (fl* zi zi))) [ziq (fl* zi zi)])
(cond (cond
((fl> (fl+ zrq ziq) 4.0) i) [(fl> (fl+ zrq ziq) 4.0) i]
(else (loop (add1 i) [else (loop (add1 i)
(fl+ (fl- zrq ziq) cr) (fl+ (fl- zrq ziq) cr)
(fl+ (fl* 2.0 (fl* zr zi)) ci))))))))) (fl+ (fl* 2.0 (fl* zr zi)) ci))]))))))
] ]
This conversion can speed @racket[mandelbrot] by a factor of 8, even This conversion can speed @racket[mandelbrot] by a factor of 8, even

View File

@ -280,7 +280,8 @@ For communication among @tech{places}, the new byte string is allocated in the
the other operations. the other operations.
@examples[ @examples[
(define b (define b
(bytes->string/utf-8 (bytes #xc3 #xa7 #xc3 #xb0 #xc3 #xb6 #xc2 #xa3))) (bytes->string/utf-8
(bytes #xc3 #xa7 #xc3 #xb0 #xc3 #xb6 #xc2 #xa3)))
(string->bytes/utf-8 b) (string->bytes/utf-8 b)
(bytes->string/utf-8 (string->bytes/utf-8 b)) (bytes->string/utf-8 (string->bytes/utf-8 b))

View File

@ -292,13 +292,13 @@ interface @racket[(class->interface object%)], and is transparent
(lambda kw-formals expr ...+) (lambda kw-formals expr ...+)
(case-lambda (formals expr ...+) ...) (case-lambda (formals expr ...+) ...)
(#%plain-lambda formals expr ...+) (#%plain-lambda formals expr ...+)
(let-values (((id) method-procedure) ...) (let-values ([(id) method-procedure] ...)
method-procedure) method-procedure)
(letrec-values (((id) method-procedure) ...) (letrec-values ([(id) method-procedure] ...)
method-procedure) method-procedure)
(let-values (((id) method-procedure) ...+) (let-values ([(id) method-procedure] ...+)
id) id)
(letrec-values (((id) method-procedure) ...+) (letrec-values ([(id) method-procedure] ...+)
id)])]{ id)])]{
Produces a class value. Produces a class value.

View File

@ -196,4 +196,3 @@ For communication among @tech{places}, the new @tech{fxvector} is
allocated in the @tech{shared memory space}. allocated in the @tech{shared memory space}.
@mz-examples[#:eval flfx-eval (make-shared-fxvector 4 3)]} @mz-examples[#:eval flfx-eval (make-shared-fxvector 4 3)]}

View File

@ -481,7 +481,8 @@ instead of @racket[match].}
type named @racket[struct-id], where the field @racket[field] in the type named @racket[struct-id], where the field @racket[field] in the
instance matches the corresponding @racket[pat]. instance matches the corresponding @racket[pat].
Any field of @racket[struct-id] may be omitted, and such fields can occur in any order. Any field of @racket[struct-id] may be omitted, and such fields can
occur in any order.
@defexamples[ @defexamples[
#:eval match-eval #:eval match-eval

View File

@ -44,7 +44,7 @@ new parameter value. A guard procedure can raise an exception to
reject a change to the parameter's value. The @racket[guard] is not reject a change to the parameter's value. The @racket[guard] is not
applied to the initial @racket[v].} applied to the initial @racket[v].}
@defform[(parameterize ((parameter-expr value-expr) ...) @defform[(parameterize ([parameter-expr value-expr] ...)
body ...+) body ...+)
#:contracts #:contracts
([parameter-expr parameter?])]{ ([parameter-expr parameter?])]{

View File

@ -24,7 +24,7 @@ used as a macro that expands to a use of the target identifier, but
@racket[syntax-local-value] of @racket[id] does not produce @racket[syntax-local-value] of @racket[id] does not produce
the target's value.} the target's value.}
@defform[(syntax-parameterize ((id expr) ...) body-expr ...+)]{ @defform[(syntax-parameterize ([id expr] ...) body-expr ...+)]{
@margin-note/ref{See also @racket[splicing-syntax-parameterize].} @margin-note/ref{See also @racket[splicing-syntax-parameterize].}

View File

@ -139,7 +139,7 @@ For example, the expression
expands to expands to
@racketblock[ @racketblock[
(let ((or-part x)) (if or-part or-part (or y))) (let ([or-part x]) (if or-part or-part (or y)))
] ]
which, in turn, expands to which, in turn, expands to

View File

@ -210,9 +210,9 @@ the binding (according to @racket[free-identifier=?]) matters.}
(if expr expr expr) (if expr expr expr)
(begin expr ...+) (begin expr ...+)
(begin0 expr expr ...) (begin0 expr expr ...)
(let-values (((id ...) expr) ...) (let-values ([(id ...) expr] ...)
expr ...+) expr ...+)
(letrec-values (((id ...) expr) ...) (letrec-values ([(id ...) expr] ...)
expr ...+) expr ...+)
(set! id expr) (set! id expr)
(@#,racket[quote] datum) (@#,racket[quote] datum)

View File

@ -109,7 +109,7 @@ is prefixed with the special form name as described under
@examples[#:eval the-eval @examples[#:eval the-eval
(wrong-syntax #'here "expected ~s" 'there) (wrong-syntax #'here "expected ~s" 'there)
(parameterize ((current-syntax-context #'(look over here))) (parameterize ([current-syntax-context #'(look over here)])
(wrong-syntax #'here "expected ~s" 'there)) (wrong-syntax #'here "expected ~s" 'there))
] ]
@ -117,7 +117,7 @@ A macro using @racket[wrong-syntax] might set the syntax context at the very
beginning of its transformation as follows: beginning of its transformation as follows:
@RACKETBLOCK[ @RACKETBLOCK[
(define-syntax (my-macro stx) (define-syntax (my-macro stx)
(parameterize ((current-syntax-context stx)) (parameterize ([current-syntax-context stx])
(syntax-case stx () (syntax-case stx ()
___))) ___)))
] ]

View File

@ -117,8 +117,8 @@ form.}
(->d (arg ...) () #:rest id rest [id result])])]{ (->d (arg ...) () #:rest id rest [id result])])]{
Like @racket[proc-doc], but supporting contract forms that embed Like @racket[proc-doc], but supporting contract forms that embed
argument names. Only a subset of @racket[->i] and @racket[->d] forms are currently argument names. Only a subset of @racket[->i] and @racket[->d] forms are
supported.} currently supported.}
@defform[(thing-doc id contract-expr dec-expr)]{ @defform[(thing-doc id contract-expr dec-expr)]{

View File

@ -163,7 +163,6 @@ Transfers cross-reference information to @racket[ci], which is the
initially collected information from @racket[renderer].} initially collected information from @racket[renderer].}
@defproc[(xref-index [xref xref?]) (listof entry?)]{ @defproc[(xref-index [xref xref?]) (listof entry?)]{
Converts indexing information @racket[xref] into a list of Converts indexing information @racket[xref] into a list of

View File

@ -83,12 +83,12 @@ language [*]:
"#<procedure:closure-storing-proc>" "#<procedure:closure-storing-proc>"
(#%plain-lambda (x) (#%plain-lambda (x)
(begin (begin
(let-values (((arg0-1643 arg1-1644 arg2-1645) (let-values ([(arg0-1643 arg1-1644 arg2-1645)
(#%plain-app (#%plain-app
values values
"#<*unevaluated-struct*>" "#<*unevaluated-struct*>"
"#<*unevaluated-struct*>" "#<*unevaluated-struct*>"
"#<*unevaluated-struct*>"))) "#<*unevaluated-struct*>")])
(with-continuation-mark "#<debug-key-struct>" (with-continuation-mark "#<debug-key-struct>"
(#%plain-lambda () (#%plain-lambda ()
(#%plain-app (#%plain-app
@ -161,7 +161,7 @@ language [*]:
#f #f
(#%plain-lambda () (#%plain-app list f)))))))) (#%plain-lambda () (#%plain-app list f))))))))
(let-values (((done-already?) (quote #f))) (let-values ([(done-already?) (quote #f)])
(#%app dynamic-wind void (#%app dynamic-wind void
(lambda () (#%app dynamic-require (quote (quote #%htdp)) (quote #f))) (lambda () (#%app dynamic-require (quote (quote #%htdp)) (quote #f)))
(lambda () (if done-already? (lambda () (if done-already?

View File

@ -11,8 +11,8 @@
@(begin @(begin
(define the-eval (define the-eval
(parameterize ((sandbox-output 'string) (parameterize ([sandbox-output 'string]
(sandbox-error-output 'string)) [sandbox-error-output 'string])
(make-evaluator 'racket/base #:requires '(syntax/keyword)))) (make-evaluator 'racket/base #:requires '(syntax/keyword))))
;;(void (the-eval '(error-print-source-location #f))) ;;(void (the-eval '(error-print-source-location #f)))
(define-syntax-rule (myexamples e ...) (define-syntax-rule (myexamples e ...)

View File

@ -23,11 +23,11 @@ the parameter expressions.
[(_ ((p v:expr) ...) body:expr) [(_ ((p v:expr) ...) body:expr)
#:declare p (expr/c #'parameter? #:declare p (expr/c #'parameter?
#:name "parameter argument") #:name "parameter argument")
#'(parameterize ((p.c v) ...) body)])) #'(parameterize ([p.c v] ...) body)]))
(myparameterize ((current-input-port (myparameterize ([current-input-port
(open-input-string "(1 2 3)"))) (open-input-string "(1 2 3)")])
(read)) (read))
(myparameterize (('whoops 'something)) (myparameterize (['whoops 'something])
'whatever) 'whatever)
] ]

View File

@ -425,7 +425,6 @@ They all construct a triangle oriented as follows:
} }
@defproc*[([(square [side-len (and/c real? (not/c negative?))] @defproc*[([(square [side-len (and/c real? (not/c negative?))]
[mode mode?] [mode mode?]
[color image-color?]) [color image-color?])
@ -657,7 +656,6 @@ the @racket[point-count] argument determines how many points the star has.
(rectangle 40 40 "solid" "silver") (rectangle 40 40 "solid" "silver")
(rectangle 50 50 "solid" "seagreen"))] (rectangle 50 50 "solid" "seagreen"))]
} }
@defproc[(overlay/offset [i1 image?] [x real?] [y real?] [i2 image?]) image?]{ @defproc[(overlay/offset [i1 image?] [x real?] [y real?] [i2 image?]) image?]{
@ -777,7 +775,6 @@ the @racket[point-count] argument determines how many points the star has.
(rectangle 30 30 50 "seagreen") (rectangle 30 30 50 "seagreen")
(rectangle 20 20 50 "seagreen"))] (rectangle 20 20 50 "seagreen"))]
} }
@ -869,7 +866,6 @@ the @racket[point-count] argument determines how many points the star has.
(ellipse 20 30 "solid" "dimgray") (ellipse 20 30 "solid" "dimgray")
(ellipse 20 10 "solid" "black"))] (ellipse 20 10 "solid" "black"))]
} }
@defproc[(beside/align [y-place y-place?] [i1 image?] [i2 image?] [is image?] ...) image?]{ @defproc[(beside/align [y-place y-place?] [i1 image?] [i2 image?] [is image?] ...) image?]{
@ -894,7 +890,6 @@ the @racket[point-count] argument determines how many points the star has.
(text "ijy" 18 "black") (text "ijy" 18 "black")
(text "ijy" 24 "black"))] (text "ijy" 24 "black"))]
} }
@ -907,7 +902,6 @@ the @racket[point-count] argument determines how many points the star has.
(ellipse 30 20 "solid" "dimgray") (ellipse 30 20 "solid" "dimgray")
(ellipse 10 20 "solid" "black"))] (ellipse 10 20 "solid" "black"))]
} }
@defproc[(above/align [x-place x-place?] [i1 image?] [i2 image?] [is image?] ...) image?]{ @defproc[(above/align [x-place x-place?] [i1 image?] [i2 image?] [is image?] ...) image?]{
@ -928,7 +922,6 @@ the @racket[point-count] argument determines how many points the star has.
(ellipse 30 20 "solid" "darkolivegreen") (ellipse 30 20 "solid" "darkolivegreen")
(ellipse 10 20 "solid" "darkgreen"))] (ellipse 10 20 "solid" "darkgreen"))]
} }
@section{Placing Images & Scenes} @section{Placing Images & Scenes}
@ -1201,9 +1194,10 @@ more expensive than with the other shapes.
([bitmap-spec rel-string ([bitmap-spec rel-string
id])]{ id])]{
Loads the bitmap specified by @racket[bitmap-spec]. If @racket[bitmap-spec] is a string, it is treated as a Loads the bitmap specified by @racket[bitmap-spec]. If
relative path. If it is an identifier, it is treated like a require spec and used to refer to a file @racket[bitmap-spec] is a string, it is treated as a relative path.
in a collection. If it is an identifier, it is treated like a require spec and used to
refer to a file in a collection.
@image-examples[(bitmap icons/stop-16x16.png) @image-examples[(bitmap icons/stop-16x16.png)
(bitmap icons/b-run.png)] (bitmap icons/b-run.png)]

View File

@ -34,8 +34,7 @@ Example:
(view dir) (view dir)
(printf "~a ~n" (control))))) (printf "~a ~n" (control)))))
(connect (connect (make-model "left")
(make-model "left")
(make-model "right") (make-model "right")
(make-model "up") (make-model "up")
(make-model "down")) (make-model "down"))

View File

@ -34,15 +34,20 @@ This module provides a macro for regular expression compilation.
pat])]{ pat])]{
Compiles a regular expression over match patterns to a @racket[machine]. Compiles a regular expression over match patterns to a @racket[machine].
The interpretation of the pattern language is mostly intuitive. The pattern language may be extended The interpretation of the pattern language is mostly intuitive. The
with @racket[define-re-transformer]. @racket[dseq] allows bindings of the @racket[match] pattern to be pattern language may be extended with @racket[define-re-transformer].
used in the rest of the regular expression. (Thus, they are not @emph{really} regular expressions.) @racket[dseq] allows bindings of the @racket[match] pattern to be used
@racket[unquote] escapes to Racket to evaluate an expression that evaluates to a regular expression (this happens in the rest of the regular expression. (Thus, they are not
once, at compile time.) @racket[rec] binds a Racket identifier to a delayed version of the inner expression; even @emph{really} regular expressions.) @racket[unquote] escapes to Racket
if the expression is initially accepting, this delayed version is never accepting. to evaluate an expression that evaluates to a regular expression (this
happens once, at compile time.) @racket[rec] binds a Racket identifier
to a delayed version of the inner expression; even if the expression is
initially accepting, this delayed version is never accepting.
The compiler will use an NFA, provided @racket[complement] and @racket[dseq] are not used. Otherwise, The compiler will use an NFA, provided @racket[complement] and
many NFAs connected with the machine simulation functions from @racketmodname[unstable/automata/machine] are used. @racket[dseq] are not used. Otherwise, many NFAs connected with the
machine simulation functions from
@racketmodname[unstable/automata/machine] are used.
} }
@(define-syntax-rule (defidforms (id ...) . dat) @(define-syntax-rule (defidforms (id ...) . dat)

View File

@ -24,18 +24,26 @@
[name? identifier?] [name? identifier?]
[method identifier?])]{ [method identifier?])]{
Defines @racket[name] as a transformer binding for the static information about a new generic group. Defines @racket[name] as a transformer binding for the static
information about a new generic group.
Defines @racket[prop:name] as a structure Defines @racket[prop:name] as a structure type property. Structure
type property. Structure types implementing this generic group should have this property where the value is a vector types implementing this generic group should have this property where
with one element per @racket[method] where each value is the value is a vector with one element per @racket[method] where each
either @racket[#f] or a procedure with the same arity as specified by @racket[kw-formals*]. value is either @racket[#f] or a procedure with the same arity as
(@racket[kw-formals*] is similar to the @racket[kw-formals] used by @racket[lambda], except no expression is given for optional arguments.) specified by @racket[kw-formals*]. (@racket[kw-formals*] is similar to
The arity of each method is checked by the guard on the structure type property. the @racket[kw-formals] used by @racket[lambda], except no expression is
given for optional arguments.) The arity of each method is checked by
the guard on the structure type property.
Defines @racket[name?] as a predicate identifying instances of structure types that implement this generic group. Defines @racket[name?] as a predicate identifying instances of structure
types that implement this generic group.
Defines each @racket[method] as a generic procedure that calls the corresponding method on values where @racket[name?] is true. Each method must have a required by-position argument that is @racket[free-identifier=?] to @racket[name]. This argument is used in the generic definition to locate the specialization. Defines each @racket[method] as a generic procedure that calls the
corresponding method on values where @racket[name?] is true. Each method
must have a required by-position argument that is
@racket[free-identifier=?] to @racket[name]. This argument is used in
the generic definition to locate the specialization.
} }
@ -61,13 +69,18 @@ context of @racket[name].
#:contracts #:contracts
([name identifier?])]{ ([name identifier?])]{
@racket[name] must be a transformer binding for the static information about a new generic group. @racket[name] must be a transformer binding for the static information
about a new generic group.
Expands to a value usable as the property value for the structure type property of the @racket[name] generic group. Expands to a value usable as the property value for the structure type
property of the @racket[name] generic group.
If the @racket[definition]s define the methods of @racket[name], then they are used in the property value. If the @racket[definition]s define the methods of @racket[name], then
they are used in the property value.
If any method of @racket[name] is not defined, then @racket[#f] is used to signify that the structure type does not implement the particular method. If any method of @racket[name] is not defined, then @racket[#f] is used
to signify that the structure type does not implement the particular
method.
Allows @racket[define/generic] to appear in @racket[definition ...]. Allows @racket[define/generic] to appear in @racket[definition ...].
@ -78,7 +91,9 @@ Allows @racket[define/generic] to appear in @racket[definition ...].
([local-name identifier?] ([local-name identifier?]
[method-name identifier?])]{ [method-name identifier?])]{
When used inside @racket[define-methods], binds @racket[local-name] to the generic for @racket[method-name]. This is useful for method specializations to use the generic methods on other values. When used inside @racket[define-methods], binds @racket[local-name] to
the generic for @racket[method-name]. This is useful for method
specializations to use the generic methods on other values.
Syntactically an error when used outside @racket[define-methods]. Syntactically an error when used outside @racket[define-methods].

View File

@ -29,9 +29,18 @@ This library provides a simplified version of parameters that are backed by cont
[none-v [any/c #f]] [none-v [any/c #f]]
[tag continuation-prompt-tag? default-continuation-prompt-tag]) [tag continuation-prompt-tag? default-continuation-prompt-tag])
(listof vector?)]{ (listof vector?)]{
Returns the values of the @racket[mps] up to @racket[tag]. The length of each vector in the result list is the same as the length of @racket[mps], and a value in a particular vector position is the value for the corresponding mark parameter in @racket[mps]. Values for multiple mark parameter appear in a single vector only when the mark parameters are for the same continuation frame in the current continuation. The @racket[none-v] argument is used for vector elements to indicate the lack of a value. Returns the values of the @racket[mps] up to @racket[tag]. The length
} of each vector in the result list is the same as the length of
@racket[mps], and a value in a particular vector position is the value
for the corresponding mark parameter in @racket[mps]. Values for
multiple mark parameter appear in a single vector only when the mark
parameters are for the same continuation frame in the current
continuation. The @racket[none-v] argument is used for vector elements
to indicate the lack of a value.
}
@defform[(mark-parameterize ([mp expr] ...) body-expr ...)]{ @defform[(mark-parameterize ([mp expr] ...) body-expr ...)]{
Parameterizes @racket[(begin body-expr ...)] by associating each @racket[mp] with the evaluation of @racket[expr] in the parameterization of the entire expression. Parameterizes @racket[(begin body-expr ...)] by associating each
} @racket[mp] with the evaluation of @racket[expr] in the
parameterization of the entire expression.
}

View File

@ -40,16 +40,16 @@ The other arguments have the same meaning as for @racket[expr/c].
@examples[#:eval the-eval @examples[#:eval the-eval
(define-syntax (myparameterize1 stx) (define-syntax (myparameterize1 stx)
(syntax-case stx () (syntax-case stx ()
[(_ ((p v)) body) [(_ ([p v]) body)
(with-syntax ([cp (wrap-expr/c (with-syntax ([cp (wrap-expr/c
#'parameter? #'p #'parameter? #'p
#:name "the parameter argument" #:name "the parameter argument"
#:context stx)]) #:context stx)])
#'(parameterize ((cp v)) body))])) #'(parameterize ([cp v]) body))]))
(myparameterize1 ((current-input-port (myparameterize1 ([current-input-port
(open-input-string "(1 2 3)"))) (open-input-string "(1 2 3)")])
(read)) (read))
(myparameterize1 (('whoops 'something)) (myparameterize1 (['whoops 'something])
'whatever) 'whatever)
(module mod racket (module mod racket

View File

@ -7,8 +7,8 @@
web-server/lang/serial-lambda web-server/lang/serial-lambda
web-server/private/define-closure)) web-server/private/define-closure))
The defunctionalization process of the Web Language (see
The defunctionalization process of the Web Language (see @secref["stateless" #:doc '(lib "web-server/scribblings/web-server.scrbl")]) @secref["stateless" #:doc '(lib "web-server/scribblings/web-server.scrbl")])
requires an explicit representation of closures that is serializable. requires an explicit representation of closures that is serializable.
@defmodule[web-server/lang/serial-lambda]{ @defmodule[web-server/lang/serial-lambda]{
@ -18,7 +18,8 @@ requires an explicit representation of closures that is serializable.
} }
@defform[(serial-case-lambda [formals body ...] ...)]{ @defform[(serial-case-lambda [formals body ...] ...)]{
Returns @racket[(case-lambda [formals body ...] ...)], except it is serializable. Returns @racket[(case-lambda [formals body ...] ...)], except it is
serializable.
} }
} }

View File

@ -20,9 +20,10 @@
[path->serlvet path->servlet/c]) [path->serlvet path->servlet/c])
(values (-> void) (values (-> void)
url->servlet/c)]{ url->servlet/c)]{
The first return value flushes the cache. The first return value flushes the cache. The second is a procedure
The second is a procedure that uses @racket[url->path] to resolve the URL to a path, then uses @racket[path->servlet] to resolve that uses @racket[url->path] to resolve the URL to a path, then uses
that path to a servlet, caching the results in an internal table. @racket[path->servlet] to resolve that path to a servlet, caching the
results in an internal table.
} }
@defproc[(make [url->servlet url->servlet/c] @defproc[(make [url->servlet url->servlet/c]
@ -35,9 +36,12 @@
(url? exn? . -> . can-be-response?) (url? exn? . -> . can-be-response?)
servlet-error-responder]) servlet-error-responder])
dispatcher/c]{ dispatcher/c]{
This dispatcher runs racket servlets, using @racket[url->servlet] to resolve URLs to the underlying servlets. This dispatcher runs racket servlets, using @racket[url->servlet] to
If servlets have errors loading, then @racket[responders-servlet-loading] is used. Other errors are handled with resolve URLs to the underlying servlets. If servlets have errors
@racket[responders-servlet]. If a servlet raises calls @racket[next-dispatcher], then the signal is propagated by this dispatcher. loading, then @racket[responders-servlet-loading] is used. Other errors
are handled with @racket[responders-servlet]. If a servlet raises calls
@racket[next-dispatcher], then the signal is propagated by this
dispatcher.
} }
} }

View File

@ -102,10 +102,12 @@ URLs to paths on the filesystem.
@defproc[(filter-url->path [regex regexp?] @defproc[(filter-url->path [regex regexp?]
[url->path url->path/c]) [url->path url->path/c])
url->path/c]{ url->path/c]{
Runs the underlying @racket[url->path] but will only return if the path, when considered as a string, Runs the underlying @racket[url->path] but will only return if the
matches the @racket[regex]. This is useful to disallow strange files, like GIFs, from being considered path, when considered as a string, matches the @racket[regex]. This is
servlets when using the servlet dispatchers. It will return a @racket[exn:fail:filesystem:exists?] exception if useful to disallow strange files, like GIFs, from being considered
the path does not match. servlets when using the servlet dispatchers. It will return a
@racket[exn:fail:filesystem:exists?] exception if the path does not
match.
} }
} }
@ -249,9 +251,9 @@ a URL that refreshes the password file, servlet cache, etc.}
web-server/configuration/responders)) web-server/configuration/responders))
@defthing[denied?/c contract?]{ @defthing[denied?/c contract?]{
Equivalent to @racket[(request? . -> . (or/c false/c string?))]. Equivalent to @racket[(request? . -> . (or/c false/c string?))]. The
The return is the authentication realm as a string if the request is not authorized and return is the authentication realm as a string if the request is not
@racket[#f] if the request @emph{is} authorized. authorized and @racket[#f] if the request @emph{is} authorized.
} }
@defproc[(make [denied? denied?/c] @defproc[(make [denied? denied?/c]
@ -260,24 +262,26 @@ a URL that refreshes the password file, servlet cache, etc.}
(url? header? . -> . response?) (url? header? . -> . response?)
(gen-authentication-responder "forbidden.html")]) (gen-authentication-responder "forbidden.html")])
dispatcher/c]{ dispatcher/c]{
A dispatcher that checks if the request is denied based on @racket[denied?]. If so, then A dispatcher that checks if the request is denied based on
@racket[authentication-responder] is called with a @racket[header] that @racket[denied?]. If so, then @racket[authentication-responder] is
requests credentials. If not, then @racket[next-dispatcher] is called with a @racket[header] that requests credentials. If not, then
invoked. @racket[next-dispatcher] is invoked.
} }
@defthing[authorized?/c contract?]{ @defthing[authorized?/c contract?]{
Equivalent to @racket[(string? (or/c false/c bytes?) (or/c false/c bytes?) . -> . (or/c false/c string?))]. Equivalent to
The input is the URI as a string and the username and passwords as bytes. @racket[(string? (or/c false/c bytes?) (or/c false/c bytes?) . -> . (or/c false/c string?))].
The return is the authentication realm as a string if the user is not authorized and The input is the URI as a string and the username and passwords as
@racket[#f] if the request @emph{is} authorized. bytes. The return is the authentication realm as a string if the user
is not authorized and @racket[#f] if the request @emph{is} authorized.
} }
@defproc[(make-basic-denied?/path [password-file path-string?]) @defproc[(make-basic-denied?/path [password-file path-string?])
(values (-> void) (values (-> void)
authorized?/c)]{ authorized?/c)]{
Creates an authorization procedure based on the given password file. The first returned value Creates an authorization procedure based on the given password
is a procedure that refreshes the password cache used by the authorization procedure. file. The first returned value is a procedure that refreshes the
password cache used by the authorization procedure.
@racket[password-file] is parsed as: @racket[password-file] is parsed as:
@racketblock[(list ([domain : string?] @racketblock[(list ([domain : string?]

View File

@ -23,8 +23,7 @@ Suppose we want to create an abstraction of entering a date in an HTML form. The
@racketblock[ @racketblock[
(define date-formlet (define date-formlet
(formlet (formlet
(div (div "Month:" ,{input-int . => . month}
"Month:" ,{input-int . => . month}
"Day:" ,{input-int . => . day}) "Day:" ,{input-int . => . day})
(list month day))) (list month day)))
] ]
@ -233,7 +232,8 @@ types. Refer to @secref["input-formlets"] for example low-level formlets using t
@defproc[(xml-forest [r xexpr-forest/c]) @defproc[(xml-forest [r xexpr-forest/c])
(formlet/c procedure?)]{ (formlet/c procedure?)]{
Constructs a @tech{formlet} with the rendering @racket[r] and the identity procedure as the processing step. Constructs a @tech{formlet} with the rendering @racket[r] and the
identity procedure as the processing step.
} }
@defproc[(xml [r xexpr/c]) @defproc[(xml [r xexpr/c])
@ -250,8 +250,10 @@ types. Refer to @secref["input-formlets"] for example low-level formlets using t
[attrs (listof (list/c symbol? string?))] [attrs (listof (list/c symbol? string?))]
[inner (formlet/c any/c)]) [inner (formlet/c any/c)])
(formlet/c any/c)]{ (formlet/c any/c)]{
Constructs a @tech{formlet} with the rendering @racket[(list (list* tag attrs inner-rendering))] where @racket[inner-rendering] is Constructs a @tech{formlet} with the rendering @racket[(list (list*
the rendering of @racket[inner] and the processing stage identical to @racket[inner]. tag attrs inner-rendering))] where @racket[inner-rendering] is the
rendering of @racket[inner] and the processing stage identical to
@racket[inner].
} }
@defproc[(formlet-display [f (formlet/c any/c)]) @defproc[(formlet-display [f (formlet/c any/c)])
@ -276,14 +278,15 @@ These @tech{formlet}s are the main combinators for form input.
@defproc[(make-input [render (string? . -> . xexpr/c)]) @defproc[(make-input [render (string? . -> . xexpr/c)])
(formlet/c (or/c false/c binding?))]{ (formlet/c (or/c false/c binding?))]{
This @tech{formlet} is rendered with @racket[render], which is passed the input name, and results in the This @tech{formlet} is rendered with @racket[render], which is passed
extracted @racket[binding]. the input name, and results in the extracted @racket[binding].
} }
@defproc[(make-input* [render (string? . -> . xexpr/c)]) @defproc[(make-input* [render (string? . -> . xexpr/c)])
(formlet/c (listof binding?))]{ (formlet/c (listof binding?))]{
This @tech{formlet} is rendered with @racket[render], which is passed the input name, and results in all the This @tech{formlet} is rendered with @racket[render], which is passed
@racket[binding]s that use the name. the input name, and results in all the @racket[binding]s that use the
name.
} }
@defproc[(text-input [#:value value (or/c false/c bytes?) #f] @defproc[(text-input [#:value value (or/c false/c bytes?) #f]
@ -292,7 +295,8 @@ These @tech{formlet}s are the main combinators for form input.
[#:read-only? read-only? boolean? #f] [#:read-only? read-only? boolean? #f]
[#:attributes attrs (listof (list/c symbol? string?)) empty]) [#:attributes attrs (listof (list/c symbol? string?)) empty])
(formlet/c (or/c false/c binding?))]{ (formlet/c (or/c false/c binding?))]{
This @tech{formlet} renders using an INPUT element with the TEXT type and the attributes given in the arguments. This @tech{formlet} renders using an INPUT element with the TEXT type
and the attributes given in the arguments.
} }
@defproc[(password-input [#:value value (or/c false/c bytes?) #f] @defproc[(password-input [#:value value (or/c false/c bytes?) #f]
@ -301,7 +305,8 @@ These @tech{formlet}s are the main combinators for form input.
[#:read-only? read-only? boolean? #f] [#:read-only? read-only? boolean? #f]
[#:attributes attrs (listof (list/c symbol? string?)) empty]) [#:attributes attrs (listof (list/c symbol? string?)) empty])
(formlet/c (or/c false/c binding?))]{ (formlet/c (or/c false/c binding?))]{
This @tech{formlet} renders using an INPUT element with the PASSWORD type and the attributes given in the arguments. This @tech{formlet} renders using an INPUT element with the PASSWORD
type and the attributes given in the arguments.
} }
@defproc[(textarea-input [#:value value (or/c false/c bytes?) #f] @defproc[(textarea-input [#:value value (or/c false/c bytes?) #f]
@ -309,14 +314,16 @@ These @tech{formlet}s are the main combinators for form input.
[#:cols cols (or/c false/c number?) #f] [#:cols cols (or/c false/c number?) #f]
[#:attributes attrs (listof (list/c symbol? string?)) empty]) [#:attributes attrs (listof (list/c symbol? string?)) empty])
(formlet/c (or/c false/c binding?))]{ (formlet/c (or/c false/c binding?))]{
This @tech{formlet} renders using an TEXTAREA element with attributes given in the arguments. This @tech{formlet} renders using an TEXTAREA element with attributes
given in the arguments.
} }
@defproc[(checkbox [value bytes?] @defproc[(checkbox [value bytes?]
[checked? boolean?] [checked? boolean?]
[#:attributes attrs (listof (list/c symbol? string?)) empty]) [#:attributes attrs (listof (list/c symbol? string?)) empty])
(formlet/c (or/c false/c binding?))]{ (formlet/c (or/c false/c binding?))]{
This @tech{formlet} renders using an INPUT element with the CHECKBOX type and the attributes given in the arguments. This @tech{formlet} renders using an INPUT element with the CHECKBOX
type and the attributes given in the arguments.
} }
@defproc[(radio [value bytes?] @defproc[(radio [value bytes?]
@ -329,23 +336,27 @@ These @tech{formlet}s are the main combinators for form input.
@defproc[(submit [value bytes?] @defproc[(submit [value bytes?]
[#:attributes attrs (listof (list/c symbol? string?)) empty]) [#:attributes attrs (listof (list/c symbol? string?)) empty])
(formlet/c (or/c false/c binding?))]{ (formlet/c (or/c false/c binding?))]{
This @tech{formlet} renders using an INPUT element with the SUBMIT type and the attributes given in the arguments. This @tech{formlet} renders using an INPUT element with the SUBMIT
type and the attributes given in the arguments.
} }
@defproc[(reset [value bytes?] @defproc[(reset [value bytes?]
[#:attributes attrs (listof (list/c symbol? string?)) empty]) [#:attributes attrs (listof (list/c symbol? string?)) empty])
(formlet/c (or/c false/c binding?))]{ (formlet/c (or/c false/c binding?))]{
This @tech{formlet} renders using an INPUT element with the RESET type and the attributes given in the arguments. This @tech{formlet} renders using an INPUT element with the RESET type
and the attributes given in the arguments.
} }
@defproc[(file-upload [#:attributes attrs (listof (list/c symbol? string?)) empty]) @defproc[(file-upload [#:attributes attrs (listof (list/c symbol? string?)) empty])
(formlet/c (or/c false/c binding?))]{ (formlet/c (or/c false/c binding?))]{
This @tech{formlet} renders using an INPUT element with the FILE type and the attributes given in the arguments. This @tech{formlet} renders using an INPUT element with the FILE type
and the attributes given in the arguments.
} }
@defproc[(hidden [value bytes?] [#:attributes attrs (listof (list/c symbol? string?)) empty]) @defproc[(hidden [value bytes?] [#:attributes attrs (listof (list/c symbol? string?)) empty])
(formlet/c (or/c false/c binding?))]{ (formlet/c (or/c false/c binding?))]{
This @tech{formlet} renders using an INPUT element with HIDDEN type and the attributes given in the arguments. This @tech{formlet} renders using an INPUT element with HIDDEN type
and the attributes given in the arguments.
} }
@defproc[(img [alt bytes?] @defproc[(img [alt bytes?]
@ -356,7 +367,8 @@ These @tech{formlet}s are the main combinators for form input.
[#:width width (or/c false/c exact-nonnegative-integer?) #f] [#:width width (or/c false/c exact-nonnegative-integer?) #f]
[#:attributes attrs (listof (list/c symbol? string?)) empty]) [#:attributes attrs (listof (list/c symbol? string?)) empty])
(formlet/c (or/c false/c binding?))]{ (formlet/c (or/c false/c binding?))]{
This @tech{formlet} renders using an IMG element with the attributes given in the arguments. This @tech{formlet} renders using an IMG element with the attributes
given in the arguments.
} }
@defproc[(button [type bytes?] @defproc[(button [type bytes?]
@ -365,7 +377,9 @@ These @tech{formlet}s are the main combinators for form input.
[#:value value (or/c false/c bytes?) #f] [#:value value (or/c false/c bytes?) #f]
[#:attributes attrs (listof (list/c symbol? string?)) empty]) [#:attributes attrs (listof (list/c symbol? string?)) empty])
(formlet/c (or/c false/c binding?))]{ (formlet/c (or/c false/c binding?))]{
This @tech{formlet} renders using a BUTTON element with the attributes given in the arguments. @racket[button-text] is the text that will appear on the button when rendered. This @tech{formlet} renders using a BUTTON element with the attributes
given in the arguments. @racket[button-text] is the text that will
appear on the button when rendered.
} }
@defproc[(multiselect-input [l sequence?] @defproc[(multiselect-input [l sequence?]
@ -374,7 +388,11 @@ These @tech{formlet}s are the main combinators for form input.
[#:selected? selected? (any/c . -> . boolean?) (λ (x) #f)] [#:selected? selected? (any/c . -> . boolean?) (λ (x) #f)]
[#:display display (any/c . -> . xexpr/c) (λ (x) x)]) [#:display display (any/c . -> . xexpr/c) (λ (x) x)])
(formlet/c list?)]{ (formlet/c list?)]{
This @tech{formlet} renders using an SELECT element with the attributes given with an OPTION for each element of the sequence. If @racket[multiple?] is @racket[#t], then multiple options may be selected. An element is selected if @racket[selected?] returns @racket[#t]. Elements are displayed with @racket[display]. This @tech{formlet} renders using an SELECT element with the
attributes given with an OPTION for each element of the sequence. If
@racket[multiple?] is @racket[#t], then multiple options may be
selected. An element is selected if @racket[selected?] returns
@racket[#t]. Elements are displayed with @racket[display].
} }
@defproc[(select-input [l sequence?] @defproc[(select-input [l sequence?]
@ -382,39 +400,50 @@ These @tech{formlet}s are the main combinators for form input.
[#:selected? selected? (any/c . -> . boolean?) (λ (x) #f)] [#:selected? selected? (any/c . -> . boolean?) (λ (x) #f)]
[#:display display (any/c . -> . xexpr/c) (λ (x) x)]) [#:display display (any/c . -> . xexpr/c) (λ (x) x)])
(formlet/c any/c)]{ (formlet/c any/c)]{
This @tech{formlet} renders using an SELECT element with the attributes given with an OPTION for each element of the sequence. An element is selected if @racket[selected?] returns @racket[#t]. Elements are displayed with @racket[display]. This @tech{formlet} renders using an SELECT element with the
attributes given with an OPTION for each element of the sequence. An
element is selected if @racket[selected?] returns
@racket[#t]. Elements are displayed with @racket[display].
} }
@defproc[(required [f (formlet/c (or/c false/c binding?))]) @defproc[(required [f (formlet/c (or/c false/c binding?))])
(formlet/c bytes?)]{ (formlet/c bytes?)]{
Constructs a @tech{formlet} that extracts the @racket[binding:form-value] from the binding produced by @racket[f], or errors. Constructs a @tech{formlet} that extracts the
@racket[binding:form-value] from the binding produced by @racket[f],
or errors.
} }
@defproc[(default @defproc[(default
[def bytes?] [def bytes?]
[f (formlet/c (or/c false/c binding?))]) [f (formlet/c (or/c false/c binding?))])
(formlet/c bytes?)]{ (formlet/c bytes?)]{
Constructs a @tech{formlet} that extracts the @racket[binding:form-value] from the binding produced by @racket[f], or returns @racket[def]. Constructs a @tech{formlet} that extracts the
@racket[binding:form-value] from the binding produced by @racket[f],
or returns @racket[def].
} }
@defproc[(to-string [f (formlet/c bytes?)]) @defproc[(to-string [f (formlet/c bytes?)])
(formlet/c string?)]{ (formlet/c string?)]{
Converts @racket[f]'s output to a string. Equivalent to @racket[(cross (pure bytes->string/utf-8) f)]. Converts @racket[f]'s output to a string. Equivalent to
@racket[(cross (pure bytes->string/utf-8) f)].
} }
@defproc[(to-number [f (formlet/c string?)]) @defproc[(to-number [f (formlet/c string?)])
(formlet/c number?)]{ (formlet/c number?)]{
Converts @racket[f]'s output to a number. Equivalent to @racket[(cross (pure string->number) f)]. Converts @racket[f]'s output to a number. Equivalent to @racket[(cross
(pure string->number) f)].
} }
@defproc[(to-symbol [f (formlet/c string?)]) @defproc[(to-symbol [f (formlet/c string?)])
(formlet/c symbol?)]{ (formlet/c symbol?)]{
Converts @racket[f]'s output to a symbol. Equivalent to @racket[(cross (pure string->symbol) f)]. Converts @racket[f]'s output to a symbol. Equivalent to
@racket[(cross (pure string->symbol) f)].
} }
@defproc[(to-boolean [f (formlet/c bytes?)]) @defproc[(to-boolean [f (formlet/c bytes?)])
(formlet/c boolean?)]{ (formlet/c boolean?)]{
Converts @racket[f]'s output to a boolean, if it is equal to @racket[#"on"]. Converts @racket[f]'s output to a boolean, if it is equal to
@racket[#"on"].
} }
@defthing[input-string (formlet/c string?)]{ @defthing[input-string (formlet/c string?)]{
@ -446,16 +475,18 @@ A few utilities are provided for using @tech{formlet}s in Web applications.
`(html (head (title "Form Entry")) `(html (head (title "Form Entry"))
(body ,form-xexpr)))]) (body ,form-xexpr)))])
(values any/c ...)]{ (values any/c ...)]{
Uses @racket[send/suspend] and @racket[response/xexpr] to send @racket[f]'s rendering (wrapped in a FORM tag whose action is Uses @racket[send/suspend] and @racket[response/xexpr] to send
the continuation URL (wrapped again by @racket[wrapper])) to the client. @racket[f]'s rendering (wrapped in a FORM tag whose action is the
When the form is submitted, the request is passed to the continuation URL (wrapped again by @racket[wrapper])) to the client.
processing stage of @racket[f]. When the form is submitted, the request is passed to the processing
stage of @racket[f].
} }
@defproc[(embed-formlet [embed/url ((request? . -> . any) . -> . string?)] @defproc[(embed-formlet [embed/url ((request? . -> . any) . -> . string?)]
[f (formlet/c any/c ...)]) [f (formlet/c any/c ...)])
xexpr/c]{ xexpr/c]{
Like @racket[send/formlet], but for use with @racket[send/suspend/dispatch]. Like @racket[send/formlet], but for use with
@racket[send/suspend/dispatch].
} }
} }

View File

@ -278,8 +278,9 @@ transmission that the server @bold{will not catch}.}
[domain (or/c false/c valid-domain?)] [domain (or/c false/c valid-domain?)]
[path (or/c false/c string?)])]{ [path (or/c false/c string?)])]{
While server cookies are represented with @racket[cookie?]s, cookies that come from the client are represented While server cookies are represented with @racket[cookie?]s, cookies
with a @racket[client-cookie] structure. that come from the client are represented with a
@racket[client-cookie] structure.
} }
@defproc[(request-cookies [req request?]) @defproc[(request-cookies [req request?])
@ -423,15 +424,19 @@ An implementation of HTTP Digest Authentication.
@defproc[(password->digest-HA1 [lookup-password username*realm->password/c]) @defproc[(password->digest-HA1 [lookup-password username*realm->password/c])
username*realm->digest-HA1/c]{ username*realm->digest-HA1/c]{
Uses @racket[lookup-password] to find the password, then computes the secret hash of it. Uses @racket[lookup-password] to find the password, then computes the
secret hash of it.
} }
@defproc[(make-check-digest-credentials [lookup-HA1 username*realm->digest-HA1/c]) @defproc[(make-check-digest-credentials [lookup-HA1 username*realm->digest-HA1/c])
(string? (listof (cons/c symbol? string?)) . -> . boolean?)]{ (string? (listof (cons/c symbol? string?)) . -> . boolean?)]{
Constructs a function that checks whether particular Digest credentials (the second argument of the returned function) Constructs a function that checks whether particular Digest credentials
are correct given the HTTP method provided as the first argument and the secret hash computed by @racket[lookup-HA1]. (the second argument of the returned function) are correct given the
HTTP method provided as the first argument and the secret hash computed
by @racket[lookup-HA1].
This is will result in an exception if the Digest credentials are missing portions. This is will result in an exception if the Digest credentials are
missing portions.
} }
Example: Example:

View File

@ -21,10 +21,11 @@ of @racketmodname[web-server/dispatchers/dispatch-servlets].
@defproc[(make-make-servlet-namespace (#:to-be-copied-module-specs to-be-copied-module-specs (listof module-path?))) @defproc[(make-make-servlet-namespace (#:to-be-copied-module-specs to-be-copied-module-specs (listof module-path?)))
make-servlet-namespace/c]{ make-servlet-namespace/c]{
This function creates a function that when called will construct a new @racket[namespace] that This function creates a function that when called will construct a new
has all the modules from @racket[to-be-copied-module-specs] and @racket[additional-specs], as well @racket[namespace] that has all the modules from
as @racket[racket] and @racket[mred], provided they are already attached @racket[to-be-copied-module-specs] and @racket[additional-specs], as
to the @racket[(current-namespace)] of the call-site. well as @racket[racket] and @racket[mred], provided they are already
attached to the @racket[(current-namespace)] of the call-site.
Example: Example:
@racketblock[ @racketblock[
@ -37,14 +38,17 @@ Example:
@section{Why this is useful} @section{Why this is useful}
A different namespace is needed for each servlet, so that if servlet A and servlet B both use A different namespace is needed for each servlet, so that if servlet A
a stateful module C, they will be isolated from one another. We see the @web-server as and servlet B both use a stateful module C, they will be isolated from
an operating system for servlets, so we inherit the isolation requirement on operating systems. one another. We see the @web-server as an operating system for servlets,
so we inherit the isolation requirement on operating systems.
However, there are some modules which must be shared. If they were not, then structures cannot However, there are some modules which must be shared. If they were not,
be passed from the @web-server to the servlets, because Racket's structures are generative. then structures cannot be passed from the @web-server to the servlets,
because Racket's structures are generative.
Since, on occasion, a user will actually wanted servlets A and B to interact through module C. Since, on occasion, a user will actually wanted servlets A and B to
A custom @racket[make-servlet-namespace] can be created, through this procedure, that attaches interact through module C. A custom @racket[make-servlet-namespace] can
module C to all servlet namespaces. Through other means (see @secref["dispatchers"]) different sets be created, through this procedure, that attaches module C to all
of servlets can share different sets of modules. servlet namespaces. Through other means (see @secref["dispatchers"])
different sets of servlets can share different sets of modules.

View File

@ -9,12 +9,17 @@
@defmodule[web-server/lang/native]{ @defmodule[web-server/lang/native]{
It is sometimes inconvenient to use @racket[serial->native] and @racket[native->serial] throughout your program. It is sometimes inconvenient to use @racket[serial->native] and
This module provides a macro for creating wrappers. @racket[native->serial] throughout your program. This module provides a
macro for creating wrappers.
@defform[#:literals (ho) (define-native (native arg-spec ...) original) #:contracts ([arg-spec ho] [arg-spec _])]{ @defform[#:literals (ho)
Builds an interface around @racket[original] named @racket[native] such that calls to @racket[native] are wrapped in @racket[serial->native] (define-native (native arg-spec ...) original)
and all arguments marked with @racket[ho] in @racket[arg-spec] are assumed to procedures and are wrapped in @racket[native->serial]. #:contracts ([arg-spec ho] [arg-spec _])]{
Builds an interface around @racket[original] named @racket[native] such
that calls to @racket[native] are wrapped in @racket[serial->native]
and all arguments marked with @racket[ho] in @racket[arg-spec] are
assumed to procedures and are wrapped in @racket[native->serial].
For example, For example,
@racketblock[ @racketblock[

View File

@ -39,33 +39,59 @@ A simple example:
"You clicked!"))]) "You clicked!"))])
"Click me")))))] "Click me")))))]
Similarly, many Web applications make use almost exclusively of functions that are arguments to @racket[embed/url] and immediately invoke @racket[send/suspend/dispatch]. Similarly, many Web applications make use almost exclusively of
functions that are arguments to @racket[embed/url] and immediately
invoke @racket[send/suspend/dispatch].
@deftogether[[@defform[(lambda/page formals e ...)] @deftogether[[@defform[(lambda/page formals e ...)]
@defform[(define/page (id . formals) e ...)]]]{ @defform[(define/page (id . formals) e ...)]]]{
The @racket[lambda/page] and @racket[define/page] automate this by expanding to functions that accept a request as the first argument (followed by any arguments specified in @racket[formals]) and immediately wrap their body in @racket[page]. This functions also cooperate with @racket[get-binding] by binding the request to the @racket[current-request] parameter. The @racket[lambda/page] and @racket[define/page] automate this by
expanding to functions that accept a request as the first argument
(followed by any arguments specified in @racket[formals]) and
immediately wrap their body in @racket[page]. This functions also
cooperate with @racket[get-binding] by binding the request to the
@racket[current-request] parameter.
} }
The binding interface of @racketmodname[web-server/http] is powerful, but subtle to use conveniently due to its protection against hostile clients. The binding interface of @racketmodname[web-server/http] is powerful,
but subtle to use conveniently due to its protection against hostile
clients.
@deftogether[[ @deftogether[[
@defparam[current-request req request?] @defparam[current-request req request?]
@defthing[binding-id/c contract?] @defthing[binding-id/c contract?]
@defthing[binding-format/c contract?] @defthing[binding-format/c contract?]
@defproc[(get-binding [id binding-id/c] [req request? (current-request)] [#:format format binding-format/c 'string]) @defproc[(get-binding [id binding-id/c]
[req request? (current-request)]
[#:format format binding-format/c 'string])
(or/c false/c string? bytes? binding?)] (or/c false/c string? bytes? binding?)]
@defproc[(get-bindings [id binding-id/c] [req request? (current-request)] [#:format format binding-format/c 'string]) @defproc[(get-bindings [id binding-id/c]
[req request? (current-request)]
[#:format format binding-format/c 'string])
(listof (or/c string? bytes? binding?))] (listof (or/c string? bytes? binding?))]
]]{ ]]{
The @racket[get-binding](s) interface attempts to resolve this by providing a powerful interface with convenient defaults. The @racket[get-binding](s) interface attempts to resolve this by
providing a powerful interface with convenient defaults.
@racket[get-binding] extracts the first binding of a form input from a request, while @racket[get-bindings] extracts them all. @racket[get-binding] extracts the first binding of a form input from a
request, while @racket[get-bindings] extracts them all.
They accept a form identifier (@racket[id]) as either a byte string, a string, or a symbol. In each case, the user input is compared in a case-sensitive way with the form input. They accept a form identifier (@racket[id]) as either a byte string, a
string, or a symbol. In each case, the user input is compared in a
case-sensitive way with the form input.
They accept an optional request argument (@racket[req]) that defaults to the value of the @racket[current-request] parameter used by @racket[lambda/page] and @racket[define/page]. They accept an optional request argument (@racket[req]) that defaults
to the value of the @racket[current-request] parameter used by
@racket[lambda/page] and @racket[define/page].
Finally, they accept an optional keyword argument (@racket[format]) that specifies the desired return format. The default, @racket['string], produces a UTF-8 string (or @racket[#f] if the byte string cannot be converted to UTF-8.) The @racket['bytes] format always produces the raw byte string. The @racket['file] format produces the file upload content (or @racket[#f] if the form input was not an uploaded file.) The @racket['binding] format produces the binding object. Finally, they accept an optional keyword argument (@racket[format])
that specifies the desired return format. The default,
@racket['string], produces a UTF-8 string (or @racket[#f] if the byte
string cannot be converted to UTF-8.) The @racket['bytes] format
always produces the raw byte string. The @racket['file] format
produces the file upload content (or @racket[#f] if the form input was
not an uploaded file.) The @racket['binding] format produces the
binding object.
} }

View File

@ -8,70 +8,88 @@
@defmodule[web-server/configuration/responders]{ @defmodule[web-server/configuration/responders]{
This module provides some functions that help constructing HTTP responders. This module provides some functions that help constructing HTTP
These functions are used by the default dispatcher constructor (see @secref["web-server-unit"]) to responders. These functions are used by the default dispatcher
turn the paths given in the @racket[configuration-table] into responders for the associated circumstance. constructor (see @secref["web-server-unit"]) to turn the paths given in
the @racket[configuration-table] into responders for the associated
circumstance.
@defproc[(file-response (http-code natural-number/c) (short-version string?) (text-file string?) (header header?) ...) @defproc[(file-response [http-code natural-number/c]
[short-version string?]
[text-file string?]
[header header?] ...)
response?]{ response?]{
Generates a @racket[response?] with the given @racket[http-code] and @racket[short-version] Generates a @racket[response?] with the given @racket[http-code] and
as the corresponding fields; with the content of the @racket[text-file] as the body; and, with @racket[short-version] as the corresponding fields; with the content of
the @racket[header]s as, you guessed it, headers. the @racket[text-file] as the body; and, with the @racket[header]s as,
you guessed it, headers.
This does not cause redirects to a well-known URL, such as @filepath{conf/not-found.html}, but rather use the contents This does not cause redirects to a well-known URL, such as
of @filepath{not-found.html} (for example) as its contents. Therefore, any relative URLs in @racket[text-file] are relative @filepath{conf/not-found.html}, but rather use the contents of
to whatever URL @racket[file-response] is used to respond @emph{to}. Thus, you should probably use absolute URLs in these files. @filepath{not-found.html} (for example) as its contents. Therefore, any
relative URLs in @racket[text-file] are relative to whatever URL
@racket[file-response] is used to respond @emph{to}. Thus, you should
probably use absolute URLs in these files.
} }
@defproc[(servlet-loading-responder (url url?) (exn exn?)) @defproc[(servlet-loading-responder [url url?] [exn exn?])
response?]{ response?]{
Gives @racket[exn] to the @racket[current-error-handler] and response with a stack trace and a "Servlet didn't load" message. Gives @racket[exn] to the @racket[current-error-handler] and response
with a stack trace and a "Servlet didn't load" message.
} }
@defproc[(gen-servlet-not-found (file path-string?)) @defproc[(gen-servlet-not-found [file path-string?])
((url url?) . -> . response?)]{ ((url url?) . -> . response?)]{
Returns a function that generates a standard "Servlet not found." error with content from @racket[file]. Returns a function that generates a standard "Servlet not found." error
with content from @racket[file].
} }
@defproc[(servlet-error-responder (url url?) (exn exn?)) @defproc[(servlet-error-responder [url url?] [exn exn?])
response?]{ response?]{
Gives @racket[exn] to the @racket[current-error-handler] and response with a stack trace and a "Servlet error" message. Gives @racket[exn] to the @racket[current-error-handler] and response
with a stack trace and a "Servlet error" message.
} }
@defproc[(gen-servlet-responder (file path-string?)) @defproc[(gen-servlet-responder [file path-string?])
((url url?) (exn any/c) . -> . response?)]{ ((url url?) (exn any/c) . -> . response?)]{
Prints the @racket[exn] to standard output and responds with a "Servlet error." message with content from @racket[file]. Prints the @racket[exn] to standard output and responds with a "Servlet
error." message with content from @racket[file].
} }
@defproc[(gen-servlets-refreshed (file path-string?)) @defproc[(gen-servlets-refreshed [file path-string?])
(-> response?)]{ (-> response?)]{
Returns a function that generates a standard "Servlet cache refreshed." message with content from @racket[file]. Returns a function that generates a standard "Servlet cache refreshed."
message with content from @racket[file].
} }
@defproc[(gen-passwords-refreshed (file path-string?)) @defproc[(gen-passwords-refreshed [file path-string?])
(-> response?)]{ (-> response?)]{
Returns a function that generates a standard "Passwords refreshed." message with content from @racket[file]. Returns a function that generates a standard "Passwords refreshed."
message with content from @racket[file].
} }
@defproc[(gen-authentication-responder (file path-string?)) @defproc[(gen-authentication-responder [file path-string?])
((url url?) (header header?) . -> . response?)]{ ((url url?) (header header?) . -> . response?)]{
Returns a function that generates an authentication failure error with content from @racket[file] and Returns a function that generates an authentication failure error with
@racket[header] as the HTTP header. content from @racket[file] and @racket[header] as the HTTP header.
} }
@defproc[(gen-protocol-responder (file path-string?)) @defproc[(gen-protocol-responder [file path-string?])
((url url?) . -> . response?)]{ ((url url?) . -> . response?)]{
Returns a function that generates a "Malformed request" error with content from @racket[file]. Returns a function that generates a "Malformed request" error with
content from @racket[file].
} }
@defproc[(gen-file-not-found-responder (file path-string?)) @defproc[(gen-file-not-found-responder [file path-string?])
((req request?) . -> . response?)]{ ((req request?) . -> . response?)]{
Returns a function that generates a standard "File not found" error with content from @racket[file]. Returns a function that generates a standard "File not found" error
with content from @racket[file].
} }
@defproc[(gen-collect-garbage-responder (file path-string?)) @defproc[(gen-collect-garbage-responder [file path-string?])
(-> response?)]{ (-> response?)]{
Returns a function that generates a standard "Garbage collection run" message with content from @racket[file]. Returns a function that generates a standard "Garbage collection run"
message with content from @racket[file].
} }
} }

View File

@ -23,7 +23,10 @@ and increasing the size of the serialization. This module provides support for t
@defproc[(soft-state-ref [ss soft-state?]) @defproc[(soft-state-ref [ss soft-state?])
any/c]{ any/c]{
Extracts the value associated with @racket[ss]. If the value is not available (perhaps because of garbage collection, deserialization in an uninitialized process, etc), then the thunk associated with @racket[ss] is invoked and the value is cached. Extracts the value associated with @racket[ss]. If the value is not
available (perhaps because of garbage collection, deserialization in an
uninitialized process, etc), then the thunk associated with @racket[ss]
is invoked and the value is cached.
} }
@defform[(soft-state expr ...)]{ @defform[(soft-state expr ...)]{

View File

@ -6,10 +6,11 @@
@title[#:tag "considerations"]{Usage Considerations} @title[#:tag "considerations"]{Usage Considerations}
A stateless servlet has the following process performed on it automatically: A stateless servlet has the following process performed on it
automatically:
@itemize[ @itemize[
@item{All uses of @racket[letrec] are removed and replaced with equivalent uses of @item{All uses of @racket[letrec] are removed and replaced with
@racket[let] and imperative features.} equivalent uses of @racket[let] and imperative features.}
@item{The program is converted into @link["http://en.wikipedia.org/wiki/Administrative_normal_form"]{ANF} (Administrative Normal Form), @item{The program is converted into @link["http://en.wikipedia.org/wiki/Administrative_normal_form"]{ANF} (Administrative Normal Form),
making all continuations explicit.} making all continuations explicit.}
@item{All continuations and continuations marks are recorded in the @item{All continuations and continuations marks are recorded in the
@ -22,41 +23,47 @@ A stateless servlet has the following process performed on it automatically:
@racket[lambda].} @racket[lambda].}
] ]
This process allows the continuations captured by your servlet to be serialized. This process allows the continuations captured by your servlet to be
This means they may be stored on the client's browser or the server's disk. serialized. This means they may be stored on the client's browser or
the server's disk.
This means your servlet has no cost to the server other than execution. This is This means your servlet has no cost to the server other than
very attractive if you've used Racket servlets and had memory problems. execution. This is very attractive if you've used Racket servlets and
had memory problems.
This means your server can restart in the middle of a long running Web interaction This means your server can restart in the middle of a long running Web
without the URLs that have been shared with the client expiring. This is interaction without the URLs that have been shared with the client
very attractive if you've used Racket servlets and had session timeout problems. expiring. This is very attractive if you've used Racket servlets and
had session timeout problems.
This process is defined on all of Racket and occurs after macro-expansion, This process is defined on all of Racket and occurs after
so you are free to use all interesting features of Racket. However, there macro-expansion, so you are free to use all interesting features of
are some considerations you must make. Racket. However, there are some considerations you must make.
First, this process drastically changes the structure of your program. It First, this process drastically changes the structure of your program.
will create an immense number of lambdas and structures your program It will create an immense number of lambdas and structures your program
did not normally contain. The performance implication of this has not been did not normally contain. The performance implication of this has not
studied with Racket. been studied with Racket.
Second, the defunctionalization process is sensitive to the syntactic structure Second, the defunctionalization process is sensitive to the syntactic
of your program. Therefore, if you change your program in a trivial way, for example, structure of your program. Therefore, if you change your program in a
changing a constant, then all serialized continuations will be obsolete and will trivial way, for example, changing a constant, then all serialized
error when deserialization is attempted. This is a feature, not a bug! It is a small continuations will be obsolete and will error when deserialization is
price to pay for protection from the sorts of errors that would occur if your program attempted. This is a feature, not a bug! It is a small price to pay for
protection from the sorts of errors that would occur if your program
were changed in a meaningful way. were changed in a meaningful way.
Third, the values in the lexical scope of your continuations must be serializable Third, the values in the lexical scope of your continuations must be
for the continuations itself to be serializable. This means that you must use serializable for the continuations itself to be serializable. This means
@racket[define-serializable-struct] rather than @racket[define-struct], and take that you must use @racket[define-serializable-struct] rather than
care to use modules that do the same. Similarly, you may not use @racket[parameterize], @racket[define-struct], and take care to use modules that do the same.
because parameterizations are not serializable. Similarly, you may not use @racket[parameterize], because
parameterizations are not serializable.
Fourth, and related, this process only runs on your code, not on the code you Fourth, and related, this process only runs on your code, not on the
@racket[require]. Thus, your continuations---to be serializable---must not code you @racket[require]. Thus, your continuations---to be
be in the context of another module. For example, the following will fail with an @as-index{"unsafe context"} serializable---must not be in the context of another module. For
example, the following will fail with an @as-index{"unsafe context"}
exception: exception:
@racketblock[ @racketblock[

View File

@ -52,8 +52,9 @@ You can supply your own (built with these functions) when you write a stateless
@defproc[(stuffer-compose [g (stuffer/c any/c any/c)] @defproc[(stuffer-compose [g (stuffer/c any/c any/c)]
[f (stuffer/c any/c any/c)]) [f (stuffer/c any/c any/c)])
(stuffer/c any/c any/c)]{ (stuffer/c any/c any/c)]{
Composes @racket[f] and @racket[g], i.e., applies @racket[f] then @racket[g] for @racket[in] Composes @racket[f] and @racket[g], i.e., applies @racket[f] then
and @racket[g] then @racket[f] for @racket[out]. @racket[g] for @racket[in] and @racket[g] then @racket[f] for
@racket[out].
} }
@defproc[(stuffer-sequence [f (stuffer/c any/c any/c)] @defproc[(stuffer-sequence [f (stuffer/c any/c any/c)]
@ -65,9 +66,10 @@ You can supply your own (built with these functions) when you write a stateless
@defproc[(stuffer-if [c (bytes? . -> . boolean?)] @defproc[(stuffer-if [c (bytes? . -> . boolean?)]
[f (stuffer/c bytes? bytes?)]) [f (stuffer/c bytes? bytes?)])
(stuffer/c bytes? bytes?)]{ (stuffer/c bytes? bytes?)]{
Creates a @tech{stuffer} that stuffs with @racket[f] if @racket[c] is true on the input Creates a @tech{stuffer} that stuffs with @racket[f] if @racket[c] is
to @racket[in]. Similarly, applies @racket[f] during @racket[out] if it was applied during true on the input to @racket[in]. Similarly, applies @racket[f] during
@racket[in] (which is recorded by prepending a byte.) @racket[out] if it was applied during @racket[in] (which is recorded by
prepending a byte.)
} }
@defproc[(stuffer-chain [x (or/c stuffer? (bytes? . -> . boolean?))] @defproc[(stuffer-chain [x (or/c stuffer? (bytes? . -> . boolean?))]
@ -85,7 +87,8 @@ You can supply your own (built with these functions) when you write a stateless
@defmodule[web-server/stuffers/serialize]{ @defmodule[web-server/stuffers/serialize]{
@defthing[serialize-stuffer (stuffer/c serializable? bytes?)]{ @defthing[serialize-stuffer (stuffer/c serializable? bytes?)]{
A @tech{stuffer} that uses @racket[serialize] and @racket[write/bytes] and @racket[deserialize] and @racket[read/bytes]. A @tech{stuffer} that uses @racket[serialize] and @racket[write/bytes]
and @racket[deserialize] and @racket[read/bytes].
} }
} }
@ -111,14 +114,16 @@ You can supply your own (built with these functions) when you write a stateless
@defthing[gzip-stuffer (stuffer/c bytes? bytes?)]{ @defthing[gzip-stuffer (stuffer/c bytes? bytes?)]{
A @tech{stuffer} that uses @racket[gzip/bytes] and @racket[gunzip/bytes]. A @tech{stuffer} that uses @racket[gzip/bytes] and @racket[gunzip/bytes].
@warning{You should compose this with @racket[base64-stuffer] to get URL-safe bytes.} @warning{You should compose this with @racket[base64-stuffer] to get
URL-safe bytes.}
} }
} }
@section{Key/Value Storage} @section{Key/Value Storage}
The @racketmodname[web-server/stuffers/hash] @tech{stuffers} rely on a key/value store. The @racketmodname[web-server/stuffers/hash] @tech{stuffers} rely on a
key/value store.
@defmodule[web-server/stuffers/store]{ @defmodule[web-server/stuffers/store]{
@ -155,8 +160,10 @@ The @racketmodname[web-server/stuffers/hash] @tech{stuffers} rely on a key/value
@defproc[(hash-stuffer [H hash-fun/c] @defproc[(hash-stuffer [H hash-fun/c]
[store store?]) [store store?])
(stuffer/c bytes? bytes?)]{ (stuffer/c bytes? bytes?)]{
A content-addressed storage @tech{stuffer} that stores input bytes, @racket[input], in @racket[store] with the key @racket[(H input)] A content-addressed storage @tech{stuffer} that stores input bytes,
and returns the key. Similarly, on @racket[out] the original bytes are looked up. @racket[input], in @racket[store] with the key @racket[(H input)] and
returns the key. Similarly, on @racket[out] the original bytes are
looked up.
} }
@defproc[(md5-stuffer [root path-string?]) @defproc[(md5-stuffer [root path-string?])
@ -172,24 +179,32 @@ The @racketmodname[web-server/stuffers/hash] @tech{stuffers} rely on a key/value
@defproc[(HMAC-SHA1 [kb bytes?] [db bytes?]) @defproc[(HMAC-SHA1 [kb bytes?] [db bytes?])
bytes?]{ bytes?]{
Performs a HMAC-SHA1 calculation on @racket[db] using @racket[kb] as the key. The result is guaranteed to be 20 bytes. Performs a HMAC-SHA1 calculation on @racket[db] using @racket[kb] as
(You could curry this to use it with @racket[hash-stuffer], but there is little value in doing so over @racket[md5].) the key. The result is guaranteed to be 20 bytes. (You could curry
this to use it with @racket[hash-stuffer], but there is little value
in doing so over @racket[md5].)
} }
@defproc[(HMAC-SHA1-stuffer [kb bytes?]) @defproc[(HMAC-SHA1-stuffer [kb bytes?])
(stuffer/c bytes? bytes?)]{ (stuffer/c bytes? bytes?)]{
A @tech{stuffer} that signs input using @racket[HMAC-SHA1] with @racket[kb] as the key. The result of the @tech{stuffer} is A @tech{stuffer} that signs input using @racket[HMAC-SHA1] with
the hash prepended to the input data. When the @tech{stuffer} is run in reverse, it checks if the first 20 bytes are the correct @racket[kb] as the key. The result of the @tech{stuffer} is the hash
has for the rest of the data. prepended to the input data. When the @tech{stuffer} is run in
reverse, it checks if the first 20 bytes are the correct has for the
rest of the data.
@warning{You should compose this with @racket[base64-stuffer] to get URL-safe bytes.} @warning{You should compose this with @racket[base64-stuffer] to get
URL-safe bytes.}
@warning{Without explicit provision, it is possible for users to modify the continuations they are sent through the other @tech{stuffers}. @warning{Without explicit provision, it is possible for users to
This @tech{stuffer} allows the servlet to certify that stuffed data was truly generated by the servlet. Therefore, you @bold{should} use this modify the continuations they are sent through the other
if you are not using the @racket[hash-stuffer]s.} @tech{stuffers}. This @tech{stuffer} allows the servlet to certify
that stuffed data was truly generated by the servlet. Therefore, you
@bold{should} use this if you are not using the
@racket[hash-stuffer]s.}
@warning{This @tech{stuffer} does @bold{not} encrypt the data in anyway, so users can still observe the stuffed values.} @warning{This @tech{stuffer} does @bold{not} encrypt the data in
anyway, so users can still observe the stuffed values.}
} }
} }
@ -200,14 +215,17 @@ The @racketmodname[web-server/stuffers/hash] @tech{stuffers} rely on a key/value
@defproc[(is-url-too-big? [v bytes?]) @defproc[(is-url-too-big? [v bytes?])
boolean?]{ boolean?]{
Determines if stuffing @racket[v] into the current servlet's URL would result in a URL that is too big for Internet Explorer. Determines if stuffing @racket[v] into the current servlet's URL would
(@link["http://www.boutell.com/newfaq/misc/urllength.html"]{IE only supports URLs up to 2048 characters.}) result in a URL that is too big for Internet Explorer.
(@link["http://www.boutell.com/newfaq/misc/urllength.html"]{IE only
supports URLs up to 2048 characters.})
} }
@defproc[(make-default-stuffer [root path-string?]) @defproc[(make-default-stuffer [root path-string?])
(stuffer/c serializable? bytes?)]{ (stuffer/c serializable? bytes?)]{
Constructs a @tech{stuffer} that serializes, then if the URL is too big, compresses (and base64-encodes), if the URL is still too big Constructs a @tech{stuffer} that serializes, then if the URL is too
then it stores it in an MD5-indexed database rooted at @racket[root]. big, compresses (and base64-encodes), if the URL is still too big then
it stores it in an MD5-indexed database rooted at @racket[root].
Equivalent to: Equivalent to:
@racketblock[ @racketblock[

View File

@ -36,7 +36,10 @@ This function accepts a servlet function and provides a function that accepts a
] ]
} }
This facility is designed to be used in concert with a technique of extracting continuation URLs and relevant values; @racketmodname[xml/path] is one way to do this. Here is an extended example that tests an Add-Two-Numbers.com: This facility is designed to be used in concert with a technique of
extracting continuation URLs and relevant values;
@racketmodname[xml/path] is one way to do this. Here is an extended
example that tests an Add-Two-Numbers.com:
@(require (for-label xml/path @(require (for-label xml/path
rackunit rackunit
racket/list racket/list

View File

@ -105,7 +105,12 @@ represented as an X-expression in Racket, by using
For example: For example:
The HTML @tt{hello} is represented as @racket["hello"]. Strings are automatically escaped when output. This guarantees valid HTML. Therefore, the value @racket["<b>Unfinished tag"] is rendered as @tt{&lt;b&gt;Unfinished tag} not @tt{<b>Unfinished tag}. Similarly, @racket["<i>Finished tag</i>"] is rendered as @tt{&lt;i&gt;Finished tag&lt;/i&gt;} not @tt{<i>Finished tag</i>}. The HTML @tt{hello} is represented as @racket["hello"]. Strings are
automatically escaped when output. This guarantees valid HTML.
Therefore, the value @racket["<b>Unfinished tag"] is rendered as
@tt{&lt;b&gt;Unfinished tag} not @tt{<b>Unfinished tag}. Similarly,
@racket["<i>Finished tag</i>"] is rendered as
@tt{&lt;i&gt;Finished tag&lt;/i&gt;} not @tt{<i>Finished tag</i>}.
@tt{<p>This is an example</p>} is @tt{<p>This is an example</p>} is

View File

@ -212,6 +212,7 @@ functions of interest for the servlet developer.
returns the instance id, continuation id, and nonce. returns the instance id, continuation id, and nonce.
} }
@defthing[servlet-prompt continuation-prompt-tag?]{The tag used for Web interaction continuation capture.} @defthing[servlet-prompt continuation-prompt-tag?]{
The tag used for Web interaction continuation capture.}
} }

View File

@ -47,7 +47,8 @@ Represents a location in an input stream.}
@defstruct[source ([start location/c] @defstruct[source ([start location/c]
[stop location/c])]{ [stop location/c])]{
Represents a source location. Other structure types extend @racket[source]. Represents a source location. Other structure types extend
@racket[source].
When XML is generated from an input stream by @racket[read-xml], When XML is generated from an input stream by @racket[read-xml],
locations are represented by @racket[location] instances. When XML locations are represented by @racket[location] instances. When XML
@ -174,7 +175,8 @@ and a @racket[_misc] is an instance of the @racket[comment] or
@racket[p-i] structure types.} @racket[p-i] structure types.}
@defthing[xexpr/c contract?]{ @defthing[xexpr/c contract?]{
A contract that is like @racket[xexpr?] except produces a better error message when the value is not an @tech{X-expression}. A contract that is like @racket[xexpr?] except produces a better error
message when the value is not an @tech{X-expression}.
} }
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------