History for SkinScriptSyntax
??changed:
-
The !SkinScript Language Reference
Preface
This document describes the syntax for !SkinScript as defined in
!ZPatterns 0.4.3, which is not yet publically available. If you are
using an earlier version of !ZPatterns, the following features are
not available:
* The 'QUERY' keyword and the 'OTHERWISE LET' clause on 'WITH/COMPUTE' declarations
* The 'INITIALIZE OBJECT WITH' declaration
* The 'DEPENDENT ON' clause of 'WITH/COMPUTE' declarations
It is also recommended that you read about HowTriggersWork before
trying to define complex rules with !SkinScript.
Basic Concepts and Syntax
If you're familiar with ZPatterns, you know that DataSkins get their
attributes and behavior from AttributeProviders and RuleAgents,
respectively. Providers and Agents (known as DataPlugIns) can be
written directly in Python, but it is much easier to write them in
!SkinScript. !SkinScript lets you define an individual attribute
provider or rule agent in a single declarative statement, using
standard Zope tools such as SQL Methods, DTML Methods, Python
Methods, and so on to do the actual data retrieval or storage. In
effect, !SkinScript is a "glue language" which lets you define the
linkages between a !DataSkin and the methods you want to implement
its "skeleton" of data storage and triggered behavior.
In most languages, the order that statements appear in makes a
difference to the results you get, and !SkinScript is no exception.
Although each !SkinScript statement defines a seperate and
independent data plug-in, the ordering makes a difference in how
they will be used by DataSkins. When a !DataSkin needs to perform
an operation (such as retrieving an attribute), it asks its
!DataManager for a list of suitable DataPlugIns. This list is
ordered according to the original order of plug-ins as listed on the
Data Plug-ins tab of the [Racks] or [Customizers] involved. And the
declarations of a !SkinScript Method are treated as though they were
individual plug-ins appearing in place of the !SkinScript Method in
that list.
In other words, !SkinScript is literally a language for defining
data plug-ins. A !SkinScript *script* consists of a series of
*declarations*, seperated by whitespace. Each declaration is
compiled into a single data plug-in. !SkinScript is a
keyword-driven language, is case-sensitive, and is not whitespace
sensitive, even for Python expressions contained within
declarations. All whitespace which occurs outside of quoted strings
is treated as though it were a single space. (Incidentally, this
means that the usual Python rules about where you can put linebreaks
in expressions do not apply. You can write the expression '1+2'
split across three lines, if you so desire.) Comments are marked as
in Python, using a '#' symbol to mean that the rest of the current
line is a comment. Comments are treated as simple whitespace.
Declarations
Declarations are the basic building block of !SkinScript.
Declarations are compiled into AttributeProviders or RuleAgents, one
per declaration. Some declarations provide attribute values:
- 'INITIALIZE OBJECT WITH' *assignmentlist*
- 'WITH ![QUERY]' *expression* 'COMPUTE' *nameorassignlist* ![OTHERWISE LET assignmentlist] ![DEPENDENT ON dependencies]
- 'WITH SELF COMPUTE' *assignmentlist*
Some handle attribute storage:
- ![WHEN eventspec] 'STORE' *attributelist* 'USING' *expression* ![SAVING mementolist]
- 'STORE' *attributelist* 'IN SELF'
And others can call an expression upon transaction commit:
- 'WHEN' *eventspec* 'CALL' *expression* ![SAVING mementolist]
Each declaration has its own parameters, but there are certain
conventions which are followed across most kinds of declarations.
Declaration Parameters
*expression* -- A DTML-style Python expression. As with DTML, the
"_" object is available for access to Python built-ins and library
functions. Please see the section below on "Variables and Functions
Available in Expressions" for details on how names other than "_"
are looked up in !SkinScript expressions.
*assignmentlist* -- A comma-seperated list of assignments in the
form *attributename* = *expression*, similar to passing keyword
arguments to a function or method.
*nameorassignlist* -- Similar to *assignmentlist*, but with a
special shorthand for the case where *attributename* and
*expression* are the same (e.g. 'foo=foo'). To make such an
assignment, you can replace *attributename* '=' *expression* with
just *attributename*. So 'foo=bar,baz=baz,bada=bing' can be
simplified to 'foo=bar,baz,bada=bing' if a clause's syntax allows a
*nameorassignmentlist*.
*mementolist* -- A *mementolist* is syntactically identical to a
*nameorassignlist*, but has a different context and purpose. A
*mementolist* is used to save old values of expressions for later
comparison purposes when a (sub)transaction commits, and appears
only in 'SAVING' clauses. Expression variables are looked up in the
context of the !DataSkin whose snapshot is being taken. So in the
clause 'SAVING bar,foo=baz' the DataSkin's 'bar' attribute will be
saved as OLD!['bar'], and its 'baz' attribute will be saved as
OLD!['foo'].
A *mementolist* is computed only once per (sub)transaction for a
given !DataSkin. The first time the !DataSkin is changed in a
(sub)transaction, the 'SAVING' clause is executed for all
declarations that have one, even if the declaration never ends up
firing.
*eventspec* -- A clause of the form 'OBJECT ADDED, CHANGED,
DELETED', where the 'ADDED', 'CHANGED' and 'DELETED' keywords may be
used in any combination. For example, 'OBJECT ADDED,DELETED' and
'OBJECT CHANGED' are both valid *eventspec* clauses. Please see
HowTriggersWork for details on how !ZPatterns events are interpreted
by !SkinScript.
*attributelist* -- A comma-seperated list of attribute names, to
which the declaration will be applied. An asterisk ("*") may be
used as a wildcard attribute name, meaning that the declaration will
be applicable for any attribute name. Remember, however, that
declarations associated with specific names will take precedence
over wildcard declarations, even if the wildcard declaration comes
before the specific declaration and would match the name being
looked up.
*dependencies* -- A comma-seperated list of attribute names which,
when changed, will cause the dependent attributes to be recalculated
on their next access. Wildcards cannot be used, only actual
attribute names.
Variables and Functions Available in Expressions
Names used in an expression are usually looked up from the
attributes of individual !SkinScript statement and its acquisition
parents (e.g. the Rack or Customizer which it's contained in, and so
on up the line). One exception to this rule is in the 'COMPUTE'
clause of a WITH/COMPUTE declaration, where names are first looked
up in the 'RESULT' object returned by the 'WITH' clause. The other
exception is in 'SAVING' clauses, where names are looked up in the
context of the !DataSkin whose snapshot is being taken.
The following variable names and functions are provided by
!SkinScript for use in expressions.
* Generally available:
'self' -- The !DataSkin instance which the declaration is being
applied to at the time the expression is being called.
'NOT_FOUND' -- A special value which causes an attribute to be
non-existent, if this is the value provided. In a WITH/COMPUTE
declaration, if the 'WITH' expression returns 'NOT_FOUND', the
'COMPUTE' clause is ignored, and the 'OTHERWISE LET' clause is
activated if one exists.
* Available for WITH/COMPUTE declarations:
'RESULT' -- The result of the 'WITH' expression in a WITH/COMPUTE
declaration. Available only from expressions in the 'COMPUTE'
clause. This variable is placed atop the DTML namespace stack
during execution of the 'COMPUTE' clause, so just referring to a
name in a 'COMPUTE' expression will look up that name in the
'RESULT' object first. Only if it is not found there, will the
search continue to the declaration and its acquisition context.
'ATTRIBUTE_NAME' -- A string containing the name of the attribute
which the !DataSkin is currently trying to retrieve. Available in
both the 'WITH' and 'COMPUTE' clauses.
* Available for WHEN/STORE and WHEN/CALL declarations:
'TRIGGER_EVENT' -- A string, either "ADD", "CHANGE", or "DELETE",
denoting the type of event which caused the expression to be
executed.
'OLD!["name"]' -- 'OLD' is a mapping object containing the values
saved by the "SAVING mementolist" clause of a WHEN/STORE or
WHEN/CALL declaration.
[499 more lines...]