summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhierro <hierro>2002-04-21 19:16:50 +0000
committerhierro <hierro>2002-04-21 19:16:50 +0000
commitaaed495ff81c08e58901022152c5129511632543 (patch)
tree9bee272c83f859cc8cc7a18ecb99cbd04b949ccd
parent92a4a7f34ba398f182d1e63fa70e424b812377fc (diff)
downloadpython-cheetah-aaed495ff81c08e58901022152c5129511632543.tar.gz
All changes to date.
-rw-r--r--docs/devel_guide_src/Makefile4
-rw-r--r--docs/devel_guide_src/bnf.tex7
-rw-r--r--docs/devel_guide_src/comments.tex7
-rw-r--r--docs/devel_guide_src/compiler.tex11
-rw-r--r--docs/devel_guide_src/compiler2.tex11
-rw-r--r--docs/devel_guide_src/design.tex11
-rw-r--r--docs/devel_guide_src/devel_guide.tex63
-rw-r--r--docs/devel_guide_src/documenting.tex11
-rw-r--r--docs/devel_guide_src/errorHandling.tex11
-rw-r--r--docs/devel_guide_src/files.tex11
-rw-r--r--docs/devel_guide_src/flowControl.tex7
-rw-r--r--docs/devel_guide_src/inheritanceEtc.tex7
-rw-r--r--docs/devel_guide_src/introduction.tex42
-rw-r--r--docs/devel_guide_src/output.tex7
-rw-r--r--docs/devel_guide_src/parser.tex11
-rw-r--r--docs/devel_guide_src/patching.tex11
-rw-r--r--docs/devel_guide_src/placeholders.tex512
-rw-r--r--docs/devel_guide_src/pyModules.tex245
-rw-r--r--docs/devel_guide_src/template.tex11
19 files changed, 916 insertions, 84 deletions
diff --git a/docs/devel_guide_src/Makefile b/docs/devel_guide_src/Makefile
index e498386..94153e4 100644
--- a/docs/devel_guide_src/Makefile
+++ b/docs/devel_guide_src/Makefile
@@ -1,11 +1,13 @@
# You must change PYTHONSRC to the path of your Python source distributon.
-PYTHONSRC=/home/iron/nobackup/PYTHON/Python-2.2b1
+PYTHONSRC=/home/iron/nobackup/PYTHON/Python-2.2
DOCNAME=devel_guide
MKHOWTO=$(PYTHONSRC)/Doc/tools/mkhowto
MAIN_TEX_FILE= devel_guide.tex
all: ps pdf html htmlMultiPage text
+almost-all: ps html htmlMultiPage text
+
pdf:
$(MKHOWTO) --pdf $(MAIN_TEX_FILE)
mv $(DOCNAME).pdf ../
diff --git a/docs/devel_guide_src/bnf.tex b/docs/devel_guide_src/bnf.tex
new file mode 100644
index 0000000..aa7149c
--- /dev/null
+++ b/docs/devel_guide_src/bnf.tex
@@ -0,0 +1,7 @@
+\section{A BNF Grammar of Cheetah}
+\label{bnf}
+
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/comments.tex b/docs/devel_guide_src/comments.tex
new file mode 100644
index 0000000..ff98d72
--- /dev/null
+++ b/docs/devel_guide_src/comments.tex
@@ -0,0 +1,7 @@
+\section{Directives: Comments}
+\label{comments.}
+
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/compiler.tex b/docs/devel_guide_src/compiler.tex
new file mode 100644
index 0000000..9e807ad
--- /dev/null
+++ b/docs/devel_guide_src/compiler.tex
@@ -0,0 +1,11 @@
+\section{The compiler}
+\label{compiler}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{}
+\label{}
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/compiler2.tex b/docs/devel_guide_src/compiler2.tex
new file mode 100644
index 0000000..7f277eb
--- /dev/null
+++ b/docs/devel_guide_src/compiler2.tex
@@ -0,0 +1,11 @@
+\section{The Compiler (more info)}
+\label{compiler2}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{}
+\label{}
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/design.tex b/docs/devel_guide_src/design.tex
new file mode 100644
index 0000000..84df362
--- /dev/null
+++ b/docs/devel_guide_src/design.tex
@@ -0,0 +1,11 @@
+\section{Design Decisions and Tradeoffs}
+\label{design}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{}
+\label{}
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/devel_guide.tex b/docs/devel_guide_src/devel_guide.tex
index b9d48d3..1d9b46e 100644
--- a/docs/devel_guide_src/devel_guide.tex
+++ b/docs/devel_guide_src/devel_guide.tex
@@ -2,10 +2,10 @@
\usepackage{moreverb} %% Verbatim Code Listings
\title{Cheetah Developers' Guide}
-\release{0.9.12 post b2}
+\release{0.9.12}
-\author{The Cheetah Development Team}
-\authoraddress{\email{cheetahtemplate-discuss@lists.sourceforge.net}}
+\author{Mike Orr}
+\authoraddress{\email{iron@mso.oz.net}}
\begin{document}
\maketitle
@@ -13,21 +13,14 @@
%\tableofcontents
-\copyright{Copyright 2002, The Cheetah Development Team.
+\copyright{Copyright 2002, Mike Orr.
This document may be copied and modified under the terms of the
{\bf Open Publication License} \url{http://www.opencontent.org/openpub/} }
-This document is not written yet. It is intended to accomplish the following:
+This document is still being written. Material to include:
-** A sample small .tmpl file and its corresponding .py template module.
-
-** Show how cheetah-compile translates placeholders into Python, as well as
-caching, filter, the other directives, and comments.
-
-** Show how placeholders which are local/global/builtin variables get
-translated to bare variable names, while other placeholders are turned into a
-searchList lookup. This is what '\$' does: besides marking the beginning of a
-placeholder, it intelligently converts it to one or the other.
+** Show how cheetah-compile translates caching, filter, the other directives,
+and comments.
** List all the methods accessible via 'self'. (Some of this may belong in the
Users' Guide.)
@@ -41,32 +34,44 @@ test suite works.
** History of Cheetah (including the WebOnions image). Describe major
milestone changes from the changelog.
-% @@MO: WebOnions logo.
+% @@MO: WebOnions logo. (Goes with history.)
** Design decisions and tradeoffs that have been made.
** How to build the documentation. Why LaTeX, a minimum LaTeX reference, etc.
-** Show where you can omit the '\$' and where you can't.
+** Show where you can omit the '\$' (leniency) and where you can't.
+
+** Appendix A will be a formal BNF grammar of Cheetah.
% Two files placeholders.tex and safeDelegation.tex contain material to be
%incorporated into this guide.
-% Why all the \$s? "Smart" variable disposition. Where you have to use them
-% in expressions.
-% Canadian spelling in honour of Cheetah's creator.
-
-%% @@MO: VFS=... is a common Python speed hack.
-
- %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %\include{whoShouldRead}
- %\include{introduction}
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %\appendix
- %\include{glossary}
- %\include{grammar}
- %\include{APIref}
+ \include{introduction}
+ \include{files}
+ \include{template}
+ \include{compiler}
+ \include{pyModules}
+ \include{placeholders}
+ \include{comments}
+ \include{output}
+ \include{inheritanceEtc}
+ \include{flowControl}
+ \include{errorHandling}
+ \include{parserInstructions}
+
+ \include{parser}
+ \include{compiler2}
+ \include{design}
+ \include{patching}
+ \include{documenting}
+
+ %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ \appendix
+ \include{bnf}
+ \include{safeDelegation}
\end{document}
% Local Variables:
diff --git a/docs/devel_guide_src/documenting.tex b/docs/devel_guide_src/documenting.tex
new file mode 100644
index 0000000..81063eb
--- /dev/null
+++ b/docs/devel_guide_src/documenting.tex
@@ -0,0 +1,11 @@
+\section{Documenting Cheetah}
+\label{documenting}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{}
+\label{}
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/errorHandling.tex b/docs/devel_guide_src/errorHandling.tex
new file mode 100644
index 0000000..e5b57d2
--- /dev/null
+++ b/docs/devel_guide_src/errorHandling.tex
@@ -0,0 +1,11 @@
+\section{Directives: Error Handling}
+\label{errorHandling}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{}
+\label{}
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/files.tex b/docs/devel_guide_src/files.tex
new file mode 100644
index 0000000..083267d
--- /dev/null
+++ b/docs/devel_guide_src/files.tex
@@ -0,0 +1,11 @@
+\section{Files}
+\label{files}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{}
+\label{}
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/flowControl.tex b/docs/devel_guide_src/flowControl.tex
new file mode 100644
index 0000000..f3f5537
--- /dev/null
+++ b/docs/devel_guide_src/flowControl.tex
@@ -0,0 +1,7 @@
+\section{Directives: Flow Control}
+\label{flowControl}
+
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/inheritanceEtc.tex b/docs/devel_guide_src/inheritanceEtc.tex
new file mode 100644
index 0000000..cd0e8c1
--- /dev/null
+++ b/docs/devel_guide_src/inheritanceEtc.tex
@@ -0,0 +1,7 @@
+\section{Directives: Import, Inheritance, Declaration and Assignment}
+\label{inheritanceEtc}
+
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/introduction.tex b/docs/devel_guide_src/introduction.tex
new file mode 100644
index 0000000..6f59999
--- /dev/null
+++ b/docs/devel_guide_src/introduction.tex
@@ -0,0 +1,42 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\section{Introduction}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Who should read this Guide?}
+
+The Cheetah Developers' Guide is for those who want to learn how Cheetah works
+internally, or wish to modify or extend Cheetah. It is assumed that
+you've read the Cheetah Users' Guide and have an intermediate knowledge of
+Python.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Contents}
+
+This Guide takes a behaviorist approach. First we'll look at what the
+Cheetah compiler generates when it compiles a template definition, and
+how it compiles the various \$placeholder features and \#directives.
+Then we'll stroll through the files in the Cheetah source distribution
+and show how each file contributes to the compilation and/or filling of
+templates. We'll list every method/attribute inherited by a template
+object. Finally, we'll describe how to submit
+bugfixes/enhancements to Cheetah, and how to add to the documentation.
+
+Appendices will contain a BNF syntax of Cheetah constructs, and ...
+\code{self}
+cheetah-compile does when it converts a template definition to a .py
+template module. Since
+compiler, it describes what happens to all templates.
+
+This Guide first takes a look at the files inside the Cheetah source
+distribution. Then it gives a brief overview of the \code{Template} object.
+Then it describes the Cheetah compiler, how it works. Then it takes a look at
+.py template modules. Then we discuss the various placeholder syntaxes,
+expressions and directives, and see their effect on the .py template module.
+Then we'll take a closer look at the parser and then the compiler.
+
+Finally, chapter ?? shows how to modify or extend Cheetah without incurring
+the wrath of the developers, and how to contribute to Cheetah's documentation.
+
+% Local Variables:
+% TeX-master: "users_guide"
+% End:
diff --git a/docs/devel_guide_src/output.tex b/docs/devel_guide_src/output.tex
new file mode 100644
index 0000000..ea2f5c3
--- /dev/null
+++ b/docs/devel_guide_src/output.tex
@@ -0,0 +1,7 @@
+\section{Directives: Output}
+\label{output}
+
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/parser.tex b/docs/devel_guide_src/parser.tex
new file mode 100644
index 0000000..ebce787
--- /dev/null
+++ b/docs/devel_guide_src/parser.tex
@@ -0,0 +1,11 @@
+\section{The parser (more info)}
+\label{parser}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{}
+\label{}
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/patching.tex b/docs/devel_guide_src/patching.tex
new file mode 100644
index 0000000..7e194f6
--- /dev/null
+++ b/docs/devel_guide_src/patching.tex
@@ -0,0 +1,11 @@
+\section{Patching Cheetah}
+\label{patching}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{}
+\label{}
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/placeholders.tex b/docs/devel_guide_src/placeholders.tex
index e34d5fc..c2d7de9 100644
--- a/docs/devel_guide_src/placeholders.tex
+++ b/docs/devel_guide_src/placeholders.tex
@@ -1,54 +1,458 @@
-This is not in legal TeX syntax yet, so don't try to compile it!
-
-Here's an analysis of NameMapper.py.
-
- valueForKey(obj, key):
-Search 'obj' for 'key'. Tries to return (1) a same-name attribute, (2)
-a same-name dictionary key, or (3) an attribute that is "'_' + key".
-If fail, raise NameMapper.NotFound.
-
- valueForName(obj, name):
-Wrapper for _valueForName. Splits 'name' into 'nameChunks' at dots.
-'executeCallables' is, I assume, whether to do autocalling.
-
- _valueForName(obj, nameChunks, executeCallables):
-'passNamespace' is false initially, since valueForName doesn't specify it.
-Take the first identifier in nameChunks. If 'passNamespace', do
-valueForKey on it (if fail, raise NameMapper.NotFoundInNamespace).
-If not 'passNamespace', same but if fail, allow NameMapper.NotFound to
-propagate. Why the difference in exceptions?
-
-Assuming the first identifier was successfully found, if the value meets
-autocallable criteria, call it.
-
-If there are further components in nameChunks, recurse using the found
-value as 'obj', and "nameChunks minus the first identifier" as
-'nameChunks' (so that the next identifier will be first each recursion).
-The result is a name lookup of a.b.c.d.e, looking recursively in 'obj' only.
-No searchList is involved.
-
- valueFromSearchList(searchList, name, executeCallables):
-name -> nameChunks. Call _valueForName using each element in searchList
-in turn as the searchable 'obj'. 'passNamespace' is always True, which
-causes the called function (_valueForName) to raise
-NameMapper.NotFoundInNamespace instead of NameMapper.NotFound if fail.
-Why? Especially since this function (valueFromSearchList) converts
-NameMapper.NotFoundInNamespace to NameMapper.NotFound anyway, so the net
-effect is the same.
-
- hasKey(obj, key):
-Boolean whether 'obj' has 'key', searching the attributes, subscripts
-and underlined attributes. There is one discrepency from
-valueForKey(): the underlined attribute is searched second rather than
-third.
-
- hasName(obj, key):
-Boolean whether 'obj' has 'name', based on valueForName.
-
-What's the difference between a 'key' and a 'name'?
-
-Class 'Mixin' wraps valueForName and valueForKey into methods.
-Presumably, this is inherited by Template and thus defines the public
-entry points for this module. Meaning that if I want to have a
-boolean "placeholder value exists" method in Template, I'll have to
-wrap hasKey or hasName. But which one? And why do both functions exist?
+\section{Placeholders}
+\label{placeholders}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Simple placeholders}
+\label{placeholders.simple}
+
+Let's add a few \$placeholders to our template:
+
+\begin{verbatim}
+>>> from Cheetah.Template import Template
+>>> values = {'what': 'surreal', 'punctuation': '?'}
+>>> t = Template("""\
+... Hello, $what world$punctuation
+... One of Python's least-used functions is $xrange.
+... """, [values])
+>>> print t
+Hello, surreal world?
+One of Python's least-used functions is <built-in function xrange>.
+
+>>> print t.generatedModuleCode()
+ 1 #!/usr/bin/env python
+
+ 2 """
+ 3 Autogenerated by CHEETAH: The Python-Powered Template Engine
+ 4 CHEETAH VERSION: 0.9.12
+ 5 Generation time: Sun Apr 21 00:53:01 2002
+ 6 """
+
+ 7 __CHEETAH_genTime__ = 'Sun Apr 21 00:53:01 2002'
+ 8 __CHEETAH_version__ = '0.9.12'
+
+ 9 ##################################################
+ 10 ## DEPENDENCIES
+
+ 11 import sys
+ 12 import os
+ 13 import os.path
+ 14 from os.path import getmtime, exists
+ 15 import time
+ 16 import types
+ 17 from Cheetah.Template import Template
+ 18 from Cheetah.DummyTransaction import DummyTransaction
+ 19 from Cheetah.NameMapper import NotFound, valueForName,
+ valueFromSearchList
+ 20 import Cheetah.Filters as Filters
+ 21 import Cheetah.ErrorCatchers as ErrorCatchers
+
+ 22 ##################################################
+ 23 ## MODULE CONSTANTS
+
+ 24 try:
+ 25 True, False
+ 26 except NameError:
+ 27 True, False = (1==1), (1==0)
+
+ 28 ##################################################
+ 29 ## CLASSES
+
+ 30 class GenTemplate(Template):
+ 31 """
+ 32
+ 33 Autogenerated by CHEETAH: The Python-Powered Template Engine
+ 34 """
+
+ 35 ##################################################
+ 36 ## GENERATED METHODS
+
+
+ 37 def __init__(self, *args, **KWs):
+ 38 """
+ 39
+ 40 """
+
+ 41 Template.__init__(self, *args, **KWs)
+
+ 42 def respond(self,
+ 43 trans=None,
+ 44 dummyTrans=False,
+ 45 VFS=valueFromSearchList,
+ 46 VFN=valueForName,
+ 47 getmtime=getmtime,
+ 48 currentTime=time.time):
+
+
+ 49 """
+ 50 This is the main method generated by Cheetah
+ 51 """
+
+ 52 if not trans:
+ 53 trans = DummyTransaction()
+ 54 dummyTrans = True
+ 55 write = trans.response().write
+ 56 SL = self._searchList
+ 57 filter = self._currentFilter
+ 58 globalSetVars = self._globalSetVars
+ 59
+ 60 ########################################
+ 61 ## START - generated method body
+ 62
+ 63 write('Hello, ')
+ 64 write(filter(VFS(SL,"what",1))) # generated from '$what' at
+ # line 1, col 8.
+ 65 write(' world')
+ 66 write(filter(VFS(SL,"punctuation",1))) # generated from
+ # '$punctuation' at line 1, col 19.
+ 67 write("\nOne of Python's least-used methods is ")
+ 68 write(filter(xrange)) # generated from '$xrange' at line 2,
+ # col 39.
+ 69 write('.\n')
+ 70
+ 71 ########################################
+ 72 ## END - generated method body
+ 73
+ 74 if dummyTrans:
+ 75 return trans.response().getvalue()
+ 76 else:
+ 77 return ""
+ 78
+ 79 ##################################################
+ 80 ## GENERATED ATTRIBUTES
+
+
+ 81 __str__ = respond
+
+ 82 _mainCheetahMethod_for_GenTemplate= 'respond'
+
+
+ 83 # CHEETAH was developed by Tavis Rudd, Chuck Esterbrook, Ian Bicking
+ # and Mike Orr;
+ 84 # with code, advice and input from many other volunteers.
+ 85 # For more information visit http://www.CheetahTemplate.org
+
+ 86 ##################################################
+ 87 ## if run from command line:
+ 88 if __name__ == '__main__':
+ 89 GenTemplate().runAsMainProgram()
+
+\end{verbatim}
+
+(Again, I have added line numbers and split the lines as in the previous
+chapter.)
+
+This generated template module is different from the previous one in several
+trivial respects and one important respect. Trivially,
+\code{.\_filePath} and \code{.\_fileMtime} are not updated in
+\code{.\_\_init\_\_}, so they inherit the value \code{None} from
+\code{Template}. Also, that if-stanza in \code{.respond} that recompiles the
+template if the source file changes is missing -- because there is no source
+file. So this module is several lines shorter than the other one.
+
+But the important way this module is different is that instead of the one
+\code{write} call outputting a string literal, this module has a series of
+\code{write} calls (lines 63-69) outputting successive chunks of the
+template. Regular text has been translated into a string literal, and
+placeholders into function calls. Every placeholder is wrapped inside a
+\code{filter} call to apply the current output filter. (The default
+output filter converts all objects to strings, and \code{None} to \code{""}.)
+
+Placeholders referring to a Python builtin like \code{xrange} (line 68)
+generate a bare variable name. Placeholders to be looked up in the searchList
+have a nested function call; e.g.,
+\begin{verbatim}
+write(filter(VFS(SL,"what",1))) # generated from '$what' at line 1, col 8.
+\end{verbatim}
+\code{VFS}, remember, is a function imported from \code{Cheetah.NameMapper}
+that looks up a value in a searchList. So we pass it the searchList, the
+name to look up, and a boolean (1) indicating we want autocalling. (It's
+\code{1} rather than \code{True} because it's generated from an
+\code{and} expression, and that's what Python 2.2 outputs for true \code{and}
+expressions.)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Complex placeholders}
+\label{placeholders.complex}
+
+Placeholders can get far more complicated than that. This example shows what
+kind of code the various NameMapper features produce. The formulas are
+taken from Cheetah's test suite, in the
+\code{Cheetah.Tests.SyntaxAndOutput.Placeholders} class.
+
+\begin{verbatim}
+1 placeholder: $aStr
+2 placeholders: $aStr $anInt
+2 placeholders, back-to-back: $aStr$anInt
+1 placeholder enclosed in {}: ${aStr}
+1 escaped placeholder: \$var
+func placeholder - with (): $aFunc()
+func placeholder - with (int): $aFunc(1234)
+func placeholder - with (string): $aFunc('aoeu')
+func placeholder - with ('''\nstring'\n'''): $aFunc('''\naoeu'\n''')
+func placeholder - with (string*int): $aFunc('aoeu'*2)
+func placeholder - with (int*float): $aFunc(2*2.0)
+Python builtin values: $None $True $False
+func placeholder - with ($arg=float): $aFunc($arg=4.0)
+deeply nested argstring: $aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ):
+function with None: $aFunc(None)
+autocalling: $aFunc! $aFunc().
+nested autocalling: $aFunc($aFunc).
+list subscription: $aList[0]
+list slicing: $aList[:2]
+list slicing and subcription combined: $aList[:2][0]
+dict - NameMapper style: $aDict.one
+dict - Python style: $aDict['one']
+dict combined with autocalled string method: $aDict.one.upper
+dict combined with string method: $aDict.one.upper()
+nested dict - NameMapper style: $aDict.nestedDict.two
+nested dict - Python style: $aDict['nestedDict']['two']
+nested dict - alternating style: $aDict['nestedDict'].two
+nested dict - NameMapper style + method: $aDict.nestedDict.two.upper
+nested dict - alternating style + method: $aDict['nestedDict'].two.upper
+nested dict - NameMapper style + method + slice: $aDict.nestedDict.two.upper[:4]
+nested dict - Python style, variable key: $aDict[$anObj.meth('nestedDict')].two
+object method: $anObj.meth1
+object method + complex slice: $anObj.meth1[0: ((4/4*2)*2)/$anObj.meth1(2) ]
+very complex slice: $( anObj.meth1[0: ((4/4*2)*2)/$anObj.meth1(2) ] )
+\end{verbatim}
+
+We'll need a big program to set up the placeholder values. Here it is:
+
+\begin{verbatim}
+#!/usr/bin/env python
+from ComplexExample import ComplexExample
+
+try: # Python >= 2.2.1
+ True, False
+except NameError: # Older Python
+ True, False = (1==1), (1==0)
+
+class DummyClass:
+ _called = False
+ def __str__(self):
+ return 'object'
+
+ def meth(self, arg="arff"):
+ return str(arg)
+
+ def meth1(self, arg="doo"):
+ return arg
+
+ def meth2(self, arg1="a1", arg2="a2"):
+ return str(arg1) + str(arg2)
+
+ def callIt(self, arg=1234):
+ self._called = True
+ self._callArg = arg
+
+def dummyFunc(arg="Scooby"):
+ return arg
+
+defaultTestNameSpace = {
+ 'aStr':'blarg',
+ 'anInt':1,
+ 'aFloat':1.5,
+ 'aList': ['item0','item1','item2'],
+ 'aDict': {'one':'item1',
+ 'two':'item2',
+ 'nestedDict':{1:'nestedItem1',
+ 'two':'nestedItem2'
+ },
+ 'nestedFunc':dummyFunc,
+ },
+ 'aFunc': dummyFunc,
+ 'anObj': DummyClass(),
+ 'aMeth': DummyClass().meth1,
+}
+
+print ComplexExample( searchList=[defaultTestNameSpace] )
+\end{verbatim}
+
+Here's the output:
+
+\begin{verbatim}
+1 placeholder: blarg
+2 placeholders: blarg 1
+2 placeholders, back-to-back: blarg1
+1 placeholder enclosed in {}: blarg
+1 escaped placeholder: $var
+func placeholder - with (): Scooby
+func placeholder - with (int): 1234
+func placeholder - with (string): aoeu
+func placeholder - with ('''\nstring'\n'''):
+aoeu'
+
+func placeholder - with (string*int): aoeuaoeu
+func placeholder - with (int*float): 4.0
+Python builtin values: 1 0
+func placeholder - with ($arg=float): 4.0
+deeply nested argstring: 1:
+function with None:
+autocalling: Scooby! Scooby.
+nested autocalling: Scooby.
+list subscription: item0
+list slicing: ['item0', 'item1']
+list slicing and subcription combined: item0
+dict - NameMapper style: item1
+dict - Python style: item1
+dict combined with autocalled string method: ITEM1
+dict combined with string method: ITEM1
+nested dict - NameMapper style: nestedItem2
+nested dict - Python style: nestedItem2
+nested dict - alternating style: nestedItem2
+nested dict - NameMapper style + method: NESTEDITEM2
+nested dict - alternating style + method: NESTEDITEM2
+nested dict - NameMapper style + method + slice: NEST
+nested dict - Python style, variable key: nestedItem2
+object method: doo
+object method + complex slice: do
+very complex slice: do
+
+\end{verbatim}
+
+And here -- tada! -- is the generated module.
+To save space, I've included only the lines containing the \code{write} calls.
+The rest of the module is the same as in the first example, chapter
+\ref{pyModules.example}. I've truncated some of the lines to make them fit on
+the page.
+
+\begin{verbatim}
+ 1 write('1 placeholder: ')
+ 2 write(filter(VFS(SL,"aStr",1))) # generated from '$aStr' at line 1, col 16.
+ 3 write('\n2 placeholders: ')
+ 4 write(filter(VFS(SL,"aStr",1))) # generated from '$aStr' at line 2, col 17.
+ 5 write(' ')
+ 6 write(filter(VFS(SL,"anInt",1)))
+ # generated from '$anInt' at line 2, col 23.
+ 7 write('\n2 placeholders, back-to-back: ')
+ 8 write(filter(VFS(SL,"aStr",1))) # generated from '$aStr' at line 3, col 31.
+ 9 write(filter(VFS(SL,"anInt",1)))
+ # generated from '$anInt' at line 3, col 36.
+10 write('\n1 placeholder enclosed in {}: ')
+11 write(filter(VFS(SL,"aStr",1))) # generated from '${aStr}' at line 4,
+ # col 31.
+12 write('\n1 escaped placeholder: $var\nfunc placeholder - with (): ')
+13 write(filter(VFS(SL,"aFunc",0)())) # generated from '$aFunc()' at line 6,
+ # col 29.
+14 write('\nfunc placeholder - with (int): ')
+15 write(filter(VFS(SL,"aFunc",0)(1234))) # generated from '$aFunc(1234)' at
+ # line 7, col 32.
+16 write('\nfunc placeholder - with (string): ')
+17 write(filter(VFS(SL,"aFunc",0)('aoeu'))) # generated from "$aFunc('aoeu')"
+ # at line 8, col 35.
+18 write("\nfunc placeholder - with ('''\\nstring'\\n'''): ")
+19 write(filter(VFS(SL,"aFunc",0)('''\naoeu'\n'''))) # generated from
+ # "$aFunc('''\\naoeu'\\n''')" at line 9, col 46.
+20 write('\nfunc placeholder - with (string*int): ')
+21 write(filter(VFS(SL,"aFunc",0)('aoeu'*2))) # generated from
+ # "$aFunc('aoeu'*2)" at line 10, col 39.
+22 write('\nfunc placeholder - with (int*float): ')
+23 write(filter(VFS(SL,"aFunc",0)(2*2.0))) # generated from '$aFunc(2*2.0)'
+ # at line 11, col 38.
+24 write('\nPython builtin values: ')
+25 write(filter(None)) # generated from '$None' at line 12, col 24.
+26 write(' ')
+27 write(filter(True)) # generated from '$True' at line 12, col 30.
+28 write(' ')
+29 write(filter(False)) # generated from '$False' at line 12, col 36.
+30 write('\nfunc placeholder - with ($arg=float): ')
+31 write(filter(VFS(SL,"aFunc",0)(arg=4.0))) # generated from
+ # '$aFunc($arg=4.0)' at line 13, col 40.
+32 write('\ndeeply nested argstring: ')
+33 write(filter(VFS(SL,"aFunc",0)(
+ arg = VFS(SL,"aMeth",0)( arg = VFS(SL,"aFunc",0)( 1 ) ) )))
+ # generated from '$aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) )'
+ # at line 14, col 26.
+34 write(':\nfunction with None: ')
+35 write(filter(VFS(SL,"aFunc",0)(None))) # generated from '$aFunc(None)' at
+ # line 15, col 21.
+36 write('\nautocalling: ')
+37 write(filter(VFS(SL,"aFunc",1))) # generated from '$aFunc' at line 16,
+ # col 14.
+38 write('! ')
+39 write(filter(VFS(SL,"aFunc",0)())) # generated from '$aFunc()' at line 16,
+ # col 22.
+40 write('.\nnested autocalling: ')
+41 write(filter(VFS(SL,"aFunc",0)(VFS(SL,"aFunc",1)))) # generated from
+ # '$aFunc($aFunc)' at line 17, col 21.
+42 write('.\nlist subscription: ')
+43 write(filter(VFS(SL,"aList",1)[0])) # generated from '$aList[0]' at line
+ # 18, col 20.
+44 write('\nlist slicing: ')
+45 write(filter(VFS(SL,"aList",1)[:2])) # generated from '$aList[:2]' at
+ # line 19, col 15.
+46 write('\nlist slicing and subcription combined: ')
+47 write(filter(VFS(SL,"aList",1)[:2][0])) # generated from '$aList[:2][0]'
+ # at line 20, col 40.
+48 write('\ndict - NameMapper style: ')
+49 write(filter(VFS(SL,"aDict.one",1))) # generated from '$aDict.one' at line
+ # 21, col 26.
+50 write('\ndict - Python style: ')
+51 write(filter(VFS(SL,"aDict",1)['one'])) # generated from "$aDict['one']"
+ # at line 22, col 22.
+52 write('\ndict combined with autocalled string method: ')
+53 write(filter(VFS(SL,"aDict.one.upper",1))) # generated from
+ # '$aDict.one.upper' at line 23, col 46.
+54 write('\ndict combined with string method: ')
+55 write(filter(VFN(VFS(SL,"aDict.one",1),"upper",0)())) # generated from
+ # '$aDict.one.upper()' at line 24, col 35.
+56 write('\nnested dict - NameMapper style: ')
+57 write(filter(VFS(SL,"aDict.nestedDict.two",1))) # generated from
+ # '$aDict.nestedDict.two' at line 25, col 33.
+58 write('\nnested dict - Python style: ')
+59 write(filter(VFS(SL,"aDict",1)['nestedDict']['two'])) # generated from
+ # "$aDict['nestedDict']['two']" at line 26, col 29.
+60 write('\nnested dict - alternating style: ')
+61 write(filter(VFN(VFS(SL,"aDict",1)['nestedDict'],"two",1))) # generated
+ # from "$aDict['nestedDict'].two" at line 27, col 34.
+62 write('\nnested dict - NameMapper style + method: ')
+63 write(filter(VFS(SL,"aDict.nestedDict.two.upper",1))) # generated from
+ # '$aDict.nestedDict.two.upper' at line 28, col 42.
+64 write('\nnested dict - alternating style + method: ')
+65 write(filter(VFN(VFS(SL,"aDict",1)['nestedDict'],"two.upper",1)))
+ # generated from "$aDict['nestedDict'].two.upper" at line 29, col 43.
+66 write('\nnested dict - NameMapper style + method + slice: ')
+67 write(filter(VFN(VFS(SL,"aDict.nestedDict.two",1),"upper",1)[:4]))
+ # generated from '$aDict.nestedDict.two.upper[:4]' at line 30, col 50.
+68 write('\nnested dict - Python style, variable key: ')
+69 write(filter(VFN(VFS(SL,"aDict",1)
+ [VFN(VFS(SL,"anObj",1),"meth",0)('nestedDict')],"two",1)))
+ # generated from "$aDict[$anObj.meth('nestedDict')].two" at line 31,
+ # col 43.
+70 write('\nobject method: ')
+71 write(filter(VFS(SL,"anObj.meth1",1))) # generated from '$anObj.meth1' at
+ # line 32, col 16.
+72 write('\nobject method + complex slice: ')
+73 write(filter(VFN(VFS(SL,"anObj",1),"meth1",1)
+ [0: ((4/4*2)*2)/VFN(VFS(SL,"anObj",1),"meth1",0)(2) ]))
+ # generated from '$anObj.meth1[0: ((4/4*2)*2)/$anObj.meth1(2) ]'
+ # at line 33, col 32.
+74 write('\nvery complex slice: ')
+75 write(filter(VFN(VFS(SL,"anObj",1),"meth1",1)
+ [0: ((4/4*2)*2)/VFN(VFS(SL,"anObj",1),"meth1",0)(2) ] ))
+ # generated from '$( anObj.meth1[0: ((4/4*2)*2)/$anObj.meth1(2) ] )'
+ # at line 34, col 21.
+76 write('\n')
+\end{verbatim}
+
+For each placeholder lookup, the the innermost level of nesting is a \code{VFS}
+call, which looks up the first (leftmost) placeholder component in the
+searchList. This is wrapped by zero or more \code{VFN} calls, which perform
+Universal Dotted Notation lookup on the next dotted component of the
+placeholder, looking for an attribute or key by that name within the previous
+object (not in the searchList). Autocalling is performed by \code{VFS} and
+\code{VFN}: that's the reason for their third argument.
+
+Explicit function/method arguments, subscripts and keys (which
+are all expressions) are left unchanged, besides expanding any embedded
+\$placeholders in them. This means they must result in valid Python
+expressions, following the standard Python quoting rules.
+
+Built-in Python values (\code{None}, \code{True} and \code{False}) are
+converted to \code{filter(None)}, etc. They use normal Python variable
+lookup rather than \code{VFS}. (Cheetah emulates \code{True} and \code{False}
+using global variables for Python < 2.2.1, when they weren't builtins yet.)
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/pyModules.tex b/docs/devel_guide_src/pyModules.tex
new file mode 100644
index 0000000..1a91b4c
--- /dev/null
+++ b/docs/devel_guide_src/pyModules.tex
@@ -0,0 +1,245 @@
+\section{.py Template Modules}
+\label{pyModules}
+
+The next few chapters examine the structure of a .py template module and how
+the various directives and placeholder expressions effect it. This will give
+us a behavioral understanding of the Cheetah compiler -- what it does. We'll
+present the first generated module in its entirety, then show describe each
+placeholder and directive in terms of the changes it creates in the module.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{An example}
+\label{pyModules.example}
+
+Our first template, following a long noble tradition in computer tutorials,
+produces a familiar, friendly greeting. Here's the template:
+
+\begin{verbatim}
+Hello, world!
+\end{verbatim}
+
+... here's the output:
+
+\begin{verbatim}
+Hello, world!
+\end{verbatim}
+
+... and here's the .py template module cheetah-compile produced, with line
+numbers added:
+
+% @@MO: Is it possible to print the line numbers gray instead of black?
+
+\begin{verbatim}
+ 1 #!/usr/bin/env python
+
+ 2 """
+ 3 Autogenerated by CHEETAH: The Python-Powered Template Engine
+ 4 CHEETAH VERSION: 0.9.12
+ 5 Generation time: Sat Apr 20 14:27:47 2002
+ 6 Source file: x.tmpl
+ 7 Source file last modified: Wed Apr 17 22:10:59 2002
+ 8 """
+
+ 9 __CHEETAH_genTime__ = 'Sat Apr 20 14:27:47 2002'
+ 10 __CHEETAH_src__ = 'x.tmpl'
+ 11 __CHEETAH_version__ = '0.9.12'
+
+ 12 ##################################################
+ 13 ## DEPENDENCIES
+
+ 14 import sys
+ 15 import os
+ 16 import os.path
+ 17 from os.path import getmtime, exists
+ 18 import time
+ 19 import types
+ 20 from Cheetah.Template import Template
+ 21 from Cheetah.DummyTransaction import DummyTransaction
+ 22 from Cheetah.NameMapper import NotFound, valueForName,
+ valueFromSearchList
+ 23 import Cheetah.Filters as Filters
+ 24 import Cheetah.ErrorCatchers as ErrorCatchers
+
+ 25 ##################################################
+ 26 ## MODULE CONSTANTS
+
+ 27 try:
+ 28 True, False
+ 29 except NameError:
+ 30 True, False = (1==1), (1==0)
+
+ 31 ##################################################
+ 32 ## CLASSES
+
+ 33 class x(Template):
+ 34 """
+ 35
+ 36 Autogenerated by CHEETAH: The Python-Powered Template Engine
+ 37 """
+
+ 38 ##################################################
+ 39 ## GENERATED METHODS
+
+
+ 40 def __init__(self, *args, **KWs):
+ 41 """
+ 42
+ 43 """
+
+ 44 Template.__init__(self, *args, **KWs)
+ 45 self._filePath = 'x.tmpl'
+ 46 self._fileMtime = 1019106659
+
+ 47 def respond(self,
+ 48 trans=None,
+ 49 dummyTrans=False,
+ 50 VFS=valueFromSearchList,
+ 51 VFN=valueForName,
+ 52 getmtime=getmtime,
+ 53 currentTime=time.time):
+
+
+ 54 """
+ 55 This is the main method generated by Cheetah
+ 56 """
+
+ 57 if not trans:
+ 58 trans = DummyTransaction()
+ 59 dummyTrans = True
+ 60 write = trans.response().write
+ 61 SL = self._searchList
+ 62 filter = self._currentFilter
+ 63 globalSetVars = self._globalSetVars
+ 64
+ 65 ########################################
+ 66 ## START - generated method body
+ 67
+ 68 if exists(self._filePath) and getmtime(self._filePath) > \
+ self._fileMtime:
+ 69 self.compile(file=self._filePath)
+ 70 write(getattr(self, self._mainCheetahMethod_for_x)
+ (trans=trans))
+ 71 if dummyTrans:
+ 72 return trans.response().getvalue()
+ 73 else:
+ 74 return ""
+ 75 write('Hello, world!\n')
+ 76
+ 77 ########################################
+ 78 ## END - generated method body
+ 79
+ 80 if dummyTrans:
+ 81 return trans.response().getvalue()
+ 82 else:
+ 83 return ""
+ 84
+ 85 ##################################################
+ 86 ## GENERATED ATTRIBUTES
+
+
+ 87 __str__ = respond
+
+ 88 _mainCheetahMethod_for_x= 'respond'
+
+
+ 89 # CHEETAH was developed by Tavis Rudd, Chuck Esterbrook, Ian Bicking
+ # and Mike Orr;
+ 90 # with code, advice and input from many other volunteers.
+ 91 # For more information visit http://www.CheetahTemplate.org
+
+ 92 ##################################################
+ 93 ## if run from command line:
+ 94 if __name__ == '__main__':
+ 95 x().runAsMainProgram()
+
+\end{verbatim}
+
+(I added the line numbers for this Guide, and split a few lines to fit the
+page width. The continuation lines don't have line numbers, and I added
+indentation, backslashes and '\#' as necessary to make the result a valid
+Python program.)
+
+The Cheetah version used was a CVS version between 0.9.12 and 0.9.13. The
+result may be slightly different in your version.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{A walk through the example}
+\label{pyModules.walk}
+
+Lines 20-24 are the Cheetah-specific imports. Line 33 introduces our generated
+class, \code{x}, a subclass of \code{Template}. It's called x because the
+source file was x.tmpl.
+
+Lines 40-46 are the \code{.\_\_init\_\_} method called when the template is
+instantiated or used as a Webware servlet, or when the module is run as a
+standalone program. We can see it calling its superclass constructor and
+setting \code{.\_filePath} and \code{.\_fileMtime} to the filename and
+modification time (in Unix ticks) of the source .tmpl file.
+
+Lines 47-84 are the main method \code{.respond}, the one that fills the
+template. Normally you call it without arguments, but Webware calls it with a
+Webware \code{Transaction} object representing the current request. Lines
+57-59 set up the \code{trans} variable. If a real or dummy transaction is
+passed in, the method uses it. Otherwise (if the \code{trans} argument is
+\code{None}), the method creates a \code{DummyTransaction} instance.
+\code{dummyTrans} is a flag that just tells whether a dummy transaction is in
+effect; it'll be used at the end of the method.
+
+The other four \code{.respond} arguments aren't anything you'd ever want to
+pass in; they exist solely to speed up access to these frequently-used
+global functions. This is a standard Python trick described in question 4.7
+of the Python FAQ (\url{http://www.python.org/cgi-bin/faqw.py}).
+\code{VFS} and \code{VFN} are the functions that give your template the
+benefits of NameMapper lookup, such as the ability to use the searchList.
+
+Line 60 initializes the \code{write} variable. This important variable is
+discussed below.
+
+Lines 60-63 initialize a few more local variables. \code{SL} is the
+searchList. \code{filter} is the current output filter. \code{globalSetVars}
+are the variables that have been defined with \code{\#set global}.
+
+The comments at lines 65 and 78 delimit the start and end of the code that
+varies with each template. The code outside this region is identical in all
+template modules. That's not quite true -- \code{\#import} for instance
+generates additional \code{import} statements at the top of the module --
+but it's true enough for the most part.
+
+Lines 68-74 exist only if the template source was a named file rather than
+a string or file object. The stanza recompiles the template if the source
+file has changed. Lines 70-74 seem to be redundant with 75-83: both
+fill the template and send the output. The reason the first set of lines
+exists is because the second set may become invalid when the template is
+recompiled. (This is for \em{re}\ compilation only. The initial compilation
+happened in the \code{.\_\_init\_\_} method if the template wasn't
+precompiled.)
+
+Line 75 is the most interesting line in this module. It's a direct
+translation of what we put in the template definition, ``Hello, world!'' Here
+the content is a single string literal. \code{write} looks like an ordinary
+function call, but remember that line 60 made it an alias to
+\code{trans.response().write}, a method in the transaction. The next few
+chapters describe how the different placeholders and directives influence this
+portion of the generated class.
+
+Lines 80-83 finish the template filling. If \code{trans} is a real Webware
+transaction, \code{write} has already sent the output to Webware for handling,
+so we return \code{""}. If \code{trans} is a dummy transaction,
+\code{write} has been accumulating the output in a Python \code{StringIO}
+object rather than sending it anywhere, so we have to return it.
+
+Line 83 is the end of the \code{.respond} method.
+
+Line 87 makes code{.\_\_str\_\_} an alias for the main method, so that you
+can \code{print} it or apply \code{str} to it and it will fill the template.
+Line 88 gives the name of the main method, because sometimes it's not
+\code{.respond}.
+
+Lines 94-95 allow the module to be run directly as a script. Essentially,
+they process the command-line arguments and them make the template fill
+itself.
+
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End:
diff --git a/docs/devel_guide_src/template.tex b/docs/devel_guide_src/template.tex
new file mode 100644
index 0000000..0aeb76e
--- /dev/null
+++ b/docs/devel_guide_src/template.tex
@@ -0,0 +1,11 @@
+\section{Template}
+\label{template}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{}
+\label{}
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End: