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
|
||||
\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 \surflets distribution to get rid of this typo:
|
||||
\begin{itemize}
|
||||
|
@ -231,11 +231,11 @@ just sends the HTML page and does not return and
|
|||
functions as the \emph{sending functions}.
|
||||
|
||||
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
|
||||
SXML list is a symbol stating the HTML tag. The other elements of a
|
||||
SXML list are the contents that are enclosed by this HTML tag. The
|
||||
contents can be other SXML list, too. Here are some examples of SXML
|
||||
lists and how they translate to HTML:
|
||||
precise, as SXML (S-expression based XML).\label{sec:SXML} The first
|
||||
element of a SXML list is a symbol stating the HTML tag. The other
|
||||
elements of a SXML list are the contents that are enclosed by this
|
||||
HTML tag. The contents can be other SXML list, too. Here are some
|
||||
examples of SXML lists and how they translate to HTML:
|
||||
|
||||
\newcommand{\htmltag}[1]{$\mathtt{<}$#1$\mathtt{>}$}
|
||||
\begin{tabbing}
|
||||
|
@ -1094,10 +1094,10 @@ value, \eg functions or records.
|
|||
\end{alltt}
|
||||
|
||||
\name{case-returned-via} has an extended syntax similar to \name{cond}
|
||||
that it useful with annotated address. The arrow \name{=>} calls the
|
||||
following function with the annotation of the address via which the
|
||||
user has left the web page. You can extract the annotation yourself
|
||||
with \name{returned-via} like this:
|
||||
that it useful with annotated address. The arrow `\name{=>}' calls
|
||||
the following function with the annotation of the address via which
|
||||
the user has left the web page. You can extract the annotation
|
||||
yourself with \name{returned-via} like this:
|
||||
|
||||
\begin{alltt}
|
||||
(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
|
||||
annotate the callbacks with the arguments for the callback function.
|
||||
Let's see an example which is a variation of the previous examples
|
||||
(important parts emphasized):
|
||||
(important parts / differences emphasized):
|
||||
|
||||
\begin{listing}
|
||||
(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
|
||||
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}
|
||||
|
||||
More to come soon about data management, \surflets containing of
|
||||
different parts and individual SXML.
|
||||
More to come soon about\surflets containing of different parts and
|
||||
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}
|
||||
|
||||
%session data
|
||||
|
|
Loading…
Reference in New Issue