85 lines
2.8 KiB
Racket
85 lines
2.8 KiB
Racket
#lang scribble/doc
|
|
@(require "web-server.ss")
|
|
|
|
@title[#:tag "web-cells.ss"]{Web Cells}
|
|
@(require (for-label web-server/servlet/web-cells))
|
|
|
|
@defmodule[web-server/servlet/web-cells]{The
|
|
@schememodname[web-server/servlet/web-cells] library provides the
|
|
interface to Web cells.
|
|
|
|
A Web cell is a kind of state defined relative to the @defterm{frame tree}.
|
|
The frame-tree is a mirror of the user's browsing session. Every time a
|
|
continuation is invoked, a new frame (called the @defterm{current frame}) is
|
|
created as a child of the current frame when the continuation was captured.
|
|
|
|
You should use Web cells if you want an effect to be encapsulated in all
|
|
interactions linked from (in a transitive sense) the HTTP response being
|
|
generated. For more information on their semantics, consult the paper
|
|
@href-link["http://www.cs.brown.edu/~sk/Publications/Papers/Published/mk-int-safe-state-web/"
|
|
"\"Interaction-Safe State for the Web\""].
|
|
|
|
@defproc[(web-cell? [v any/c])
|
|
boolean?]{
|
|
Determines if @scheme[v] is a web-cell.
|
|
}
|
|
|
|
@defproc[(make-web-cell [v any/c])
|
|
web-cell?]{
|
|
Creates a web-cell with a default value of @scheme[v].
|
|
}
|
|
|
|
@defproc[(web-cell-ref [wc web-cell?])
|
|
any/c]{
|
|
Looks up the value of @scheme[wc] found in the nearest
|
|
frame.
|
|
}
|
|
|
|
@defproc[(web-cell-shadow [wc web-cell?]
|
|
[v any/c])
|
|
void]{
|
|
Binds @scheme[wc] to @scheme[v] in the current frame, shadowing any
|
|
other bindings to @scheme[wc] in the current frame.
|
|
}
|
|
|
|
Below is an extended example that demonstrates how Web cells allow
|
|
the creation of reusable Web abstractions without requiring global
|
|
transformations of the program into continuation or store passing style.
|
|
@schememod[
|
|
web-server/insta
|
|
|
|
(define (start initial-request)
|
|
(define counter1 (make-counter))
|
|
(define counter2 (make-counter))
|
|
(define include1 (include-counter counter1))
|
|
(define include2 (include-counter counter2))
|
|
(send/suspend/dispatch
|
|
(lambda (embed/url)
|
|
`(html
|
|
(body (h2 "Double Counters")
|
|
(div (h3 "First")
|
|
,(include1 embed/url))
|
|
(div (h3 "Second")
|
|
,(include2 embed/url)))))))
|
|
|
|
(define (make-counter)
|
|
(make-web-cell 0))
|
|
|
|
(define (include-counter a-counter)
|
|
(let/cc k
|
|
(let loop ()
|
|
(k
|
|
(lambda (embed/url)
|
|
`(div (h3 ,(number->string (web-cell-ref a-counter)))
|
|
(a ([href
|
|
,(embed/url
|
|
(lambda _
|
|
@code:comment{A new frame has been created}
|
|
(define last (web-cell-ref a-counter))
|
|
@code:comment{We can inspect the value at the parent}
|
|
(web-cell-shadow a-counter (add1 last))
|
|
@code:comment{The new frame has been modified}
|
|
(loop)))])
|
|
"+")))))))
|
|
]
|
|
} |