Some more sections (session-data, part of mysxml)

This commit is contained in:
interp 2004-01-18 03:32:08 +00:00
parent 63d708b219
commit 15b5138bd0
1 changed files with 231 additions and 38 deletions

View File

@ -73,7 +73,7 @@ surflets:
directory called \name{SSAX}, to which I will refer to as directory called \name{SSAX}, to which I will refer to as
\typew{\$SSAX}. \typew{\$SSAX}.
\item Unfortunately, this distribution (plt200-4.9) has a typo in \item Unfortunately, this SSAX distribution (plt200-4.9) has a typo in
the package definition for scsh. Apply the patch that comes with the package definition for scsh. Apply the patch that comes with
the \surflets distribution to get rid of this typo: the \surflets distribution to get rid of this typo:
\begin{itemize} \begin{itemize}
@ -231,11 +231,11 @@ just sends the HTML page and does not return and
functions as the \emph{sending functions}. functions as the \emph{sending functions}.
In a \surflet, HTML pages are represented as lists, or, to be more In a \surflet, HTML pages are represented as lists, or, to be more
precise, as SXML (S-expression based XML). The first element of a precise, as SXML (S-expression based XML).\label{sec:SXML} The first
SXML list is a symbol stating the HTML tag. The other elements of a element of a SXML list is a symbol stating the HTML tag. The other
SXML list are the contents that are enclosed by this HTML tag. The elements of a SXML list are the contents that are enclosed by this
contents can be other SXML list, too. Here are some examples of SXML HTML tag. The contents can be other SXML list, too. Here are some
lists and how they translate to HTML: examples of SXML lists and how they translate to HTML:
\newcommand{\htmltag}[1]{$\mathtt{<}$#1$\mathtt{>}$} \newcommand{\htmltag}[1]{$\mathtt{<}$#1$\mathtt{>}$}
\begin{tabbing} \begin{tabbing}
@ -1094,10 +1094,10 @@ value, \eg functions or records.
\end{alltt} \end{alltt}
\name{case-returned-via} has an extended syntax similar to \name{cond} \name{case-returned-via} has an extended syntax similar to \name{cond}
that it useful with annotated address. The arrow \name{=>} calls the that it useful with annotated address. The arrow `\name{=>}' calls
following function with the annotation of the address via which the the following function with the annotation of the address via which
user has left the web page. You can extract the annotation yourself the user has left the web page. You can extract the annotation
with \name{returned-via} like this: yourself with \name{returned-via} like this:
\begin{alltt} \begin{alltt}
(result-page (returned-via language bindings)) (result-page (returned-via language bindings))
@ -1126,7 +1126,7 @@ Several different callbacks would result in the storage of the several
slightly different continuations. This is unnecessary, as you can slightly different continuations. This is unnecessary, as you can
annotate the callbacks with the arguments for the callback function. annotate the callbacks with the arguments for the callback function.
Let's see an example which is a variation of the previous examples Let's see an example which is a variation of the previous examples
(important parts emphasized): (important parts / differences emphasized):
\begin{listing} \begin{listing}
(define-structure surflet surflet-interface (define-structure surflet surflet-interface
@ -1166,37 +1166,230 @@ first argument. Furthermore, you don't have to use
callbacks. However, it can be sensible to combine the dispatch and callbacks. However, it can be sensible to combine the dispatch and
the callback method, so you have to use \name{send-html/suspend}. the callback method, so you have to use \name{send-html/suspend}.
Note that is nonsensical to create a callback on top level, \ie the
call to \name{make-annotated-callback} must occur every time
\name{main} is called and not only once when the \surflet is read into
memory. For the same reason it is nonsensical in most cases to reuse
a callback.
The \surflet library provides also a wrapper function with which you
can instruct the callback to call different functions instead of a
single one. If you create your callback like
\begin{alltt}
(let ((callback (make-annotated-callback callback-function)))
\dots)
\end{alltt}
you can instruct the callback to call different functions like this:
\begin{alltt}
(callback function1 arg1 arg2)
\dots
(callback function2 arg3 arg4 arg5)
\end{alltt}
Again, it is your choice which option you want to use. Note that
calling a function with several arguments and of different amount each
time is also possible if you only use a single function for the
callback.
\section{Data management}
When you write web programs, there are usually two kinds of data that
you use: data that is local to each instance of a \surflet, \eg the
users login, and data that is global to each instance of a \surflet,
\eg a port to a logfile. Changes to local data is only visible to
each instance of a \surflet, while changes to global data is visible
to every instance of a \surflet.
The \surflet library does not really distinguish between these two
types of data, but provides ways to realize both of them in a
convenient way that is not (really) different from the way you handle
this data types in a regular Scheme program.
If a data item is globally used in your \surflet, define it global
(on top level) and change its values with \name{set!}. If a data
item is locally used, define it locally (in your function) and do not
change its value with \name{set!}.
If the following sounds too technical to you, you can safely skip this
paragraph. The reason why the distinction between global and local
data is done via whether you mutate the data's value with \name{set!}
is that the \surflets are implemented with continuations.
Continuations cannot reflect changes that are done via \name{set!} (or
side effects in general) and thus such changes are globally visible.
On the other hand continuations represent states of a program and a
reified continuations reifies also the values of all (local) data.
But what to do if you happen to want to change your \emph{local}
data's value with \name{set!}? The \surflet library provides a place
where you store such mutable local data and two functions to access
it: \name{set-session-data!} sets the mutable local data and
\name{get-session-data} reads the mutable local data. Here is an
example. It uses the callback technique that was presented in the
previous section. If you haven't read that section, you only need to
know that \name{show-page} is called again and again as long as the
user keeps on clicking on ``Click''.
\begin{listing}
(define-structure surflet surflet-interface
(open surflets
surflets/callbacks
scheme-with-scsh)
(begin
(define (main req)
(set-session-data! -1)
(let ((start (make-annotated-callback show-page)))
(show-page req 'click start)))
(define (show-page req what callback)
(if (eq? what 'click)
(click callback)
(cancel)))
(define (click callback)
(set-session-data! (+ 1 (get-session-data)))
(send-html
`(html
(head (title "Click counter"))
(body
(h2 "Click or cancel")
(p "You've already clicked "
,(get-session-data)
" times.")
(p (url ,(callback 'click callback) "Click")
(url ,(callback 'cancel callback) "Cancel"))))))
(define (cancel)
(send-html/finish
`(html
(head (title "Click counter finished"))
(body
(h2 "Finished")
(p "after " ,(get-session-data) " clicks.")))))
))
\end{listing}
At the beginning of \name{main} we initialize the mutable local data
with \name{set-session-data!}.
\begin{alltt}
(define (main req)
(set-session-data! -1)
(let ((start (make-annotated-callback show-page)))
(show-page req 'click start)))
\end{alltt}
Afterwards, we create and save a callback that will be called again
and again. We call \name{show-page} with the callback to show the
first web page.
\begin{alltt}
(define (show-page req what callback)
(if (eq? what 'click)
(click callback)
(cancel)))
\end{alltt}
\name{show-page} evaluates its second argument \name{what} to
determine what to do next: continue or cancel.
\begin{alltt}
(define (click callback)
(set-session-data! (+ 1 (get-session-data)))
(send-html
`(html
(head (title "Click counter"))
(body
(h2 "Click or cancel")
(p "You've already clicked "
,(get-session-data)
" times.")
(p (url ,(callback 'click callback) "Click")
(url ,(callback 'cancel callback) "Cancel"))))))
\end{alltt}
If the user continues, \name{click} increases the mutable local
counter and shows the next page.
Note that we don't use \name{send-html/suspend} here because we use
the callback to lead to the next web page. If the user clicks on the
link labeled with ``Click'' or ``Cancel'', \name{show-page} will be
called with \typew{'click} or \typew{'cancel}, respectively, and the
callback as parameters. This creates an endless loop without saving
endless states of the \surflet.
\name{cancel} shows the final page with the amount of clicks
performed.
\section{My own SXML}
Section \ref{sec:SXML} introduced SXML, the way how \surflets
represent HTML. This section will show you, how you can create your
own rules to translate from SXML to HTML.
\subsection{Terms and theoretical background}
This subsection will introduce the main concepts of the translation
process and some necessary terms we will use in the following.
The translation process from SXML to HTML takes two steps. In the
first step, SXML is translated to an intermediate form. This is done
by the \textit{translator}. In the second step, the intermediate form
is translated into an HTML string. This is done by the
\textit{printer}. The intermediate form looks very much like SXML,
but contains only atoms or, recursively, list of \textit{atoms}.
Atoms are numbers, characters, strings, \sharpf, and the empty list.
We call the intermediate form an \textit{atom tree} and the list from
which we've started an \textit{SXML tree}.
The basic unit in the translation process is a \textit{conversion
rule}. A conversion rule consists of a trigger and a conversion
function. The translator calls the conversion function when it sees
the trigger at the beginning of a list in the SXML tree, \ie at a
node. It calls the conversion function with the all list elements as
parameters and replaces the whole list by the result of the conversion
function. The result of the conversion function is supposed to be an
atom tree.
The translator gets the SXML tree and a list of conversion rules as
arguments. It then traverses the SXML tree depth first and calls the
conversion functions according to the triggers it encounters,
replacing the nodes in the SXML tree with the result of the conversion
functions it called for each node. The result of this translation
step will be an atom tree, which the printer will print to a port.
There are exceptions to this basic rules. First, the translator might
not traverse the whole SXML tree. If the translator traverses the
whole tree, every argument to a conversion function is first
translated before it is passed to the conversion function. This is
the regular case and we say the conversion function gets its arguments
\textit{preprocessed}. However, the conversion rule can instruct the
translator not to preprocess the conversion function's arguments and
pass the arguments as they are in the SXML tree, \ie
\textit{unprocessed}. In that case, the translator will stop
traversing the SXML tree at that node and replacing the whole node by
the result of the conversion function called for this node.
Second, there are two default triggers which you can't use in your
translation rules: \typew{*default*} and \typew{*text*}. The
conversion rule that uses \typew{*default*} as its trigger is the
default conversion rule which the translator uses if no other
conversion rule triggers for a node in the SXML tree. The conversion
rule that uses \typew{*text*} as its trigger is the text conversion
rule and triggers, if the node in the SXML tree is a string. In the
standard conversion rule set the text conversion rule performs HTML
escaping, \eg for the ampersand (\&).
\section{Outlook} \section{Outlook}
More to come soon about data management, \surflets containing of More to come soon about\surflets containing of different parts and
different parts and individual SXML. individual SXML.
%\section{Data management}
%
%There are different kinds of data that float around in a \surflet,
%actually in any serve side scripted program: There is local data that
%is associated to each session, \ie each session has its own copy of
%this data and if one session modifies this data it does not change the
%value of the data in other sessions. There is also global data, \ie
%data that is shared among sessions and modification of this data in
%one session is visible in other sessions. Both types of data are
%realizable in a \surflet.
%
%Local data is managed automatically by the \surflet library. When you
%call \name{send-html/suspend}, your local data is saved in a
%continuation. After the user has proceeded in your web site, this
%continuation and thus your local data is restored.
%
%As all data is stored in a continuation, there are no copies of your
%data saved. This means that if you change data via side effects, \eg
%via \name{set!}, this changes remain effective after the continuation
%has been restored. Thus, using side effects to change data, for
%example with \name{set!} is a way to realize global data.
%
%Sometimes it is desirable to be able to change local data via side
%effects.
%
%\end{document} %\end{document}
%session data %session data