summaryrefslogtreecommitdiff
path: root/www/users_guide/language.rst
diff options
context:
space:
mode:
Diffstat (limited to 'www/users_guide/language.rst')
-rw-r--r--www/users_guide/language.rst741
1 files changed, 741 insertions, 0 deletions
diff --git a/www/users_guide/language.rst b/www/users_guide/language.rst
new file mode 100644
index 0000000..f387562
--- /dev/null
+++ b/www/users_guide/language.rst
@@ -0,0 +1,741 @@
+.. role:: math(raw)
+ :format: html latex
+
+Language Overview
+=================
+
+(language)
+
+Cheetah's basic syntax was inspired by the Java-based template
+engines Velocity and WebMacro. It has two types of tags: {
+$placeholders} and { #directives}. Both types are case-sensitive.
+
+Placeholder tags begin with a dollar sign ({$varName}) and are
+similar to data fields in a form letter or to the {%(key)s} fields
+on the left side of Python's {%} operator. When the template is
+filled, the placeholders are replaced with the values they refer
+to.
+
+Directive tags begin with a hash character (#) and are used for
+comments, loops, conditional blocks, includes, and all other
+advanced features. ({ Note:} you can customize the start and end
+delimeters for placeholder and directive tags, but in this Guide
+we'll assume you're using the default.)
+
+Placeholders and directives can be escaped by putting a backslash
+before them. ``\$var`` and ``\#if`` will be output as literal
+text.
+
+A placeholder or directive can span multiple physical lines,
+following the same rules as Python source code: put a backslash
+(``\``) at the end of all lines except the last line. However, if
+there's an unclosed parenthesis, bracket or brace pending, you
+don't need the backslash.
+
+::
+
+ #if $this_is_a_very_long_line and $has_lots_of_conditions \
+ and $more_conditions:
+ <H1>bla</H1>
+ #end if
+
+ #if $country in ('Argentina', 'Uruguay', 'Peru', 'Colombia',
+ 'Costa Rica', 'Venezuela', 'Mexico')
+ <H1>Hola, senorita!</H1>
+ #else
+ <H1>Hey, baby!</H1>
+ #end if
+
+Language Constructs - Summary
+-----------------------------
+
+(language.constructs)
+
+
+#. Comments and documentation strings
+
+
+ #. {## single line}
+
+ #. {#\* multi line \*#}
+
+
+#. Generation, caching and filtering of output
+
+
+ #. plain text
+
+ #. look up a value: {$placeholder}
+
+ #. evaluate an expression: {#echo} ...
+
+ #. same but discard the output: {#silent} ...
+
+ #. one-line if: {#if EXPR then EXPR else EXPR}
+
+ #. gobble the EOL: {#slurp}
+
+ #. parsed file includes: {#include} ...
+
+ #. raw file includes: {#include raw} ...
+
+ #. verbatim output of Cheetah code: {#raw} ... {#end raw}
+
+ #. cached placeholders: {$\*var}, {$\*<interval>\*var}
+
+ #. cached regions: {#cache} ... {#end cache}
+
+ #. set the output filter: {#filter} ...
+
+ #. control output indentation: {#indent} ... ({ not implemented
+ yet})
+
+
+#. Importing Python modules and objects: {#import} ..., {#from}
+ ...
+
+#. Inheritance
+
+
+ #. set the base class to inherit from: {#extends}
+
+ #. set the name of the main method to implement: {#implements}
+ ...
+
+
+#. Compile-time declaration
+
+
+ #. define class attributes: {#attr} ...
+
+ #. define class methods: {#def} ... {#end def}
+
+ #. {#block} ... {#end block} provides a simplified interface to
+ {#def} ... {#end def}
+
+
+#. Run-time assignment
+
+
+ #. local vars: {#set} ...
+
+ #. global vars: {#set global} ...
+
+ #. deleting local vars: {#del} ...
+
+
+#. Flow control
+
+
+ #. {#if} ... {#else} ... {#else if} (aka {#elif}) ... {#end if}
+
+ #. {#unless} ... {#end unless}
+
+ #. {#for} ... {#end for}
+
+ #. {#repeat} ... {#end repeat}
+
+ #. {#while} ... {#end while}
+
+ #. {#break}
+
+ #. {#continue}
+
+ #. {#pass}
+
+ #. {#stop}
+
+
+#. error/exception handling
+
+
+ #. {#assert}
+
+ #. {#raise}
+
+ #. {#try} ... {#except} ... {#else} ... {#end try}
+
+ #. {#try} ... {#finally} ... {#end try}
+
+ #. {#errorCatcher} ... set a handler for exceptions raised by
+ $placeholder calls.
+
+
+#. Instructions to the parser/compiler
+
+
+ #. {#breakpoint}
+
+ #. {#compiler-settings} ... {#end compiler-settings}
+
+
+#. Escape to pure Python code
+
+
+ #. evalute expression and print the output: {<%=} ... {%>}
+
+ #. execute code and discard output: {<%} ... {%>}
+
+
+#. Fine control over Cheetah-generated Python modules
+
+
+ #. set the source code encoding of compiled template modules:
+ {#encoding}
+
+ #. set the sh-bang line of compiled template modules: {#shBang}
+
+
+
+The use of all these constructs will be covered in the next several
+chapters.
+
+Placeholder Syntax Rules
+------------------------
+
+(language.placeholders.syntax)
+
+
+- Placeholders follow the same syntax rules as Python variables
+ except that they are preceded by {$} (the short form) or enclosed
+ in {${}} (the long form). Examples:
+
+ ::
+
+ $var
+ ${var}
+ $var2.abc['def']('gh', $subplaceholder, 2)
+ ${var2.abc['def']('gh', $subplaceholder, 2)}
+
+ We recommend {$} in simple cases, and {${}} when followed directly
+ by a letter or when Cheetah or a human template maintainer might
+ get confused about where the placeholder ends. You may alternately
+ use ``$()`` or ``$[]``, although this may confuse the (human)
+ template maintainer:
+
+ ::
+
+ $(var)
+ $[var]
+ $(var2.abc['def']('gh', $subplaceholder, 2))
+ $[var2.abc['def']('gh', $subplaceholder, 2)]
+
+ { Note:} Advanced users can change the delimiters to anything they
+ want via the {#compiler} directive.
+
+ { Note 2:} The long form can be used only with top-level
+ placeholders, not in expressions. See section
+ language.placeholders.positions for an elaboration on this.
+
+- To reiterate Python's rules, placeholders consist of one or more
+ identifiers separated by periods. Each identifier must start with a
+ letter or an underscore, and the subsequent characters must be
+ letters, digits or underscores. Any identifier may be followed by
+ arguments enclosed in ``()`` and/or keys/subscripts in ``[]``.
+
+- Identifiers are case sensitive. {$var} does not equal {$Var} or
+ {$vAr} or {$VAR}.
+
+- Arguments inside ``()`` or ``[]`` are just like in Python.
+ Strings may be quoted using any Python quoting style. Each argument
+ is an expression and may use any of Python's expression operators.
+ Variables used in argument expressions are placeholders and should
+ be prefixed with {$}. This also applies to the \*arg and \*\*kw
+ forms. However, you do { not} need the {$} with the special Python
+ constants {None}, {True} and {False}. Examples:
+
+ ::
+
+ $hex($myVar)
+ $func($arg=1234)
+ $func2($*args, $**kw)
+ $func3(3.14159, $arg2, None, True)
+ $myList[$mySubscript]
+
+- Trailing periods are ignored. Cheetah will recognize that the
+ placeholder name in {$varName.} is {varName}, and the period will
+ be left alone in the template output.
+
+- The syntax {${placeholderName, arg1="val1"}} passes arguments to
+ the output filter (see {#filter}, section output.filter. The braces
+ and comma are required in this case. It's conventional to omit the
+ {$} before the keyword arguments (i.e. {arg1}) in this case.
+
+- Cheetah ignores all dollar signs ({$}) that are not followed by
+ a letter or an underscore.
+
+
+The following are valid $placeholders:
+
+::
+
+ $a $_ $var $_var $var1 $_1var $var2_ $dict.key $list[3]
+ $object.method $object.method() $object.method
+ $nest($nest($var))
+
+These are not $placeholders but are treated as literal text:
+
+::
+
+ $@var $^var $15.50 $$
+
+Where can you use placeholders?
+-------------------------------
+
+(language.placeholders.positions)
+
+There are three places you can use placeholders: top-level
+position, expression position and LVALUE position. Each has
+slightly different syntax rules.
+
+Top-level position means interspersed in text. This is the only
+place you can use the placeholder long form: {${var}}.
+
+{ Expression position} means inside a Cheetah expression, which is
+the same as a Python expression. The placeholder names a searchList
+or other variable to be read. Expression position occurs inside ()
+and :math:`$[]$` arguments within placeholder tags (i.e., a
+placeholder inside a placeholder), and in several directive tags.
+
+{ LVALUE position} means naming a variable that will be written to.
+LVALUE is a computer science term meaning
+"the left side of an assignment statement". The first argument of
+directives {#set}, {#for}, {#def}, {#block} and {#attr} is an
+LVALUE.
+
+This stupid example shows the three positions. Top-level position
+is shown in {courier}, expression position is { italic}, and LVALUE
+position is { bold}.
+
+ #for { $count} in { $range}({ $ninetyNine}, 0, -1)
+ #set { $after} = { $count} - 1
+ {$count} bottles of beer on the wall. {$count} bottles of beer!
+ Take one down, pass it around. {$after} bottles of beer on the
+ wall.
+ #end for
+ {$hex}({ $myVar}, { $default}={ None})
+
+
+The output of course is:
+
+::
+
+ 99 bottles of beer on the wall. 99 bottles of beer!
+ Take one down, pass it around. 98 bottles of beer on the wall.
+ 98 bottles of beer on the wall. 98 bottles of beer!
+ Take one down, pass it around. 97 bottles of beer on the wall.
+ ...
+
+Are all those dollar signs really necessary?
+--------------------------------------------
+
+(language.placeholders.dollar-signs)
+
+{$} is a "smart variable prefix". When Cheetah sees {$}, it
+determines both the variable's position and whether it's a
+searchList value or a non-searchList value, and generates the
+appropriate Python code.
+
+In top-level position, the {$} is { required}. Otherwise there's
+nothing to distinguish the variable from ordinary text, and the
+variable name is output verbatim.
+
+In expression position, the {$} is { required} if the value comes
+from the searchList or a "#set global" variable, { recommended} for
+local/global/builtin variables, and { not necessary} for the
+special constants {None}, {True} and {False}. This works because
+Cheetah generates a function call for a searchList placeholder, but
+a bare variable name for a local/global/builtin variable.
+
+In LVALUE position, the {$} is { recommended}. Cheetah knows where
+an LVALUE is expected, so it can handle your variable name whether
+it has {$} or not.
+
+EXCEPTION: Do { not} use the {$} prefix for intermediate variables
+in a Python list comprehensions. This is a limitation of Cheetah's
+parser; it can't tell which variables in a list comprehension are
+the intermediate variables, so you have to help it. For example:
+
+::
+
+ #set $theRange = [x ** 2 for x in $range(10)]
+
+{$theRange} is a regular {#set} variable. {$range} is a Python
+built-in function. But {x} is a scratch variable internal to the
+list comprehension: if you type {$x}, Cheetah will miscompile it.
+
+NameMapper Syntax
+-----------------
+
+(language.namemapper)
+
+One of our core aims for Cheetah was to make it easy for
+non-programmers to use. Therefore, Cheetah uses a simplified syntax
+for mapping placeholders in Cheetah to values in Python. It's known
+as the { NameMapper syntax} and allows for non-programmers to use
+Cheetah without knowing (a) the difference between an instance and
+a dictionary, (b) what functions and methods are, and (c) what
+'self' is. A side benefit is that you can change the underlying
+data structure (e.g., instance to dictionary or vice-versa) without
+having to modify the templates.
+
+NameMapper syntax is used for all variables in Cheetah placeholders
+and directives. If desired, it can be turned off via the {Template}
+class' {'useNameMapper'} compiler setting. But it's doubtful you'd
+ever want to turn it off.
+
+Example
+~~~~~~~
+
+(language.namemapper.example)
+
+Consider this scenario:
+
+You are building a customer information system. The designers with
+you want to use information from your system on the client's
+website -AND- they want to understand the display code and so they
+can maintian it themselves.
+
+You write a UI class with a 'customers' method that returns a
+dictionary of all the customer objects. Each customer object has an
+'address' method that returns the a dictionary with information
+about the customer's address. The designers want to be able to
+access that information.
+
+Using PSP, the display code for the website would look something
+like the following, assuming your servlet subclasses the class you
+created for managing customer information:
+
+::
+
+ <%= self.customer()[ID].address()['city'] %> (42 chars)
+
+With Cheetah's NameMapper syntax, you can use any of the
+following:
+
+::
+
+ $self.customers()[$ID].address()['city'] (39 chars)
+ --OR--
+ $customers()[$ID].address()['city']
+ --OR--
+ $customers()[$ID].address().city
+ --OR--
+ $customers()[$ID].address.city
+ --OR--
+ $customers[$ID].address.city (27 chars)
+
+Which of these would you prefer to explain to the designers, who
+have no programming experience? The last form is 15 characters
+shorter than the PSP version and - conceptually - far more
+accessible. With PHP or ASP, the code would be even messier than
+with PSP.
+
+This is a rather extreme example and, of course, you could also
+just implement {$getCustomer($ID).city} and obey the Law of Demeter
+(search Google for more on that). But good object orientated design
+isn't the point of this example.
+
+Dictionary Access
+~~~~~~~~~~~~~~~~~
+
+(language.namemapper.dict)
+
+NameMapper syntax allows access to dictionary items with the same
+dotted notation used to access object attributes in Python. This
+aspect of NameMapper syntax is known as 'Unified Dotted Notation'.
+For example, with Cheetah it is possible to write:
+
+::
+
+ $customers()['kerr'].address() --OR-- $customers().kerr.address()
+
+where the second form is in NameMapper syntax.
+
+This works only with dictionary keys that also happen to be valid
+Python identifiers.
+
+Autocalling
+~~~~~~~~~~~
+
+(language.namemapper.autocalling)
+
+Cheetah automatically detects functions and methods in Cheetah
+$variables and calls them if the parentheses have been left off.
+Our previous example can be further simplified to:
+
+::
+
+ $customers.kerr.address
+
+As another example, if 'a' is an object, 'b' is a method
+
+::
+
+ $a.b
+
+is equivalent to
+
+::
+
+ $a.b()
+
+If b returns a dictionary, then following variations are possible
+
+::
+
+ $a.b.c --OR-- $a.b().c --OR-- $a.b()['c']
+
+where 'c' is a key in the dictionary that a.b() returns.
+
+Further notes:
+
+
+- When Cheetah autocalls a function/method, it calls it without
+ any arguments. Thus, the function/method must have been declared
+ without arguments (except {self} for methods) or to provide default
+ values for all arguments. If the function requires arguments, you
+ must use the {()}.
+
+- Cheetah autocalls only functions and methods. Classes and other
+ callable objects are not autocalled. The reason is that the primary
+ purpose of a function/method is to call it, whereas the primary
+ purpose of an instance is to look up its attributes or call its
+ methods, not to call the instance itself. And calling a class may
+ allocate large sums of memory uselessly or have other side effects,
+ depending on the class. For instance, consider {$myInstance.fname}.
+ Do we want to look up {fname} in the namespace of {myInstance} or
+ in the namespace of whatever {myinstance} returns? It could go
+ either way, so Cheetah follows the principle of least surprise. If
+ you { do} want to call the instance, put the {()} on, or rename the
+ {.\_\_call\_\_()} method to {.\_\_str\_\_}.
+
+- Autocalling can be disabled via Cheetah's 'useAutocalling'
+ compiler setting. You can also disable it for one placeholder by
+ using the syntax {$getVar('varName', 'default value', False)}.
+ ({.getVar()} works only with searchList values.)
+
+
+Namespace cascading and the searchList
+--------------------------------------
+
+(language.searchList)
+
+When Cheetah maps a variable name in a template to a Python value,
+it searches several namespaces in order:
+
+
+#. { Local variables:} created by {#set}, {#for}, or predefined by
+ Cheetah.
+
+#. The { searchList}, consisting of:
+
+
+ #. {#set global} variables.
+
+ #. The { searchList} containers you passed to the {Template}
+ constructor, if any.
+
+ #. The { Template instance} ("self"). This contains any attributes
+ you assigned, {#def} methods and {#block methods},
+ attributes/methods inherited via {#extends}, and other
+ attributes/methods built into {Template} or inherited by it
+ (there's a list of all these methods in section tips.allMethods).
+
+
+#. { Python globals:} created by {#import}, {#from ... import}, or
+ otherwise predefined by Cheetah.
+
+#. { Python builtins:} {None}, {max}, etc.
+
+
+The first matching name found is used.
+
+Remember, these namespaces apply only to the { first} identifier
+after the {$}. In a placeholder like {$a.b}, only 'a' is looked up
+in the searchList and other namespaces. 'b' is looked up only
+inside 'a'.
+
+A searchList container can be any Python object with attributes or
+keys: dictionaries, instances, classes or modules. If an instance
+contains both attributes and keys, its attributes are searched
+first, then its keys.
+
+Because the {Template} instance is part of the searchList, you can
+access its attributes/methods without 'self': {$myAttr}. However,
+use the 'self' if you want to make sure you're getting the
+{Template} attribute and not a same-name variable defined in a
+higher namespace: {$self.myAttr}. This works because "self" itself
+is a local variable.
+
+The final resulting value, after all lookups and function calls
+(but before the filter is applied) is called the { placeholder
+value}, no matter which namespace it was found in.
+
+{ { Note carefully:}} if you put an object 'myObject' in the
+searchList, you { cannot} look up {$myObject}! You can look up only
+the attributes/keys { inside} 'myObject'.
+
+Earlier versions of Cheetah did not allow you to override Python
+builtin names, but this was fixed in Cheetah 0.9.15.
+
+If your template will be used as a Webware servlet, do not override
+methods 'name' and 'log' in the {Template} instance or it will
+interfere with Webware's logging. However, it { is} OK to use those
+variables in a higher namespace, since Webware doesn't know about
+Cheetah namespaces.
+
+Missing Values
+--------------
+
+(language.namemapper.missing)
+
+If NameMapper can not find a Python value for a Cheetah variable
+name, it will raise the NameMapper.NotFound exception. You can use
+the {#errorCatcher} directive (section errorHandling.errorCatcher)
+or { errorCatcher} Template constructor argument (section
+howWorks.constructing) to specify an alternate behaviour. BUT BE
+AWARE THAT errorCatcher IS ONLY INTENDED FOR DEBUGGING!
+
+To provide a default value for a placeholder, write it like this:
+{$getVar('varName', 'default value')}. If you don't specify a
+default and the variable is missing, {NameMapper.NotFound} will be
+raised.
+
+Directive Syntax Rules
+----------------------
+
+(language.directives.syntax)
+
+Directive tags begin with a hash character (#) and are used for
+comments, loops, conditional blocks, includes, and all other
+advanced features. Cheetah uses a Python-like syntax inside
+directive tags and understands any valid Python expression. {
+However, unlike Python, Cheetah does not use colons (:) and
+indentation to mark off multi-line directives.} That doesn't work
+in an environment where whitespace is significant as part of the
+text. Instead, multi-line directives like {#for} have corresponding
+closing tags ({#end for}). Most directives are direct mirrors of
+Python statements.
+
+Many directives have arguments after the opening tag, which must be
+in the specified syntax for the tag. All end tags have the
+following syntax:
+
+::
+
+ #end TAG_NAME [EXPR]
+
+The expression is ignored, so it's essentially a comment.
+
+Directive closures and whitespace handling
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+(language.directives.closures) Directive tags can be closed
+explicitly with {#}, or implicitly with the end of the line if
+you're feeling lazy.
+
+::
+
+ #block testBlock #
+ Text in the body of the
+ block directive
+ #end block testBlock #
+
+is identical to:
+
+::
+
+ #block testBlock
+ Text in the body of the
+ block directive
+ #end block testBlock
+
+When a directive tag is closed explicitly, it can be followed with
+other text on the same line:
+
+::
+
+ bah, bah, #if $sheep.color == 'black'# black#end if # sheep.
+
+When a directive tag is closed implicitly with the end of the line,
+all trailing whitespace is gobbled, including the newline
+character:
+
+::
+
+ """
+ foo #set $x = 2
+ bar
+ """
+ outputs
+ """
+ foo bar
+ """
+
+ while
+ """
+ foo #set $x = 2 #
+ bar
+ """
+ outputs
+ """
+ foo
+ bar
+ """
+
+When a directive tag is closed implicitly AND there is no other
+text on the line, the ENTIRE line is gobbled up including any
+preceeding whitespace:
+
+::
+
+ """
+ foo
+ #set $x = 2
+ bar
+ """
+ outputs
+ """
+ foo
+ bar
+ """
+
+ while
+ """
+ foo
+ - #set $x = 2
+ bar
+ """
+ outputs
+ """
+ foo
+ - bar
+ """
+
+The {#slurp} directive (section output.slurp) also gobbles up
+whitespace.
+
+Spaces outside directives are output { exactly} as written. In the
+black sheep example, there's a space before "black" and another
+before "sheep". So although it's legal to put multiple directives
+on one line, it can be hard to read.
+
+::
+
+ #if $a# #echo $a + 1# #end if
+ - There's a space between each directive,
+ or two extra spaces total.
+ #if $a##echo $a + 1##end if
+ - No spaces, but you have to look closely
+ to verify none of the ``##'' are comment markers.
+ #if $a##echo $a + 1##end if ### A comment.
+ - In ``###'', the first ``#'' ends the directive,
+ the other two begin the comment. (This also shows
+ how you can add extra whitespace in the directive
+ tag without affecting the output.)
+ #if $a##echo $a + 1##end if # ## A comment.
+ - More readable, but now there's a space before the
+ comment.
+
+