Some more sections (session-data, part of mysxml)
This commit is contained in:
parent
63d708b219
commit
15b5138bd0
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue