Dylan Server Pages (DSP) is a template engine for providing dynamic web site content using the Dylan language. They are similar in spirit to JavaServer Pages, but without the ability to mix program logic and page content, which is a bad idea anyway. All dynamic content is invoked via DSP tag calls such as <xx:show-current-username/>.
(Okay, opinions can vary on the wisdom of closly mixing content and implementation, as with JSP scriptlets, but I contend that it's only ok for one-off hacks and small one-person projects. This isn't necessary in DSP because with Dylan's powerful language features writing custom tags is trivial and concise compared to JSP. And with Open Dylan, you often don't even need to restart your application to compile new custom tags and try them out.)
Currently, a DSP application is implemented as a Dylan project that uses the Koala HTTP server library. This effectively means that each DSP application has to run on a different Koala server and therefore on a different HTTP port. (The plan is to eventually fix Koala to load DSP application libraries at runtime, based on configuration files.)
DSP templates contain normal HTML plus DSP tag calls. DSP tag calls generate the dynamic content of you web pages. They use standard XML syntax. For example, <mylib:mytag arg="foo"/> is tag call with no body that passes one argument, arg, to mytag when it is invoked. "mylib" tells the DSP template engine what tag library (taglib for short) "mytag" will be found in.
There are several special tags called directives defined that couldn't easily have been defined by the user. DSP directives use the same syntax as other tags, but they use the special tag library name %dsp. For example, the include directive might look like this: <%dsp:include location="foo.dsp"/>.
Each top-level template file must have a corresponding instance of <dylan-server-page> associated with it. This is accomplished with the define page macro, which also publishes the URLs associated with the page.
DSP template files may have any filename extension, but the extension ".dsp" may be treated specially in the future. For example, .dsp files may eventually be automatically exported as <dylan-server-page>s.
A DSP directive is used much like a normal DSP tag, but it couldn't be written as a normal tag without special support from the DSP engine. DSP directives are distinguished by the %dsp tag prefix. There are two built in DSP directives:
<%dsp:include location="header.dsp"/>Note that if the location given is absolute (i.e., begins with a slash) then the document is looked up relative to the document root directory. Otherwise it is looked up relative to the directory containing the current document.
<%dsp:taglib name="my-taglib" prefix="xx"/>
...
<xx:my-tag/>
...
The value of the name argument must be the same as the name in a define taglib form. The prefix may contain
any characters except for < and : and may not be
"%dsp".
<dsp:if test="my-predicate?">
<dsp:then>...true part...</dsp:then>
<dsp:else>...false part...</dsp:else>
</dsp:if>
Note that there may be multiple dsp:then and
dsp:else tags inside the same
dsp:if tag body. If there is any plain HTML in the
body of the dsp:if, and outside of any
dsp:then or dsp:else tags, it will
always be displayed.
Taglibs are fairly uninteresting as far as programming a DSP application goes. They are only used when defining tags and named methods, to specify which taglib those objects belongs to. They are defined as follows:
define taglib demo () end;The above defines a taglib named "demo". See the Tags section for how the taglib is specified when defining a tag. This taglib would be included in a page with the following directive:
<%dsp:taglib name="demo" prefix="xyz"/>and its tags would then be used like this:
<xyz:tag-one/>Note that
prefix is optional, and defaults to the value
of name.
define [body] tag tag-name [in taglib-name]
(method-parameters)
(tag-parameters)
...code...
end;
The following example tag should clear things up a bit:
define tag current-time in demo
(page :: <dylan-server-page>)
(style)
write(output-stream(current-response()), current-time(style));
end;
The above defines a tag called "current-time" in the
"demo" taglib which outputs the current time in the DSP page.
See the define tag macro for
a full description tag definition. The above tag would be called like
this:
<%dsp:taglib name="demo" prefix="xyz"/>
<xyz:current-time style="24hr"/>
Note that style defines a parameter for the tag call
such that the style variable is bound to the value of
that parameter in the body of the tag definition.
The tag functon must always accept one argument: page, an
instance of <dylan-server-page>.
| define taglib Macro | Library: koala; Module: http-server |
Signature
define taglib taglib-name ()Summary
end
Defines a new tag library with name taglib-name.
| define tag Macro | Library: koala; Module: http-server |
Signature
define [modifiers] tag tag-name [in taglib-name]Summary
(method-parameters)
(tag-call-parameters)
body
end
Defines a new tag named tag-name in the taglib-name tag library.Arguments
| modifiers | |
The only valid modifier is body, which must be used if the tag allows
nested body elements. If body is not specified then the tag call must
end in "/>" or an error will be signalled when the DSP template is
parsed. If body is specified,
method-parameters must have a third parameter (see below).
|
|
| tag-name | |
|
The name of the tag, as it will appear in the .dsp file.
|
|
| taglib-name | |
|
The name of the taglib the tag should be added to.
|
|
| method-parameters | |
Each tag definition creates a method that will be called when the tag is
invoked. This is the parameter list for that method. The basic form of
the parameter list is (page[, process-body]). page is
an instance of <dylan-server-page>. process-body is an instance of
<function>. The process-body argument should be specified if and
only if the body modifier is supplied.
|
|
| tag-call-parameters | |
tag-call-parameters allows you to receive named
keyword arguments from a tag call. For example, if your tag call looks like
then tag-call-parameters might look like
in which case body code may refer to arg1 and
arg2. If the tag call doesn't specify a given
tag-call-parameter then #f will be used. If a
tag-call-parameter has a type specifier, then the
passed argument will be parsed into the appropriate type before it is passed.
See the parse-tag-arg generic function. Note
that this means specifying a type of which #f is not a member effectively
makes the tag-call-parameter required. For example,
specifies that arg1 is optional (it will be a <string> if supplied) and
arg2 is required and must be parsable to an <integer>.
|
|
| body | |
|
The body of the tag definition. method-parameter and
tag-call-parameters are bound within the body.
|
|
Defines a new tag named tag-name in the taglib-name tag library. For simple DSP tags with no body elements, the body code normally just does output to the output stream of the current response, generating dynamic output in place of the literal tag call in the source file. Tags that have body elements may additionally want to setup state for nested tags to use. This may be done, for example, through the use of dynamically bound thread variables or storing information in the session or page context.ExamplesWhen the DSP engine invokes the tag to generate dynamic content it passes arguments that match method-parameters. tag-call-parameters receive arguments specified in the tag call, in the DSP source file, after they have been parsed to the specified types.
A simple tag in the "demo" taglib that displays "Hello, world!" in the page. It is invoked withSee Also<demo:hello/>:A tag that allows body elements, and processes the body elements three times. It is invoked withdefine tag hello in demo (page :: <dylan-server-page>) () format(output-stream(current-response()), "Hello, world!"); end;<demo:three-times>...whatever...</demo:three-times>:define body tag three-times in demo (page :: <dylan-server-page>, do-body :: <function>) () for (i from 1 to 3) do-body(); end; end;
define taglib, <dylan-server-page>, <response>, output-stream, map-tag-call-arguments, show-tag-call-arguments