From d9ce7916e309e2393d824e249f512d2629e5e181 Mon Sep 17 00:00:00 2001 From: "R. Tyler Ballance" Date: Mon, 16 Nov 2009 21:09:13 -0800 Subject: Revert "Delete the "old" docs directory to make way for fancy smancy sphinx" This reverts commit 5dc95cfcd015628665d3672e56d0551943b5db6b. --- docs/COPYING | 122 ++++ docs/OnePageTutorial.html | 546 +++++++++++++++++ docs/README | 15 + docs/TODO | 46 ++ docs/devel_guide_src/Makefile | 38 ++ docs/devel_guide_src/README | 9 + docs/devel_guide_src/bnf.tex | 7 + docs/devel_guide_src/cache.tex | 365 ++++++++++++ docs/devel_guide_src/comments.tex | 100 ++++ docs/devel_guide_src/compiler.tex | 8 + docs/devel_guide_src/design.tex | 102 ++++ docs/devel_guide_src/devel_guide.tex | 55 ++ docs/devel_guide_src/documenting.tex | 8 + docs/devel_guide_src/errorHandling.tex | 309 ++++++++++ docs/devel_guide_src/files.tex | 11 + docs/devel_guide_src/flowControl.tex | 360 ++++++++++++ docs/devel_guide_src/history.tex | 92 +++ docs/devel_guide_src/inheritanceEtc.tex | 232 ++++++++ docs/devel_guide_src/introduction.tex | 29 + docs/devel_guide_src/output.tex | 282 +++++++++ docs/devel_guide_src/parser.tex | 9 + docs/devel_guide_src/parserInstructions.tex | 61 ++ docs/devel_guide_src/patching.tex | 134 +++++ docs/devel_guide_src/placeholders.tex | 478 +++++++++++++++ docs/devel_guide_src/pyModules.tex | 246 ++++++++ docs/devel_guide_src/safeDelegation.tex | 44 ++ docs/devel_guide_src/template.tex | 11 + docs/howto_extras/comparisions.txt | 451 ++++++++++++++ docs/users_guide_2_src/01_introduction.txt | 291 +++++++++ docs/users_guide_2_src/02_glossary.txt | 66 +++ docs/users_guide_2_src/03_gettingStarted.txt | 262 +++++++++ docs/users_guide_2_src/04_howItWorks.txt | 369 ++++++++++++ docs/users_guide_2_src/05_language.txt | 651 +++++++++++++++++++++ .../05_placeholders_and_the_namemapper.txt | 0 docs/users_guide_2_src/06_comments.txt | 99 ++++ docs/users_guide_2_src/07_output.txt | 548 +++++++++++++++++ docs/users_guide_2_src/08_inheritanceEtc.txt | 564 ++++++++++++++++++ docs/users_guide_2_src/09_flowControl.txt | 414 +++++++++++++ docs/users_guide_2_src/10_errorHandling.txt | 145 +++++ docs/users_guide_2_src/11_parserInstructions.txt | 116 ++++ docs/users_guide_2_src/12_moduleFormatting.txt | 1 + .../13_tipsAndTroubleshooting.txt | 549 +++++++++++++++++ .../13a_precompiledTemplateModules.txt | 109 ++++ docs/users_guide_2_src/14_webware.txt | 582 ++++++++++++++++++ docs/users_guide_2_src/15_otherHtml.txt | 95 +++ docs/users_guide_2_src/16_nonHtml.txt | 17 + docs/users_guide_2_src/17_libraries.txt | 306 ++++++++++ docs/users_guide_2_src/18_editors.txt | 39 ++ docs/users_guide_2_src/A_links.txt | 112 ++++ docs/users_guide_2_src/B_examples.txt | 24 + docs/users_guide_2_src/C_comparisions.txt | 451 ++++++++++++++ docs/users_guide_2_src/E_license.txt | 32 + docs/users_guide_2_src/Makefile | 16 + docs/users_guide_2_src/default.css | 293 ++++++++++ docs/users_guide_2_src/eg_1.py | 11 + docs/users_guide_2_src/eg_2.py | 10 + docs/users_guide_2_src/eg_3.py | 18 + docs/users_guide_2_src/eg_4.py | 22 + docs/users_guide_2_src/eg_5.py | 25 + docs/users_guide_2_src/latex2rst.py | 45 ++ docs/users_guide_2_src/unused.txt | 67 +++ docs/users_guide_src/Makefile | 39 ++ docs/users_guide_src/README | 9 + docs/users_guide_src/comments.tex | 99 ++++ docs/users_guide_src/comparisons.tex | 451 ++++++++++++++ docs/users_guide_src/editors.tex | 39 ++ docs/users_guide_src/errorHandling.tex | 145 +++++ docs/users_guide_src/examples.tex | 24 + docs/users_guide_src/flowControl.tex | 414 +++++++++++++ docs/users_guide_src/gettingStarted.tex | 266 +++++++++ docs/users_guide_src/glossary.tex | 96 +++ docs/users_guide_src/howItWorks.tex | 420 +++++++++++++ docs/users_guide_src/inheritanceEtc.tex | 492 ++++++++++++++++ docs/users_guide_src/introduction.tex | 392 +++++++++++++ docs/users_guide_src/language.tex | 651 +++++++++++++++++++++ docs/users_guide_src/libraries.tex | 306 ++++++++++ docs/users_guide_src/links.tex | 112 ++++ docs/users_guide_src/moreverb.sty | 197 +++++++ docs/users_guide_src/nonHtml.tex | 17 + docs/users_guide_src/optikLicense.tex | 43 ++ docs/users_guide_src/otherHtml.tex | 95 +++ docs/users_guide_src/output.tex | 548 +++++++++++++++++ docs/users_guide_src/parserInstructions.tex | 116 ++++ docs/users_guide_src/tipsAndTricks.tex | 544 +++++++++++++++++ docs/users_guide_src/users_guide.tex | 54 ++ docs/users_guide_src/webware.tex | 575 ++++++++++++++++++ 86 files changed, 16663 insertions(+) create mode 100644 docs/COPYING create mode 100644 docs/OnePageTutorial.html create mode 100644 docs/README create mode 100644 docs/TODO create mode 100755 docs/devel_guide_src/Makefile create mode 100755 docs/devel_guide_src/README create mode 100755 docs/devel_guide_src/bnf.tex create mode 100755 docs/devel_guide_src/cache.tex create mode 100755 docs/devel_guide_src/comments.tex create mode 100755 docs/devel_guide_src/compiler.tex create mode 100755 docs/devel_guide_src/design.tex create mode 100755 docs/devel_guide_src/devel_guide.tex create mode 100755 docs/devel_guide_src/documenting.tex create mode 100755 docs/devel_guide_src/errorHandling.tex create mode 100755 docs/devel_guide_src/files.tex create mode 100755 docs/devel_guide_src/flowControl.tex create mode 100755 docs/devel_guide_src/history.tex create mode 100755 docs/devel_guide_src/inheritanceEtc.tex create mode 100755 docs/devel_guide_src/introduction.tex create mode 100755 docs/devel_guide_src/output.tex create mode 100755 docs/devel_guide_src/parser.tex create mode 100644 docs/devel_guide_src/parserInstructions.tex create mode 100755 docs/devel_guide_src/patching.tex create mode 100755 docs/devel_guide_src/placeholders.tex create mode 100755 docs/devel_guide_src/pyModules.tex create mode 100755 docs/devel_guide_src/safeDelegation.tex create mode 100755 docs/devel_guide_src/template.tex create mode 100755 docs/howto_extras/comparisions.txt create mode 100755 docs/users_guide_2_src/01_introduction.txt create mode 100644 docs/users_guide_2_src/02_glossary.txt create mode 100755 docs/users_guide_2_src/03_gettingStarted.txt create mode 100755 docs/users_guide_2_src/04_howItWorks.txt create mode 100755 docs/users_guide_2_src/05_language.txt create mode 100644 docs/users_guide_2_src/05_placeholders_and_the_namemapper.txt create mode 100755 docs/users_guide_2_src/06_comments.txt create mode 100755 docs/users_guide_2_src/07_output.txt create mode 100755 docs/users_guide_2_src/08_inheritanceEtc.txt create mode 100755 docs/users_guide_2_src/09_flowControl.txt create mode 100755 docs/users_guide_2_src/10_errorHandling.txt create mode 100755 docs/users_guide_2_src/11_parserInstructions.txt create mode 100644 docs/users_guide_2_src/12_moduleFormatting.txt create mode 100755 docs/users_guide_2_src/13_tipsAndTroubleshooting.txt create mode 100644 docs/users_guide_2_src/13a_precompiledTemplateModules.txt create mode 100755 docs/users_guide_2_src/14_webware.txt create mode 100755 docs/users_guide_2_src/15_otherHtml.txt create mode 100755 docs/users_guide_2_src/16_nonHtml.txt create mode 100755 docs/users_guide_2_src/17_libraries.txt create mode 100755 docs/users_guide_2_src/18_editors.txt create mode 100755 docs/users_guide_2_src/A_links.txt create mode 100755 docs/users_guide_2_src/B_examples.txt create mode 100755 docs/users_guide_2_src/C_comparisions.txt create mode 100644 docs/users_guide_2_src/E_license.txt create mode 100644 docs/users_guide_2_src/Makefile create mode 100644 docs/users_guide_2_src/default.css create mode 100644 docs/users_guide_2_src/eg_1.py create mode 100644 docs/users_guide_2_src/eg_2.py create mode 100644 docs/users_guide_2_src/eg_3.py create mode 100644 docs/users_guide_2_src/eg_4.py create mode 100644 docs/users_guide_2_src/eg_5.py create mode 100755 docs/users_guide_2_src/latex2rst.py create mode 100644 docs/users_guide_2_src/unused.txt create mode 100755 docs/users_guide_src/Makefile create mode 100755 docs/users_guide_src/README create mode 100755 docs/users_guide_src/comments.tex create mode 100755 docs/users_guide_src/comparisons.tex create mode 100755 docs/users_guide_src/editors.tex create mode 100755 docs/users_guide_src/errorHandling.tex create mode 100755 docs/users_guide_src/examples.tex create mode 100755 docs/users_guide_src/flowControl.tex create mode 100755 docs/users_guide_src/gettingStarted.tex create mode 100644 docs/users_guide_src/glossary.tex create mode 100755 docs/users_guide_src/howItWorks.tex create mode 100755 docs/users_guide_src/inheritanceEtc.tex create mode 100755 docs/users_guide_src/introduction.tex create mode 100755 docs/users_guide_src/language.tex create mode 100755 docs/users_guide_src/libraries.tex create mode 100755 docs/users_guide_src/links.tex create mode 100755 docs/users_guide_src/moreverb.sty create mode 100755 docs/users_guide_src/nonHtml.tex create mode 100755 docs/users_guide_src/optikLicense.tex create mode 100755 docs/users_guide_src/otherHtml.tex create mode 100755 docs/users_guide_src/output.tex create mode 100755 docs/users_guide_src/parserInstructions.tex create mode 100755 docs/users_guide_src/tipsAndTricks.tex create mode 100755 docs/users_guide_src/users_guide.tex create mode 100755 docs/users_guide_src/webware.tex diff --git a/docs/COPYING b/docs/COPYING new file mode 100644 index 0000000..ee79713 --- /dev/null +++ b/docs/COPYING @@ -0,0 +1,122 @@ +The Cheetah Users' Guide, Cheetah Developers' Guide and all other +documentation in this directory is released under the Open +Publication License (http://www.opencontent.org/openpub/). + +Regarding section VI of the Open Publication License, there are no +"license options" (=additional restrictions) on these works. + +A text version of the Open Publication License follows. It was +downloaded from http://www.opencontent.org/openpub/, converted to +text with 'links', and (minimally) reformatted by hand. + +################################################################### + Open Publication License + v1.0, 8 June 1999 + + I. REQUIREMENTS ON BOTH UNMODIFIED AND MODIFIED VERSIONS + + The Open Publication works may be reproduced and distributed in whole or in + part, in any medium physical or electronic, provided that the terms of this + license are adhered to, and that this license or an incorporation of it by + reference (with any options elected by the author(s) and/or publisher) is + displayed in the reproduction. + + Proper form for an incorporation by reference is as follows: + + Copyright (c) by . This material may be + distributed only subject to the terms and conditions set forth in the Open + Publication License, vX.Y or later (the latest version is presently + available at http://www.opencontent.org/openpub/). + + The reference must be immediately followed with any options elected by the + author(s) and/or publisher of the document (see section VI). + + Commercial redistribution of Open Publication-licensed material is permitted. + + Any publication in standard (paper) book form shall require the citation of + the original publisher and author. The publisher and author's names shall + appear on all outer surfaces of the book. On all outer surfaces of the book + the original publisher's name shall be as large as the title of the work and + cited as possessive with respect to the title. + + II. COPYRIGHT + + The copyright to each Open Publication is owned by its author(s) or designee. + + III. SCOPE OF LICENSE + + The following license terms apply to all Open Publication works, unless + otherwise explicitly stated in the document. + + Mere aggregation of Open Publication works or a portion of an Open + Publication work with other works or programs on the same media shall not + cause this license to apply to those other works. The aggregate work shall + contain a notice specifying the inclusion of the Open Publication material + and appropriate copyright notice. + + SEVERABILITY. If any part of this license is found to be unenforceable in any + jurisdiction, the remaining portions of the license remain in force. + + NO WARRANTY. Open Publication works are licensed and provided "as is" without + warranty of any kind, express or implied, including, but not limited to, the + implied warranties of merchantability and fitness for a particular purpose or + a warranty of non-infringement. + + IV. REQUIREMENTS ON MODIFIED WORKS + + All modified versions of documents covered by this license, including + translations, anthologies, compilations and partial documents, must meet the + following requirements: + + 1. The modified version must be labeled as such. + 2. The person making the modifications must be identified and the + modifications dated. + 3. Acknowledgement of the original author and publisher if applicable must + be retained according to normal academic citation practices. + 4. The location of the original unmodified document must be identified. + 5. The original author's (or authors') name(s) may not be used to assert or + imply endorsement of the resulting document without the original author's + (or authors') permission. + + V. GOOD-PRACTICE RECOMMENDATIONS + + In addition to the requirements of this license, it is requested from and + strongly recommended of redistributors that: + + 1. If you are distributing Open Publication works on hardcopy or CD-ROM, you + provide email notification to the authors of your intent to redistribute + at least thirty days before your manuscript or media freeze, to give the + authors time to provide updated documents. This notification should + describe modifications, if any, made to the document. + 2. All substantive modifications (including deletions) be either clearly + marked up in the document or else described in an attachment to the + document. + 3. Finally, while it is not mandatory under this license, it is considered + good form to offer a free copy of any hardcopy and CD-ROM expression of + an Open Publication-licensed work to its author(s). + + VI. LICENSE OPTIONS + + The author(s) and/or publisher of an Open Publication-licensed document may + elect certain options by appending language to the reference to or copy of + the license. These options are considered part of the license instance and + must be included with the license (or its incorporation by reference) in + derived works. + + A. To prohibit distribution of substantively modified versions without the + explicit permission of the author(s). "Substantive modification" is defined + as a change to the semantic content of the document, and excludes mere + changes in format or typographical corrections. + + To accomplish this, add the phrase `Distribution of substantively modified + versions of this document is prohibited without the explicit permission of + the copyright holder.' to the license reference or copy. + + B. To prohibit any publication of this work or derivative works in whole or + in part in standard (paper) book form for commercial purposes is prohibited + unless prior permission is obtained from the copyright holder. + + To accomplish this, add the phrase 'Distribution of the work or derivative of + the work in any standard (paper) book form is prohibited unless prior + permission is obtained from the copyright holder.' to the license reference + or copy. diff --git a/docs/OnePageTutorial.html b/docs/OnePageTutorial.html new file mode 100644 index 0000000..eaa9acc --- /dev/null +++ b/docs/OnePageTutorial.html @@ -0,0 +1,546 @@ + + + + + +Cheetah Template One-Page Tutorial + + + + + + + +

Cheetah Template One-Page Tutorial
+By Chuck Esterbrook, now maintained by Mike Orr
+Updated May 17, 2002

+ +

Substitution

+ +

The most commonly used templating feature is substitution: + +

+My name is $name
+
+ +

You can use dotted notation to traverse objects. For example: + +

+$author.person.primaryEmail
+
+ +

When a variable name is flush against other text you must use curly braces to separate it: + +

+Jim is a ${vice}maniac.
+
+ +

However, the template language is savvy enough to handle sentence endings and variables: + +

+My name is $name.
+$foo$bar
+
+ + +

#if (conditional)

+ +

The #if statement can be used to detect if a value is blank/undefined/NULL. The most common use for an #if statement is showing a different form of content if something is undefined. + +

+#if $keywords
+    $keywords
+#else
+    There are no keywords!
+#end if
+
+ +

The #else part is optional: + +

+#if $keywords
+    <span class=keywords>$keywords</span>
+#end if
+
+ + +

#for (looping)

+ +

The #for statement is used to loop through any kind of list. + +

+#for $author in $authors
+    $author.person.fullName
+#end for
+
+ + +

Combining statements

+ +

You can combine statements. For example, + +

Template.html: +

+$name
+
+<p> $content
+
+#include "authors.html"
+
+ +Authors.html: +
+#if $authors
+    <table class=Author>
+    #for $author in $authors
+        <tr class=Author> <td class=Author>
+            $author
+        </td> </tr>
+    #end for
+    </table>
+#end if
+
+ + +

Examples

+ +

Here is an example that lists several names and puts commas between them. Note the use of #slurp to slurp up extra whitespace that might interfere. + +

+#set sep = ''
+#for $author in $authors
+${sep}${author.person}#slurp
+#set sep = ', '
+#end for
+
+ + + + diff --git a/docs/README b/docs/README new file mode 100644 index 0000000..3f3fcd7 --- /dev/null +++ b/docs/README @@ -0,0 +1,15 @@ +users_guide_src/ : + Users' Guide for Cheetah 1.0. Will be deleted when users Guide 2 is + finished. + +users_guide_2_src/ : + Users' Guide and Cookbook for Cheetah 2.0. HTML version has both parts + in one; PDF version has them as two documents. This section is under + construction. + +devel_guide_src/ : + Developers' Guide for Cheetah 1.0. Will be deleted when Users' Guide 2 + is finished. + +howto_extras/ : + Extra content for future HOWTOs and FAQs. May or may not be up to date. diff --git a/docs/TODO b/docs/TODO new file mode 100644 index 0000000..8c22561 --- /dev/null +++ b/docs/TODO @@ -0,0 +1,46 @@ +Cheetah Documentation TODO +-------------------------- + +Cheetah FAQ +=============================================================================== +A place for specific questions & answers for troubleshooting. Some questions +may duplicate material in the Users' Guide, but some paragraphs in the UG will +be moved to the FAQ. +- Why am I getting a NotFound error? I put my variable in the searchList! +- Why is my template output empty? +- Why are my $property, $file, ... placeholders misbehaving? + +Users' Guide: +=============================================================================== +- 200+ e-mails in MO's mailbox regarding possible doc updates. +- more examples in the Webware section (EL) +- more examples/advice all over the Users' Guide about recommended/ + non-recommended strategies (MO) + +Developers' Guide: +=============================================================================== +- Finish. (MO) + +Quick Reference Guide: +=============================================================================== +Cheat sheet on Cheetah syntax and usage. (MO but not soon) + +Beginners' Guide: +=============================================================================== +Written for somebody who has to maintain templates but +doesn't know Python. Looking for a writer, somebody who trains such +maintainers and knows what their needs are. To get the correct LaTeX +structure, copy users_guide.tex and one of its chapters, and modify as +necessary. + + +HOWTOs: +======= +Somebody offered to write some HOWTOs on specialized topics. Who was it? + +BNF: +==== +- write a formalized grammar for Cheetah in BNF. MO partly did in +a Developer's Guide appendix. Essentially, the directives still need +to be done, and a proofreading of the rest. Move to separate text file and +find somebody to finish it. diff --git a/docs/devel_guide_src/Makefile b/docs/devel_guide_src/Makefile new file mode 100755 index 0000000..9e5da96 --- /dev/null +++ b/docs/devel_guide_src/Makefile @@ -0,0 +1,38 @@ +# You must change PYTHONSRC to the path of your Python source distributon. +PYTHONSRC=/home/tavis/tmp/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 ../ + +ps: + $(MKHOWTO) --ps $(MAIN_TEX_FILE) + mv $(DOCNAME).ps ../ +html: + -rm -rf $(DOCNAME) + $(MKHOWTO) --html --split 1 --iconserver . $(MAIN_TEX_FILE) + -rm -rf ../$(DOCNAME)_html + mv $(DOCNAME) ../$(DOCNAME)_html + +htmlMultiPage: + -rm -rf $(DOCNAME) + $(MKHOWTO) --html --iconserver . $(MAIN_TEX_FILE) + -rm -rf ../$(DOCNAME)_html_multipage + mv $(DOCNAME) ../$(DOCNAME)_html_multipage + +text: + $(MKHOWTO) --text $(MAIN_TEX_FILE) + mv $(DOCNAME).txt ../ + +clean: + -rm -rf $(DOCNAME) + -rm -f *.aux *.l2h *~ *.log *.ind *.bkm *.how *.toc + -rm -rf ../html + diff --git a/docs/devel_guide_src/README b/docs/devel_guide_src/README new file mode 100755 index 0000000..3b45564 --- /dev/null +++ b/docs/devel_guide_src/README @@ -0,0 +1,9 @@ +To build the Cheetah documentation, you need the 'mkhowto' program from +the Python source distribution. So: + +1) Get the Python source distribution and unpack it in some directory. + +2) Edit the Cheetah documentation's Makefile and change PYTHONSRC to +point to the top-level directory of your Python source distribution. + +3) Run 'make'. diff --git a/docs/devel_guide_src/bnf.tex b/docs/devel_guide_src/bnf.tex new file mode 100755 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/cache.tex b/docs/devel_guide_src/cache.tex new file mode 100755 index 0000000..043b8cf --- /dev/null +++ b/docs/devel_guide_src/cache.tex @@ -0,0 +1,365 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Caching placeholders and \#cache} +\label{cache} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Dynamic placeholder -- no cache} +\label{cache.dynamic} + +The template: +\begin{verbatim} +Dynamic variable: $voom +\end{verbatim} + +The command line and the output: +\begin{verbatim} +% voom='Voom!' python x.py --env +Dynamic variable: Voom! +\end{verbatim} + +The generated code: +\begin{verbatim} +write('Dynamic variable: ') +write(filter(VFS(SL,"voom",1))) # generated from '$voom' at line 1, col 20. +write('\n') +\end{verbatim} + +Just what we expected, like any other dynamic placeholder. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Static placeholder} +\label{cache.static} + +The template: +\begin{verbatim} +Cached variable: $*voom +\end{verbatim} + +The command line and output: +\begin{verbatim} +% voom='Voom!' python x.py --env +Cached variable: Voom! +\end{verbatim} + +The generated code, with line numbers: +\begin{verbatim} + 1 write('Cached variable: ') + 2 ## START CACHE REGION: at line, col (1, 19) in the source. + 3 RECACHE = True + 4 if not self._cacheData.has_key('19760169'): + 5 pass + 6 else: + 7 RECACHE = False + 8 if RECACHE: + 9 orig_trans = trans +10 trans = cacheCollector = DummyTransaction() +11 write = cacheCollector.response().write +12 write(filter(VFS(SL,"voom",1))) # generated from '$*voom' at line 1, + # col 19. +13 trans = orig_trans +14 write = trans.response().write +15 self._cacheData['19760169'] = cacheCollector.response().getvalue() +16 del cacheCollector +17 write(self._cacheData['19760169']) +18 ## END CACHE REGION + +19 write('\n') +\end{verbatim} + +That one little star generated a whole lotta code. First, instead of an +ordinary \code{VFS} lookup (searchList) lookup, it converted the +placeholder to a lookup in the \code{.\_cacheData} dictionary. Cheetah also +generated a unique key (\code{'19760169'}) for our cached item -- this is its +cache ID. + +Second, Cheetah put a pair of if-blocks before the \code{write}. The first +(lines 3-7) determine whether the cache value is missing or out of date, and +sets local variable \code{RECACHE} true or false. +This stanza may look unnecessarily verbose -- lines 3-7 could be eliminated if +line 8 was changed to +\begin{verbatim} +if not self._cacheData.has_key('19760169'): +\end{verbatim} +-- but this model is expandable for some of the cache features we'll see below. + +The second if-block, lines 8-16, do the cache updating if necessary. +Clearly, the programmer is trying to stick as close to normal (dynamic) +workflow as possible. Remember that \code{write}, even though it looks like a +local function, is actually a method of a file-like object. So we create a +temporary file-like object to divert the \code{write} object into, then read +the result and stuff it into the cache. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Timed-refresh placeholder} +\label{cache.timed} + +The template: +\begin{verbatim} +Timed cache: $*.5m*voom +\end{verbatim} + +The command line and the output: +\begin{verbatim} +% voom='Voom!' python x.py --env +Timed cache: Voom! +\end{verbatim} + +The generated method's docstring: +\begin{verbatim} +""" +This is the main method generated by Cheetah +This cache will be refreshed every 30.0 seconds. +""" +\end{verbatim} + +The generated code: +\begin{verbatim} + 1 write('Timed cache: ') + 2 ## START CACHE REGION: at line, col (1, 15) in the source. + 3 RECACHE = True + 4 if not self._cacheData.has_key('55048032'): + 5 self.__cache55048032__refreshTime = currentTime() + 30.0 + 6 elif currentTime() > self.__cache55048032__refreshTime: + 7 self.__cache55048032__refreshTime = currentTime() + 30.0 + 8 else: + 9 RECACHE = False +10 if RECACHE: +11 orig_trans = trans +12 trans = cacheCollector = DummyTransaction() +13 write = cacheCollector.response().write +14 write(filter(VFS(SL,"voom",1))) # generated from '$*.5m*voom' at + # line 1, col 15. +15 trans = orig_trans +16 write = trans.response().write +17 self._cacheData['55048032'] = cacheCollector.response().getvalue() +18 del cacheCollector +19 write(self._cacheData['55048032']) +20 ## END CACHE REGION + +21 write('\n') +\end{verbatim} + +This code is identical to the static cache example except for the docstring +and the first if-block. (OK, so the cache ID is different and the comment on +line 14 is different too. Big deal.) + +Each timed-refresh cache item has a corrsponding private attribute +\code{.\_\_cache\#\#\#\#\#\#\#\#\_\_refreshTime} giving the refresh time +in ticks (=seconds since January 1, 1970). The first if-block (lines 3-9) +checks whether the cache value is missing or its update time has passed, and if +so, sets \code{RECACHE} to true and also schedules another refresh at the next +interval. + +The method docstring reminds the user how often the cache will be refreshed. +This information is unfortunately not as robust as it could be. Each +timed-cache placeholder blindly generates a line in the docstring. If all +refreshes are at the same interval, there will be multiple identical lines +in the docstring. If the refreshes are at different intervals, you get a +situation like this: +\begin{verbatim} +""" +This is the main method generated by Cheetah +This cache will be refreshed every 30.0 seconds. +This cache will be refreshed every 60.0 seconds. +This cache will be refreshed every 120.0 seconds. +""" +\end{verbatim} +The docstring tells only that ``something'' will be refreshed every 60.0 +seconds, but doesn't reveal {\em which} placeholder that is. Only if you +know the relative order of the placeholders in the template can you figure +that out. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Timed-refresh placeholder with braces} +\label{cache.timed.braces} + +This example is the same but with the long placeholder syntax. It's here +because it's a Cheetah FAQ whether to put the cache interval inside or outside +the braces. (It's also here so I can look it up because I frequently forget.) +The answer is: outside. The braces go around only the placeholder name (and +perhaps some output-filter arguments.) + +The template: +\begin{verbatim} +Timed with {}: $*.5m*{voom} +\end{verbatim} + +The output: +\begin{verbatim} +Timed with {}: Voom! +\end{verbatim} + +The generated code differs only in the comment. Inside the cache-refresh +if-block: +\begin{verbatim} +write(filter(VFS(SL,"voom",1))) # generated from '$*.5m*{voom}' at line 1, + #col 17. +\end{verbatim} + +If you try to do it this way: +\begin{verbatim} +Timed with {}: ${*.5m*voom} ## Wrong! +\end{verbatim} +you get: +\begin{verbatim} +Timed with {}: ${*.5m*voom} +\end{verbatim} +\verb+${+ is not a valid placeholder, so it gets treated as ordinary text. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#cache} +\label{cache.directive} + +The template: +\begin{verbatim} +#cache +This is a cached region. $voom +#end cache +\end{verbatim} + +The output: +\begin{verbatim} +This is a cached region. Voom! +\end{verbatim} + +The generated code: +\begin{verbatim} + 1 ## START CACHE REGION: at line, col (1, 1) in the source. + 2 RECACHE = True + 3 if not self._cacheData.has_key('23711421'): + 4 pass + 5 else: + 6 RECACHE = False + 7 if RECACHE: + 8 orig_trans = trans + 9 trans = cacheCollector = DummyTransaction() +10 write = cacheCollector.response().write +11 write('This is a cached region. ') +12 write(filter(VFS(SL,"voom",1))) # generated from '$voom' at line 2, + # col 27. +13 write('\n') +14 trans = orig_trans +15 write = trans.response().write +16 self._cacheData['23711421'] = cacheCollector.response().getvalue() +17 del cacheCollector +18 write(self._cacheData['23711421']) +19 ## END CACHE REGION +\end{verbatim} + +This is the same as the \code{\$*voom} example, except that the plain text +around the placeholder is inside the second if-block. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#cache with timer and id} +\label{cache.directive.timer} + +The template: +\begin{verbatim} +#cache timer='.5m', id='cache1' +This is a cached region. $voom +#end cache +\end{verbatim} + +The output: +\begin{verbatim} +This is a cached region. Voom! +\end{verbatim} + +The generated code is the same as the previous example except the first +if-block: +\begin{verbatim} +RECACHE = True +if not self._cacheData.has_key('13925129'): + self._cacheIndex['cache1'] = '13925129' + self.__cache13925129__refreshTime = currentTime() + 30.0 +elif currentTime() > self.__cache13925129__refreshTime: + self.__cache13925129__refreshTime = currentTime() + 30.0 +else: + RECACHE = False +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#cache with test: expression and method conditions} +\label{cache.directive.test} + +The template: +\begin{verbatim} +#cache test=$isDBUpdated +This is a cached region. $voom +#end cache +\end{verbatim} + +(Analysis postponed: bug in Cheetah produces invalid Python.) + +%The output: +%\begin{verbatim} +%\end{verbatim} + +%The generated code: +%\begin{verbatim} +%\end{verbatim} + + +The template: +\begin{verbatim} +#cache id='cache1', test=($isDBUpdated or $someOtherCondition) +This is a cached region. $voom +#end cache +\end{verbatim} + +The output: +\begin{verbatim} +This is a cached region. Voom! +\end{verbatim} + +The first if-block in the generated code: +\begin{verbatim} +RECACHE = True +if not self._cacheData.has_key('36798144'): + self._cacheIndex['cache1'] = '36798144' +elif (VFS(SL,"isDBUpdated",1) or VFS(SL,"someOtherCondition",1)): + RECACHE = True +else: + RECACHE = False +\end{verbatim} +The second if-block is the same as in the previous example. If you leave +out the \code{()} around the test expression, the result is the same, although +it may be harder for the template maintainer to read. + +You can even combine arguments, although this is of questionable value. + +The template: +\begin{verbatim} +#cache id='cache1', timer='30m', test=$isDBUpdated or $someOtherCondition +This is a cached region. $voom +#end cache +\end{verbatim} + +The output: +\begin{verbatim} +This is a cached region. Voom! +\end{verbatim} + +The first if-block: +\begin{verbatim} +RECACHE = True +if not self._cacheData.has_key('88939345'): + self._cacheIndex['cache1'] = '88939345' + self.__cache88939345__refreshTime = currentTime() + 1800.0 +elif currentTime() > self.__cache88939345__refreshTime: + self.__cache88939345__refreshTime = currentTime() + 1800.0 +elif VFS(SL,"isDBUpdated",1) or VFS(SL,"someOtherCondition",1): + RECACHE = True +else: + RECACHE = False +\end{verbatim} + +We are planning to add a \code{'varyBy'} keyword argument in the future that +will allow separate cache instances to be created for a variety of conditions, +such as different query string parameters or browser types. This is inspired by +ASP.net's varyByParam and varyByBrowser output caching keywords. Since this is +not implemented yet, I cannot provide examples here. + +% 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 100755 index 0000000..4a7bdbd --- /dev/null +++ b/docs/devel_guide_src/comments.tex @@ -0,0 +1,100 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Directives: Comments} +\label{comments} + +The template: + +\begin{verbatim} +Text before the comment. +## The comment. +Text after the comment. +#* A multi-line comment spanning several lines. + It spans several lines, too. +*# +Text after the multi-line comment. +\end{verbatim} + +The output: + +\begin{verbatim} +Text before the comment. +Text after the comment. + +Text after the multi-line comment. + +\end{verbatim} + +The generated code: + +\begin{verbatim} + write('Text before the comment.\n') + # The comment. + write('Text after the comment.\n') + # A multi-line comment spanning several lines. + # It spans several lines, too. + write('\nText after the multi-line comment.\n') +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Docstring and header comments} +\label{comments.docstring} + +The template: +\begin{verbatim} +##doc: .respond() method comment. +##doc-method: Another .respond() method comment. +##doc-class: A class comment. +##doc-module: A module comment. +##header: A header comment. +\end{verbatim} + +The output: +\begin{verbatim} + +\end{verbatim} + +The beginning of the generated \code{.respond} method: +\begin{verbatim} +def respond(self, + trans=None, + dummyTrans=False, + VFS=valueFromSearchList, + VFN=valueForName, + getmtime=getmtime, + currentTime=time.time): + + """ + This is the main method generated by Cheetah + .respond() method comment. + Another .respond() method comment. + """ +\end{verbatim} + +The class docstring: +\begin{verbatim} +""" +A class comment. + +Autogenerated by CHEETAH: The Python-Powered Template Engine +""" +\end{verbatim} + +The top of the module: +\begin{verbatim} +#!/usr/bin/env python +# A header comment. + +"""A module comment. + +Autogenerated by CHEETAH: The Python-Powered Template Engine + CHEETAH VERSION: 0.9.13a1 + Generation time: Fri Apr 26 22:39:23 2002 + Source file: x.tmpl + Source file last modified: Fri Apr 26 22:36:23 2002 +""" +\end{verbatim} + + +% 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 100755 index 0000000..e27aa94 --- /dev/null +++ b/docs/devel_guide_src/compiler.tex @@ -0,0 +1,8 @@ +\section{The compiler} +\label{compiler} + +How templates are compiled: a walk through Compiler.py. + +% 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 100755 index 0000000..3008a63 --- /dev/null +++ b/docs/devel_guide_src/design.tex @@ -0,0 +1,102 @@ +\section{Design Decisions and Tradeoffs} +\label{design} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Delimiters} +\label{design.Delimiters} + +One of the first decisions we encountered was which delimiter syntax to use. +We decided to follow Velocity's \code{\$placeholder} and \code{\#directive} +syntax because the former is widely used in other languages for the same +purpose, and the latter stands out in an HTML or text document. We also +implemented the \verb+${longPlaceholder}+ syntax like the shells for cases +where Cheetah or you might be confused where a placeholder ends. Tavis went +ahead and made \verb+${longPlaceholder}+ and \verb+$[longPlaceholder]+ +interchangeable with it since it was trivial to implement. Finally, +the \code{\#compiler} directive allows you to change the delimiters if you +don't like them or if they conflict with the text in your document. +(Obviously, if your document contains a Perl program listing, you don't +necessarily want to backslash each and every \code{\$} and \code{\#}, do you?) + +The choice of comment delimiters was more arbitrary. \code{\#\#} and +\code{\#* \ldots *\#} doesn't match any language, but it's reminiscent of +Python and C while also being consistent with our ``\code{\#} is for +directives'' convention. + +We specifically chose {\em not} to use pseudo HTML tags for placeholders and +directives, as described more thoroughly in the Cheetah Users' Guide +introduction. Pseudo HTML tags may be easier to see in a visual editor +(supposedly), but in text editors they're hard to distinguish from ``real'' +HTML tags unless you look closely, and they're many more keystrokes to type. +Also, if you make a mistake, the tag will show up as literal text in the +rendered HTML page where it will be easy to notice and eradicate, rather than +disappearing as bogus HTML tags do in browsers. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Late binding} +\label{design.lateBinding} + +One of Cheetah's unique features is the name mapper, which lets you write +\code{\$a.b} without worrying much about the type of \code{a} or \code{b}. +Prior to version 0.9.7, Cheetah did the entire NameMapper lookup at runtime. +This provided maximum flexibility at the expense of speed. Doing a NameMapper +lookup is intrinsically more expensive than an ordinary Python expression +because Cheetah has to decide what type of container \code{a} is, whether the +the value is a function (autocall it), issue the appropriate Python incantation +to look up \code{b} in it, autocall again if necessary, and then convert the +result to a string. + +To maximize run-time (filling-time) performance, Cheetah 0.9.7 pushed much of +this work back into the compiler. The compiler looked up \code{a} in the +searchList at compile time, noted its type, and generated an eval'able Python +expression based on that. + +This approach had two significant drawbacks. What if \code{a} later changes +type before a template filling? Answer: unpredictable exceptions occur. What +if \code{a} does not exist in the searchList at compile time? Answer: the +template can't compile. + +To prevent these catastrophes, users were required to prepopulate the +searchList before instantiating the template instance, and then not to change +\code{a}'s type. Static typing is repugnant in a dynamic language like Python, +and having to prepopulate the searchList made certain usages impossible. For +example, you couldn't instantiate the template object without a searchList and +then set \code{self} attributes to specify the values. + +After significant user complaints about the fragility of this system, Tavis +rewrote placeholder handling, and in version 0.9.8a3 (August 2001), Tavis +moved the name mapper lookup back into runtime. Performance wasn't crippled +because he discovered that writing a C version of the name mapper was easier +than anticipated, and the C version completed the lookup quickly. Now Cheetah +had ``late binding'', meaning the compiler does not look up \code{a} or care +whether it exists. This allows users to create \code{a} or change its type +anytime before a template filling. + +The lesson we learned is that it's better to decide what you want and then +figure out how to do it, rather than assuming that certain goals are +unattainable due to performance considerations. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Caching framework} +\label{design.cache} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Webware compatibility and the transaction framework} +\label{design.webware} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Single inheritance} +\label{design.singleInheritance} + + + + + +% 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 new file mode 100755 index 0000000..1e795c4 --- /dev/null +++ b/docs/devel_guide_src/devel_guide.tex @@ -0,0 +1,55 @@ +\documentclass{howto} +\usepackage{moreverb} %% Verbatim Code Listings + +\title{Cheetah Developers' Guide} +\release{0.9.15a1} + +\author{Mike Orr with assistance from Tavis Rudd} +\authoraddress{\email{iron@mso.oz.net}} + +\begin{document} +\maketitle + + +\tableofcontents + +\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/} } + + + %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + \include{introduction} + + %% How the directives affect the .py template module. + \include{pyModules} + \include{placeholders} + \include{cache} + \include{comments} + \include{output} + \include{inheritanceEtc} + \include{flowControl} + \include{errorHandling} + \include{parserInstructions} + + %% A walk through the Cheetah source. + \include{files} + \include{template} + \include{parser} + \include{compiler} + + %% Other development issues and howtos. + \include{history} + \include{design} + \include{patching} + \include{documenting} + + %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + \appendix + \include{bnf} + \include{safeDelegation} +\end{document} + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/devel_guide_src/documenting.tex b/docs/devel_guide_src/documenting.tex new file mode 100755 index 0000000..51d5153 --- /dev/null +++ b/docs/devel_guide_src/documenting.tex @@ -0,0 +1,8 @@ +\section{Documenting Cheetah} +\label{documenting} + +How to build the documentation. Why LaTeX, a minimum LaTeX reference, etc. + +% 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 100755 index 0000000..02079d5 --- /dev/null +++ b/docs/devel_guide_src/errorHandling.tex @@ -0,0 +1,309 @@ +\section{Directives: Error Handling} +\label{errorHandling} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#try and \#raise} +\label{errorHandling.try} + +The template: +\begin{verbatim} +#import traceback +#try +#raise RuntimeError +#except RuntimeError +A runtime error occurred. +#end try + +#try +#raise RuntimeError("Hahaha!") +#except RuntimeError +#echo $sys.exc_info()[1] +#end try + +#try +#echo 1/0 +#except ZeroDivisionError +You can't divide by zero, idiot! +#end try +\end{verbatim} + +The output: +\begin{verbatim} +A runtime error occurred. + +Hahaha! + +You can't divide by zero, idiot! +\end{verbatim} + +The generated code: +\begin{verbatim} +try: + raise RuntimeError +except RuntimeError: + write('A runtime error occurred.\n') +write('\n') +try: + raise RuntimeError("Hahaha!") +except RuntimeError: + write(filter(VFN(sys,"exc_info",0)()[1])) + write('\n') +write('\n') +try: + write(filter(1/0)) + write('\n') +except ZeroDivisionError: + write("You can't divide by zero, idiot!\n") +\end{verbatim} + +\code{\#finally} works just like in Python. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#assert} +\label{errorHandling.assert} + +The template: +\begin{verbatim} +#assert False, "You lose, buster!" +\end{verbatim} + +The output: +\begin{verbatim} +Traceback (most recent call last): + File "x.py", line 117, in ? + x().runAsMainProgram() + File "/local/opt/Python/lib/python2.2/site-packages/Webware/Cheetah/ +Template.py", line 331, in runAsMainProgram + CmdLineIface(templateObj=self).run() + File "/local/opt/Python/lib/python2.2/site-packages/Webware/Cheetah/ +TemplateCmdLineIface.py", line 59, in run + print self._template + File "x.py", line 91, in respond + assert False, "You lose, buster!" +AssertionError: You lose, buster! +\end{verbatim} + +The generated code: +\begin{verbatim} +assert False, "You lose, buster!" +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#errorCatcher} +\label{errorHandling.errorCatcher} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{No error catcher} +\label{errorHandling.errorCatcher.no} + +The template: +\begin{verbatim} +$noValue +\end{verbatim} + +The output: +\begin{verbatim} + +Traceback (most recent call last): + File "x.py", line 118, in ? + x().runAsMainProgram() + File "/local/opt/Python/lib/python2.2/site-packages/Webware/Cheetah/ +Template.py", line 331, in runAsMainProgram + CmdLineIface(templateObj=self).run() + File "/local/opt/Python/lib/python2.2/site-packages/Webware/Cheetah/ +TemplateCmdLineIface.py", line 59, in run + print self._template + File "x.py", line 91, in respond + write(filter(VFS(SL,"noValue",1))) # generated from '$noValue' at line +1, col 1. +NameMapper.NotFound: noValue +\end{verbatim} + +The generated code: +\begin{verbatim} +write(filter(VFS(SL,"noValue",1))) # generated from '$noValue' at line 1, + # col 1. +write('\n') +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Echo and BigEcho} +\label{errorHandling.errorCatcher.echo} + +The template: +\begin{verbatim} +#errorCatcher Echo +$noValue +#errorCatcher BigEcho +$noValue +\end{verbatim} + +The output: +\begin{verbatim} +$noValue +===============<$noValue could not be found>=============== +\end{verbatim} + +The generated code: +\begin{verbatim} +if self._errorCatchers.has_key("Echo"): + self._errorCatcher = self._errorCatchers["Echo"] +else: + self._errorCatcher = self._errorCatchers["Echo"] = ErrorCatchers.Echo(self) +write(filter(self.__errorCatcher1(localsDict=locals()))) + # generated from '$noValue' at line 2, col 1. +write('\n') +if self._errorCatchers.has_key("BigEcho"): + self._errorCatcher = self._errorCatchers["BigEcho"] +else: + self._errorCatcher = self._errorCatchers["BigEcho"] = \ + ErrorCatchers.BigEcho(self) +write(filter(self.__errorCatcher1(localsDict=locals()))) + # generated from '$noValue' at line 4, col 1. +write('\n') +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{ListErrors} +\label{errorHandling.errorCatcher.listErrors} + +The template: +\begin{verbatim} +#import pprint +#errorCatcher ListErrors +$noValue +$anotherMissingValue.really +$pprint.pformat($errorCatcher.listErrors) +## This is really self.errorCatcher().listErrors() +\end{verbatim} + +The output: +\begin{verbatim} +$noValue +$anotherMissingValue.really +[{'code': 'VFS(SL,"noValue",1)', + 'exc_val': , + 'lineCol': (3, 1), + 'rawCode': '$noValue', + 'time': 'Wed May 15 00:38:23 2002'}, + {'code': 'VFS(SL,"anotherMissingValue.really",1)', + 'exc_val': , + 'lineCol': (4, 1), + 'rawCode': '$anotherMissingValue.really', + 'time': 'Wed May 15 00:38:23 2002'}] +\end{verbatim} + +The generated import: +\begin{verbatim} +import pprint +\end{verbatim} + +Then in the generated class, we have our familiar \code{.respond} method +and several new methods: +\begin{verbatim} +def __errorCatcher1(self, localsDict={}): + """ + Generated from $noValue at line, col (3, 1). + """ + + try: + return eval('''VFS(SL,"noValue",1)''', globals(), localsDict) + except self._errorCatcher.exceptions(), e: + return self._errorCatcher.warn(exc_val=e, code= 'VFS(SL,"noValue",1)' , + rawCode= '$noValue' , lineCol=(3, 1)) + +def __errorCatcher2(self, localsDict={}): + """ + Generated from $anotherMissingValue.really at line, col (4, 1). + """ + + try: + return eval('''VFS(SL,"anotherMissingValue.really",1)''', globals(), + localsDict) + except self._errorCatcher.exceptions(), e: + return self._errorCatcher.warn(exc_val=e, + code= 'VFS(SL,"anotherMissingValue.really",1)' , + rawCode= '$anotherMissingValue.really' , lineCol=(4, 1)) + +def __errorCatcher3(self, localsDict={}): + """ + Generated from $pprint.pformat($errorCatcher.listErrors) at line, col + (5, 1). + """ + + try: + return eval('''VFN(pprint,"pformat",0)(VFS(SL, + "errorCatcher.listErrors",1))''', globals(), localsDict) + except self._errorCatcher.exceptions(), e: + return self._errorCatcher.warn(exc_val=e, code= + 'VFN(pprint,"pformat",0)(VFS(SL,"errorCatcher.listErrors",1))' , + rawCode= '$pprint.pformat($errorCatcher.listErrors)' , + lineCol=(5, 1)) +\end{verbatim} +\begin{verbatim} +def respond(self, + trans=None, + dummyTrans=False, + VFS=valueFromSearchList, + VFN=valueForName, + getmtime=getmtime, + currentTime=time.time): + + + """ + This is the main method generated by Cheetah + """ + + if not trans: + trans = DummyTransaction() + dummyTrans = True + write = trans.response().write + SL = self._searchList + filter = self._currentFilter + globalSetVars = self._globalSetVars + + ######################################## + ## START - generated method body + + if exists(self._filePath) and getmtime(self._filePath) > self._fileMtime: + self.compile(file=self._filePath) + write(getattr(self, self._mainCheetahMethod_for_x)(trans=trans)) + if dummyTrans: + return trans.response().getvalue() + else: + return "" + if self._errorCatchers.has_key("ListErrors"): + self._errorCatcher = self._errorCatchers["ListErrors"] + else: + self._errorCatcher = self._errorCatchers["ListErrors"] = \ + ErrorCatchers.ListErrors(self) + write(filter(self.__errorCatcher1(localsDict=locals()))) + # generated from '$noValue' at line 3, col 1. + write('\n') + write(filter(self.__errorCatcher2(localsDict=locals()))) + # generated from '$anotherMissingValue.really' at line 4, col 1. + write('\n') + write(filter(self.__errorCatcher3(localsDict=locals()))) + # generated from '$pprint.pformat($errorCatcher.listErrors)' at line + # 5, col 1. + write('\n') + # This is really self.errorCatcher().listErrors() + + ######################################## + ## END - generated method body + + if dummyTrans: + return trans.response().getvalue() + else: + return "" +\end{verbatim} + +So whenever an error catcher is active, each placeholder gets wrapped in its +own method. No wonder error catchers slow down the system! + + +% 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 100755 index 0000000..0ce45a9 --- /dev/null +++ b/docs/devel_guide_src/files.tex @@ -0,0 +1,11 @@ +\section{Files} +\label{files} + +This chapter will be an overview of the files in the Cheetah package, +and how they interrelate in compiling and filling a template. We'll +also look at files in the Cheetah tarball that don't get copied into +the package. + +% 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 100755 index 0000000..936df67 --- /dev/null +++ b/docs/devel_guide_src/flowControl.tex @@ -0,0 +1,360 @@ +\section{Directives: Flow Control} +\label{flowControl} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#for} +\label{flowControl.for} + +The template: +\begin{verbatim} +#for $i in $range(10) +$i #slurp +#end for +\end{verbatim} + +The output: +\begin{verbatim} +0 1 2 3 4 5 6 7 8 9 +\end{verbatim} + +The generated code: +\begin{verbatim} +for i in range(10): + write(filter(i)) # generated from '$i' at line 2, col 1. + write(' ') +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#repeat} +\label{flowControl.repeat} + +The template: +\begin{verbatim} +#repeat 3 +My bonnie lies over the ocean +#end repeat +O, bring back my bonnie to me! +\end{verbatim} + +The output: +\begin{verbatim} +My bonnie lies over the ocean +My bonnie lies over the ocean +My bonnie lies over the ocean +O, bring back my bonnie to me! +\end{verbatim} +(OK, so the second line should be ``sea'' instead of ``ocean''.) + +The generated code: +\begin{verbatim} +for __i0 in range(3): + write('My bonnie lies over the ocean\n') +write('O, bring back my bonnie to me!\n') +\end{verbatim} + +Note that a new local variable of the form \code{\_\_i\$num} will be +used for each instance of \code{repeat} in order to permit nesting. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#while} +\label{flowControl.while} + +The template: +\begin{verbatim} +#set $alive = True +#while $alive +I am alive! +#set $alive = False +#end while +\end{verbatim} + +The output: +\begin{verbatim} +I am alive! +\end{verbatim} + +The generated code: +\begin{verbatim} +alive = True +while alive: + write('I am alive!\n') + alive = False +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#if} +\label{} + +The template: +\begin{verbatim} +#set $size = 500 +#if $size >= 1500 +It's big +#else if $size < 1500 and $size > 0 +It's small +#else +It's not there +#end if +\end{verbatim} + +The output: +\begin{verbatim} +It's small +\end{verbatim} + +The generated code: +\begin{verbatim} +size = 500 +if size >= 1500: + write("It's big\n") +elif size < 1500 and size > 0: + write("It's small\n") +else: + write("It's not there\n") +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#unless} +\label{flowControl.unless} + +The template: +\begin{verbatim} +#set $count = 9 +#unless $count + 5 > 15 +Count is in range. +#end unless +\end{verbatim} + +The output: +\begin{verbatim} +Count is in range. +\end{verbatim} + +The generated code: +\begin{verbatim} + count = 9 + if not (count + 5 > 15): + write('Count is in range.\n') +\end{verbatim} + +{\em Note:} There is a bug in Cheetah 0.9.13. It's forgetting the +parentheses in the \code{if} expression, which could lead to it calculating +something different than it should. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#break and \#continue} +\label{flowControl.break} + +The template: +\begin{verbatim} +#for $i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 'James', 'Joe', 'Snow'] +#if $i == 10 + #continue +#end if +#if $i == 'Joe' + #break +#end if +$i - #slurp +#end for +\end{verbatim} + +The output: +\begin{verbatim} +1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 11 - 12 - James - +\end{verbatim} + +The generated code: +\begin{verbatim} +for i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 'James', 'Joe', 'Snow']: + if i == 10: + write('') + continue + if i == 'Joe': + write('') + break + write(filter(i)) # generated from '$i' at line 8, col 1. + write(' - ') +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#pass} +\label{flowControl.pass} + +The template: +\begin{verbatim} +Let's check the number. +#set $size = 500 +#if $size >= 1500 +It's big +#elif $size > 0 +#pass +#else +Invalid entry +#end if +Done checking the number. +\end{verbatim} + +The output: +\begin{verbatim} +Let's check the number. +Done checking the number. +\end{verbatim} + +The generated code: +\begin{verbatim} +write("Let's check the number.\n") +size = 500 +if size >= 1500: + write("It's big\n") +elif size > 0: + pass +else: + write('Invalid entry\n') +write('Done checking the number.\n') +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#stop} +\label{flowControl.stop} + +The template: +\begin{verbatim} +A cat +#if 1 + sat on a mat + #stop + watching a rat +#end if +in a flat. +\end{verbatim} + +The output: +\begin{verbatim} +A cat + sat on a mat +\end{verbatim} + +The generated code: +\begin{verbatim} +write('A cat\n') +if 1: + write(' sat on a mat\n') + if dummyTrans: + return trans.response().getvalue() + else: + return "" + write(' watching a rat\n') +write('in a flat.\n') +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#return} +\label{flowControl.return} + +The template: +\begin{verbatim} +1 +$test[1] +3 +#def test +1.5 +#if 1 +#return '123' +#else +99999 +#end if +#end def +\end{verbatim} + +The output: +\begin{verbatim} +1 +2 +3 +\end{verbatim} + +The generated code: +\begin{verbatim} + def test(self, + trans=None, + dummyTrans=False, + VFS=valueFromSearchList, + VFN=valueForName, + getmtime=getmtime, + currentTime=time.time): + + + """ + Generated from #def test at line 5, col 1. + """ + + if not trans: + trans = DummyTransaction() + dummyTrans = True + write = trans.response().write + SL = self._searchList + filter = self._currentFilter + globalSetVars = self._globalSetVars + + ######################################## + ## START - generated method body + + write('1.5\n') + if 1: + return '123' + else: + write('99999\n') + + ######################################## + ## END - generated method body + + if dummyTrans: + return trans.response().getvalue() + else: + return "" +\end{verbatim} +\begin{verbatim} + def respond(self, + trans=None, + dummyTrans=False, + VFS=valueFromSearchList, + VFN=valueForName, + getmtime=getmtime, + currentTime=time.time): + + + """ + This is the main method generated by Cheetah + """ + + if not trans: + trans = DummyTransaction() + dummyTrans = True + write = trans.response().write + SL = self._searchList + filter = self._currentFilter + globalSetVars = self._globalSetVars + + ######################################## + ## START - generated method body + + write('\n1\n') + write(filter(VFS(SL,"test",1)[1])) # generated from '$test[1]' at line 3, col 1. + write('\n3\n') + + ######################################## + ## END - generated method body + + if dummyTrans: + return trans.response().getvalue() + else: + return "" +\end{verbatim} + + +% Local Variables: +% TeX-master: "devel_guide" +% End: diff --git a/docs/devel_guide_src/history.tex b/docs/devel_guide_src/history.tex new file mode 100755 index 0000000..d5444d5 --- /dev/null +++ b/docs/devel_guide_src/history.tex @@ -0,0 +1,92 @@ +\section{History of Cheetah} +\label{history} + +In Spring 2001, several members of the webware-discuss mailing list expressed +the need for a template engine. Webware like Python is great for organizing +logic, but they both suffer when you need to do extensive variable +interpolation into large pieces of text, or to build up a text string from its +nested parts. Python's \code{\%} operator gets you only so far, the syntax is +cumbersome, and you have to use a separate format string for each nested part. +Most of us had used template systems from other platforms--chiefly Zope's DTML, +PHPLib's Template object and Java's Velocity--and wanted to port something like +those so it could be used both in Webware servlets and in standalone Python +programs. + +% @@MO: What influence did PSP have on Cheetah? + +Since I (Mike Orr) am writing this history, I'll describe how I encountered +Cheetah. I had written a template module called PlowPlate based on PHPLib's +Template library. Like PHPLib, it used regular expressions to search +and destroy--er, replace--placeholders, behaved like a dictionary to +specify placeholder values, contained no directives, but did have BEGIN and +END markers which could be used to extract a named block (subtemplate). +Meanwhile, Tavis Rudd was also on webware-discuss and interested in templates, +and he lived just a few hours away. So on 12 May 2001 we met in Vancouver at +a gelato shop on Denman Street and discussed Webware, and he drew on a napkin +the outline of a template system he was working on. + +[Note from Tavis: Mikes got the dates and sequence of things a little out of order, +but what the hell ...] + +Instead of filling the template by search-and-replace, he wanted to break it up +into parts. This was a primitive form of template compiling: do the +time-consuming work once and put it to a state where you can fill the template +quickly multiple times. A template without directives happens to break down +naturally into a list of alternating text/placeholder pairs. The odd +subscript values are literal strings; the even subscripts are string keys into +a dictionary of placeholder values. The project was called TemplateServer. + +In a couple months, Tavis decided that instead of compiling to a list, he +wanted to compile to Python source code: a series of \code{write} calls that +would output into a file-like object. This was the nucleus that became +Cheetah. I thought that idea was stupid, but it turned out that this +not-so-stupid idea blew all the others out of the water in terms of +performance. + +Another thing Tavis pushed hard for from near the beginning was ``display +logic'', or simple directives like \code{\#for}, \code{\#if} and +\code{\#echo}. (OK, \code{\#echo} came later, but conceptually it belongs +here. I thought display logic was even stupider than compiling to Python +source code because it would just lead to ``DTML hell''--complicated templates +that are hard to read and maintain, and for which you have to learn (and debug) +a whole new language when Python does it just fine. But others (hi Chuck!) had +templates that were maintained by secretaries who didn't know Python, and the +secretaries needed display logic, so that was that. Finally, after working +with Cheetah templates (with display logic) and PlowPlate templates (with just +blocks rather than display logic), I realized Tavis was smarter than I was and +display logic really did belong in the template. + +The next step was making directives for all the Python flow-control +statements: \code{\#while}, \code{\#try}, \code{\#assert}, etc. Some of +them we couldn't think of a use for. Nevertheless, they were easy to code, +and ``somebody'' would probably need them ``someday'', so we may as well +implement them now. + +During all this, Chuck Esterbrook, Ian Bicking and others offered (and still +offer) their support and suggestions, and Chuck gave us feedback about his use +of Cheetah--its first deployment in a commercial production environment. +Later, Edmund Lian became our \#1 bug reporter and suggester as he used Cheetah +in his web applications. + +% @@MO: Write more about the contributions of Chuck, Ian and others. My +% memory is faulty so I'll have to ask them. + +We were going to release 1.0 in January 2002, but we decided to delay it +until more people used it in real-world situations and gave us feedback +about what is still needed. This has led to many refinements, and we have +added (and removed) features according to this feedback. Nevertheless, +Cheetah has been changing but stable since the late-binding rewrite in +fall 2001, and anybody who keeps up with the cheetah-discuss mailing list +will know when changes occur that require modifying one's template, and +since most people use point releases rather than CVS, they generally have +a few week's warning about any significant changes. + +More detail on Cheetah's history and evolution, and why it is the way it is, +can be found in our paper for the Python10 conference, +\url{http://www.cheetahtemplate.org/Py10.html}. + +% @@MO: Look through the changelog for important milestones to mention. + +% 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 100755 index 0000000..0179555 --- /dev/null +++ b/docs/devel_guide_src/inheritanceEtc.tex @@ -0,0 +1,232 @@ +\section{Directives: Import, Inheritance, Declaration and Assignment} +\label{inheritanceEtc} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#import and \#from} +\label{inheritanceEtc.import} + +The template: +\begin{verbatim} +#import math +\end{verbatim} + +This construct does not produce any output. + +The generated module, at the bottom of the import section: +\begin{verbatim} +import math +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#extends} +\label{inheritanceEtc.extends} + +The template: +\begin{verbatim} +#extends SomeClass +\end{verbatim} + +The generated import (skipped if \code{SomeClass} has already been +imported): +\begin{verbatim} +from SomeClass import SomeClass +\end{verbatim} + +The generated class: +\begin{verbatim} +class x(SomeClass): +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#implements} +\label{inheritanceEtc.implements} + +The template: +\begin{verbatim} +#implements doOutput +\end{verbatim} + +In the generated class, the main method is \code{.doOutput} instead of +\code{.respond}, and the attribute naming this method is: +\begin{verbatim} +_mainCheetahMethod_for_x2= 'doOutput' +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#set and \#set global} +\label{inheritanceEtc.set} + +The template: +\begin{verbatim} +#set $namesList = ['Moe','Larry','Curly'] +$namesList +#set global $toes = ['eeny', 'meeny', 'miney', 'moe'] +$toes +\end{verbatim} + +The output: +\begin{verbatim} +['Moe', 'Larry', 'Curly'] +['eeny', 'meeny', 'miney', 'moe'] +\end{verbatim} + + +The generated code: +\begin{verbatim} +1 namesList = ['Moe','Larry','Curly'] +2 write(filter(namesList)) # generated from '$namesList' at line 2, col 1. +3 write('\n') +4 globalSetVars["toes"] = ['eeny', 'meeny', 'miney', 'moe'] +5 write(filter(VFS(SL,"toes",1))) # generated from '$toes' at line 4, col 1. +6 write('\n') +\end{verbatim} + +\code{globalSetVars} is a local variable referencing \code{.\_globalSetVars}. +Writes go into it directly, but reads take advantage of the fact that +\code{.\_globalSetVars} is on the searchList. (In fact, it's the very first +namespace.) + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#del} +\label{inheritanceEtc.del} + +The template: +\begin{verbatim} +#set $a = 1 +#del $a +#set $a = 2 +#set $arr = [0, 1, 2] +#del $a, $arr[1] +\end{verbatim} + +In the generated class: +\begin{verbatim} +1 a = 1 +2 del a +3 a = 2 +4 arr = [0, 1, 2] +5 del a, arr[1] +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#attr} +\label{inheritanceEtc.attr} + +The template: +\begin{verbatim} +#attr $namesList = ['Moe', 'Larry', 'Curly'] +\end{verbatim} + +In the generated class: +\begin{verbatim} +## GENERATED ATTRIBUTES + +namesList = ['Moe', 'Larry', 'Curly'] +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#def} +\label{inheritanceEtc.def} + +The template: +\begin{verbatim} +#def printArg($arg) +The argument is $arg. +#end def +My method returned $printArg(5). +\end{verbatim} + +The output: +\begin{verbatim} +My method returned The argument is 5. +. +\end{verbatim} + +Hmm, not exactly what we expected. The method returns a trailing newline +because we didn't end the last line with \code{\#slurp}. So the second +period (outside the method) appears on a separate line. + +The \code{\#def} generates a method \code{.printArg} whose structure is similar +to the main method: +\begin{verbatim} +def printArg(self, + arg, + trans=None, + dummyTrans=False, + VFS=valueFromSearchList, + VFN=valueForName, + getmtime=getmtime, + currentTime=time.time): + + + """ + Generated from #def printArg($arg) at line 1, col 1. + """ + + if not trans: + trans = DummyTransaction() + dummyTrans = True + write = trans.response().write + SL = self._searchList + filter = self._currentFilter + globalSetVars = self._globalSetVars + + ######################################## + ## START - generated method body + + write('The argument is ') + write(filter(arg)) # generated from '$arg' at line 2, col 17. + write('.\n') + + ######################################## + ## END - generated method body + + if dummyTrans: + return trans.response().getvalue() + else: + return "" +\end{verbatim} + +When \code{.printArg} is called from a placeholder, only the arguments the user +supplied are passed. The other arguments retain their default values. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#block} +\label{inheritanceEtc.block} + +The template: +\begin{verbatim} +#block content +This page is under construction. +#end block +\end{verbatim} + +The output: +\begin{verbatim} +This page is under construction. +\end{verbatim} + +This construct generates a method \code{.content} in the same structure +as \code{.printArg} above, containing the write code: +\begin{verbatim} +write('This page is under construction.\n') +\end{verbatim} + +In the main method, the write code is: +\begin{verbatim} +self.content(trans=trans) # generated from ('content', '#block content') + # at line 1, col 1. +\end{verbatim} + +So a block placeholder implicitly passes the current transaction to the method. + + +% 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 100755 index 0000000..3403d7e --- /dev/null +++ b/docs/devel_guide_src/introduction.tex @@ -0,0 +1,29 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\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. Then 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. + +Appendix A will contain a BNF syntax of the Cheetah template language. + + +% 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 100755 index 0000000..1b714c2 --- /dev/null +++ b/docs/devel_guide_src/output.tex @@ -0,0 +1,282 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Directives: Output} +\label{output} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#echo} +\label{output.echo} + +The template: +\begin{verbatim} +Here is my #echo ', '.join(['silly']*5) # example +\end{verbatim} + +The output: +\begin{verbatim} +Here is my silly, silly, silly, silly, silly example +\end{verbatim} + +The generated code: +\begin{verbatim} +write('Here is my ') +write(filter(', '.join(['silly']*5) )) +write(' example\n') +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#silent} +\label{output.silent} + +The template: +\begin{verbatim} +Here is my #silent ', '.join(['silly']*5) # example +\end{verbatim} + +The output: +\begin{verbatim} +Here is my example +\end{verbatim} + +The generated code: +\begin{verbatim} + write('Here is my ') + ', '.join(['silly']*5) + write(' example\n') +\end{verbatim} + +OK, it's not quite covert because that extra space gives it away, but it +almost succeeds. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#raw} +\label{output.raw} + +The template: +\begin{verbatim} +Text before raw. +#raw +Text in raw. $alligator. $croc.o['dile']. #set $a = $b + $c. +#end raw +Text after raw. +\end{verbatim} + +The output: +\begin{verbatim} +Text before raw. +Text in raw. $alligator. $croc.o['dile']. #set $a = $b + $c. +Text after raw. +\end{verbatim} + +The generated code: +\begin{verbatim} + write('''Text before raw. +Text in raw. $alligator. $croc.o['dile']. #set $a = $b + $c. +Text after raw. +''') +\end{verbatim} + +So we see that \code{\#raw} is really like a quoting mechanism. It says that +anything inside it is ordinary text, and Cheetah joins a \code{\#raw} section +with adjacent string literals rather than generating a separate \code{write} +call. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#include} +\label{output.include} + +The main template: +\begin{verbatim} +#include "y.tmpl" +\end{verbatim} + +The included template y.tmpl: +\begin{verbatim} +Let's go $voom! +\end{verbatim} + +The shell command and output: +\begin{verbatim} +% voom="VOOM" x.py --env +Let's go VOOM! +\end{verbatim} + +The generated code: +\begin{verbatim} +write(self._includeCheetahSource("y.tmpl", trans=trans, includeFrom="file", + raw=0)) +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{\#include raw} +\label{output.include.raw} + +The main template: +\begin{verbatim} +#include raw "y.tmpl" +\end{verbatim} + +The shell command and output: +\begin{verbatim} +% voom="VOOM" x.py --env +Let's go $voom! +\end{verbatim} + +The generated code: +\begin{verbatim} +write(self._includeCheetahSource("y.tmpl", trans=trans, includeFrom="fil +e", raw=1)) +\end{verbatim} + +That last argument, \code{raw}, makes the difference. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{\#include from a string or expression (eval)} +\label{output.include.expression} + +The template: +\begin{verbatim} +#attr $y = "Let's go $voom!" +#include source=$y +#include raw source=$y +#include source="Bam! Bam!" +\end{verbatim} + +The output: +\begin{verbatim} +% voom="VOOM" x.py --env +Let's go VOOM!Let's go $voom!Bam! Bam! +\end{verbatim} + +The generated code: +\begin{verbatim} +write(self._includeCheetahSource(VFS(SL,"y",1), trans=trans, + includeFrom="str", raw=0, includeID="481020889808.74")) +write(self._includeCheetahSource(VFS(SL,"y",1), trans=trans, + includeFrom="str", raw=1, includeID="711020889808.75")) +write(self._includeCheetahSource("Bam! Bam!", trans=trans, + includeFrom="str", raw=0, includeID="1001020889808.75")) +\end{verbatim} + +Later in the generated class: +\begin{verbatim} +y = "Let's go $voom!" +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#slurp} +\label{output.slurp} + +The template: +\begin{verbatim} +#for $i in range(5) +$i +#end for +#for $i in range(5) +$i #slurp +#end for +Line after slurp. +\end{verbatim} + +The output: +\begin{verbatim} +0 +1 +2 +3 +4 +0 1 2 3 4 Line after slurp. +\end{verbatim} + +The generated code: +\begin{verbatim} +for i in range(5): + write(filter(i)) # generated from '$i' at line 2, col 1. + write('\n') +for i in range(5): + write(filter(i)) # generated from '$i' at line 5, col 1. + write(' ') +write('Line after slurp.\n') +\end{verbatim} + +The space after each number is because of the space before \code{\#slurp} in +the template definition. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#filter} +\label{output.filter} + +The template: +\begin{verbatim} +#attr $ode = ">> Rubber Ducky, you're the one! You make bathtime so much fun! <<" +$ode +#filter WebSafe +$ode +#filter MaxLen +${ode, maxlen=13} +#filter None +${ode, maxlen=13} +\end{verbatim} + +The output: +\begin{verbatim} +>> Rubber Ducky, you're the one! You make bathtime so much fun! << +>> Rubber Ducky, you're the one! You make bathtime so much fun! << +>> Rubber Duc +>> Rubber Ducky, you're the one! You make bathtime so much fun! << +\end{verbatim} + +The \code{WebSafe} filter escapes characters that have a special meaning in +HTML. The \code{MaxLen} filter chops off values at the specified length. +\code{\#filter None} returns to the default filter, which ignores the \code{maxlen} +argument. + +The generated code: +\begin{verbatim} + 1 write(filter(VFS(SL,"ode",1))) # generated from '$ode' at line 2, col 1. + 2 write('\n') + 3 filterName = 'WebSafe' + 4 if self._filters.has_key("WebSafe"): + 5 filter = self._currentFilter = self._filters[filterName] + 6 else: + 7 filter = self._currentFilter = \ + 8 self._filters[filterName] = getattr(self._filtersLib, + filterName)(self).filter + 9 write(filter(VFS(SL,"ode",1))) # generated from '$ode' at line 4, col 1. +10 write('\n') +11 filterName = 'MaxLen' +12 if self._filters.has_key("MaxLen"): +13 filter = self._currentFilter = self._filters[filterName] +14 else: +15 filter = self._currentFilter = \ +16 self._filters[filterName] = getattr(self._filtersLib, + filterName)(self).filter +17 write(filter(VFS(SL,"ode",1), maxlen=13)) # generated from + #'${ode, maxlen=13}' at line 6, col 1. +18 write('\n') +19 filter = self._initialFilter +20 write(filter(VFS(SL,"ode",1), maxlen=13)) # generated from + #'${ode, maxlen=13}' at line 8, col 1. +21 write('\n') +\end{verbatim} + +As we've seen many times, Cheetah wraps all placeholder lookups in a +\code{filter} call. (This also applies to non-searchList lookups: local, +global and builtin variables.) The \code{filter} ``function'' +is actually an alias to the current filter object: +\begin{verbatim} +filter = self._currentFilter +\end{verbatim} +as set at the top of the main method. Here in lines 3-8 and 11-16 we see +the filter being changed. Whoops, I lied. \code{filter} is not an alias to +the filter object itself but to that object's \code{.filter} method. Line 19 +switches back to the default filter. + +In line 17 we see the \code{maxlen} argument being passed as a keyword +argument to \code{filter} (not to \code{VFS}). In line 20 the same thing +happens although the default filter ignores the argument. + +% 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 100755 index 0000000..0198b5d --- /dev/null +++ b/docs/devel_guide_src/parser.tex @@ -0,0 +1,9 @@ +\section{The parser} +\label{parser} + +How templates are compiled: a walk through Parser.py's source. +(Also need to look at Lexer.py, but not too closely.) + +% Local Variables: +% TeX-master: "devel_guide" +% End: diff --git a/docs/devel_guide_src/parserInstructions.tex b/docs/devel_guide_src/parserInstructions.tex new file mode 100644 index 0000000..0af065f --- /dev/null +++ b/docs/devel_guide_src/parserInstructions.tex @@ -0,0 +1,61 @@ +\section{Directives: Parser Instructions} +\label{parserInstructions} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#breakpoint} +\label{parserInstructions.breakpoint} + + +The template: +\begin{verbatim} +Text before breakpoint. +#breakpoint +Text after breakpoint. +#raise RuntimeError +\end{verbatim} + +The output: +\begin{verbatim} +Text before breakpoint. +\end{verbatim} + +The generated code: +\begin{verbatim} +write('Text before breakpoint.\n') +\end{verbatim} + +Nothing after the breakpoint was compiled. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#compiler} +\label{parserInstructions.compiler} + +The template: +\begin{verbatim} +// Not a comment +#compiler commentStartToken = '//' +// A comment +#compiler reset +// Not a comment +\end{verbatim} + +The output: +\begin{verbatim} +// Not a comment +// Not a comment +\end{verbatim} + +The generated code: +\begin{verbatim} +write('// Not a comment\n') +# A comment +write('// Not a comment\n') +\end{verbatim} + +So this didn't affect the generated program, it just affected how the +template definition was read. + +% 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 100755 index 0000000..6049068 --- /dev/null +++ b/docs/devel_guide_src/patching.tex @@ -0,0 +1,134 @@ +\section{Patching Cheetah} +\label{patching} + +How to commit changes to CVS or submit patches, how to run the test suite. +Describe distutils and how the regression tests work. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{File Requirements} +\label{patching.fileRequirements} + +The code{Template} class contains not only the Cheetah infrastructure, but also +some convenience methods useful in all templates. More methods may be added if +it's generally agreed among Cheetah developers that the method is sufficiently +useful to all types of templates, or at least to all types of HTML-output +templates. If a method is too long to fit into \code{Template} -- especially +if it has helper methods -- put it in a mixin class under \code{Cheetah.Utils} +and inherit it. + +Routines for a specific problem domain should be put under +\code{Cheetah.Tools}, so that it doesn't clutter the namespace unless the user +asks for it. + +Remember: \code{Cheetah.Utils} is for objects required by any part of Cheetah's +core. \code{Cheetah.Tools} is for completely optional objects. It should +always be possible to delete \code{Cheetah.Tools} without breaking Cheetah's +core services. + +If a core method needs to look up an attribute defined under +\code{Cheetah.Tools}, it should use \code{hasattr()} and gracefully provide a +default if the attribute does not exist (meaning the user has not imported that +subsystem). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Testing Changes and Building Regression Tests} +\label{patching.testing} + +Cheetah ships with a regression test suite. To run the built-in tests, +execute at the shell prompt: +\begin{verbatim} + cheetah test +\end{verbatim} + +Before checking any changes in, run the tests and verify they all pass. That +way, users can check out the CVS version of Cheetah at any time with a fairly +high confidence that it will work. If you fix a bug or add a feature, please +take the time to add a test that exploits the bug/feature. This will help in +the future, to prevent somebody else from breaking it again without realizing +it. Users can also run the test suite to verify all the features work on their +particular platform and computer. + +The general procedure for modifying Cheetah is as follows: +\begin{enumerate} +\item Write a simple Python program that exploits the bug/feature you're + working on. You can either write a regression test (see below), or a + separate program that writes the template output to one file and put the + expected output in another file; then you can run \code{diff} on the two + outputs. (\code{diff} is a utility included on all Unix-like systems. It + shows the differences between two files line by line. A precompiled + Windows version is at + \url{http://gnuwin32.sourceforge.net/packages/diffutils.htm}, and MacOS + sources at \url{http://perso.wanadoo.fr/gilles.depeyrot/DevTools\_en.html}.) +\item Make the change in your Cheetah CVS sandbox or in your installed + version of Cheetah. If you make it in the sandbox, you'll have to run + \code{python setup.py install} before testing it. If you make it in the + installed version, do {\em not} run the installer or it will overwrite your + changes! +\item Run \code{cheetah test} to verify you didn't break anything. Then run + your little test program. +\item Repeat steps 2-3 until everything is correct. +\item Turn your little program into a regression test as described below. +\item When \code{cheetah test} runs cleanly with your regression test + included, update the \code{CHANGES} file and check in your changes. If you + made the changes in your installed copy of Cheetah, you'll have to copy + them back into the CVS sandbox first. If you added any files that must be + distributed, {\em be sure to} \code{cvs add} them before committing. + Otherwise Cheetah will run fine on your computer but fail on anybody + else's, and the test suite can't check for this. +\item Announce the change on the cheetahtemplate-discuss list and provide a + tutorial if necessary. The documentation maintainer will update the + Users' Guide and Developers' Guide based on this message and on the + changelog. +\end{enumerate} + +If you add a directory to Cheetah, you have to mention it in \code{setup.py} or +it won't be installed. + +The tests are in the \code{Cheetah.Tests} package, aka the \code{src/Tests/} +directory of your CVS sandbox. Most of the tests are in +\code{SyntaxAndOutput.py}. You can either run all the tests or choose which +to run: +\begin{description} +\item{\code{python Test.py}} + Run all the tests. (Equivalent to \code{cheetah test}.) +\item{\code{python SyntaxAndOutput.py}} + Run only the tests in that module. +\item{\code{python SyntaxAndOutput.py CGI}} + Run only the tests in the class \code{CGI} inside the module. The class + must be a direct or indirect subclass of + \code{unittest\_local\_copy.TestCase}. +\item{\code{python SyntaxAndOutput.py CGI Indenter}} + Run the tests in classes \code{CGI} and \code{Indenter}. +\item{\code{python SyntaxAndOutput.py CGI.test1}} + Run only test \code{test1}, which is a method in the \code{CGI} class. +\item{etc...} +\end{description} + +To make a SyntaxAndOutput test, first see if your test logically fits into one +of the existing classes. If so, simply add a method; e.g., \code{test16}. +The method should not require any arguments except \code{self}, and should +call \code{.verify(source, expectedOutput)}, where the two arguments are +a template definition string and a control string. The tester will complain +if the template output does not match the control string. You have a wide +variety of placeholder variables to choose from, anything that's included in +the \code{defaultTestNameSpace} global dictionary. If that's not enough, add +items to the dictionary, but please keep it from being cluttered with wordy +esoteric items for a single test). + +If your test logically belongs in a separate class, create a subclass of +\code{OutputTest}. You do not need to do anything else; the test suite will +automatically find your class in the module. Having a separate class allows +you to define state variables needed by your tests (see the \code{CGI} class) +or override \code{.searchList()} (see the \code{Indenter} class) to provide +your own searchList. + +To modify another test module or create your own test module, you'll have to +study the existing modules, the \code{unittest\_local\_copy} source, and the +\code{unittest} documentation in the Python Library Reference. Note that we +are using a hacked version of \code{unittest} to make a more convenient test +structure for Cheetah. The differences between \code{unittest\_local\_copy} +and Python's standard \code{unittest} are documented at the top of the module. + +% Local Variables: +% TeX-master: "devel_guide" +% End: diff --git a/docs/devel_guide_src/placeholders.tex b/docs/devel_guide_src/placeholders.tex new file mode 100755 index 0000000..e487d09 --- /dev/null +++ b/docs/devel_guide_src/placeholders.tex @@ -0,0 +1,478 @@ +\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 . + +>>> 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 + +\end{verbatim} +\begin{verbatim} + + 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 "" +\end{verbatim} +\begin{verbatim} + 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) ] ) +$_('a call to gettext') +\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, + '_': lambda x: 'translated ' + x +} + +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 +translated a call to gettext + +\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 split 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. +\end{verbatim} +\begin{verbatim} +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: ') +\end{verbatim} +\begin{verbatim} +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 if False: +77 _('foo') +78 write(filter(VFS(SL,"_",0)("a call to gettext"))) + # generated from "$_('a call to gettext')" + # at line 35, col 1. +79 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.) + +Notice the last line is a call to \code{_} (i.e. \code{gettext}) which is used +for internationalization (see +\url{http://docs.python.org/lib/module-gettext.html}). The code is converted +normally, but an \code{if False} block is used so that gettext can +successfully mark the string for translation when parsing the generated Python. +Otherwise, the NameMapper syntax would get in the way of this. + +% 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 100755 index 0000000..2aa3236 --- /dev/null +++ b/docs/devel_guide_src/pyModules.tex @@ -0,0 +1,246 @@ +\section{.py Template Modules} +\label{pyModules} + +This chapter examines the structure of a .py template module. The following +few chapters will then show how each placeholder and directive affects the +generated Python code. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{An example} +\label{pyModules.example} + +Our first template follows a long noble tradition in computer tutorials. +It produces a familiar, friendly greeting. Here's the template: + +\begin{verbatim} +Hello, world! +\end{verbatim} + +... the output: + +\begin{verbatim} +Hello, world! +\end{verbatim} + +... and 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 """ +\end{verbatim} +\begin{verbatim} + 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 "" +\end{verbatim} +\begin{verbatim} + 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 examples were generated from CVS versions of Cheetah between 0.9.12 and +0.9.14. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\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/safeDelegation.tex b/docs/devel_guide_src/safeDelegation.tex new file mode 100755 index 0000000..dd1a8aa --- /dev/null +++ b/docs/devel_guide_src/safeDelegation.tex @@ -0,0 +1,44 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Safe Delegation} +\label{safeDelegation} + +% @@MO: Does this really belong in the Developers' Guide or any guide? +% It's more of a wiki Wishlist item, no? Especially since nobody has +% expressed a need for it. + +Safe delegation, as provided by Zope and Allaire's Spectra, is not implemented +in Cheetah. The core aim has been to help developers and template maintainers +get things done, without throwing unnecessary complications in their +way. So you should give write access to your templates only to those whom you +trust. However, several hooks have been built into Cheetah so that safe +delegation can be implemented at a later date. + +It should be possible to implement safe delegation via a future configuration +Setting \code{safeDelegationLevel} (0=none, 1=semi-secure, 2-alcatraz). This +is not implemented but the steps are listed here in case somebody wants to try +them out and test them. + +Of course, you would also need to benchmark your code +and verify it does not impact performance when safe delegation is off, and +impacts it only modestly when it is on." All necessary changes can be made +at compile time, so there should be no performance impact when filling the +same TO multiple times. + +\begin{enumerate} + +\item Only give untrusted developers access to the .tmpl files. +(Verifying what this means. Why can't trusted developers access them?) + +\item Disable the \code{\#attr} directive and maybe the \code{\#set} directive. + +\item Use Cheetah's directive validation hooks to disallow +references to \code{self}, etc +(e.g. \code{\#if \$steal(self.thePrivateVar)} ) + +\item Implement a validator for the \$placeholders and use it +to disallow '\_\_' in \$placeholders so that tricks like +\code{\$obj.\_\_class\_\_.\_\_dict\_\_} are not possible. + +\end{enumerate} + + diff --git a/docs/devel_guide_src/template.tex b/docs/devel_guide_src/template.tex new file mode 100755 index 0000000..1ad21c4 --- /dev/null +++ b/docs/devel_guide_src/template.tex @@ -0,0 +1,11 @@ +\section{Template} +\label{template} + +This chapter will mainly walk through the \code{Cheetah.Template} constructor +and not at what point the template is compiled. + +(Also need to look at Transaction,py and Servlet.py.) + +% Local Variables: +% TeX-master: "devel_guide" +% End: diff --git a/docs/howto_extras/comparisions.txt b/docs/howto_extras/comparisions.txt new file mode 100755 index 0000000..56a0fb3 --- /dev/null +++ b/docs/howto_extras/comparisions.txt @@ -0,0 +1,451 @@ +\section{Cheetah vs. Other Template Engines} +\label{comparisons} + +This appendix compares Cheetah with various other template/emdedded scripting +languages and Internet development frameworks. As Cheetah is similar to +Velocity at a superficial level, you may also wish to read comparisons between +Velocity and other languages at +\url{http://jakarta.apache.org/velocity/ymtd/ymtd.html}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Which features are unique to Cheetah} +\label{comparisons.unique} + +\begin{itemize} +\item The {\bf block framework} (section \ref{inheritanceEtc.block}) +\item Cheetah's powerful yet simple {\bf caching framework} (section + \ref{output.caching}) +\item Cheetah's {\bf Unified Dotted Notation} and {\bf autocalling} + (sections \ref{language.namemapper.dict} and + \ref{language.namemapper.autocalling}) +\item Cheetah's searchList (section \ref{language.searchList}) + information. +\item Cheetah's \code{\#raw} directive (section \ref{output.raw}) +\item Cheetah's \code{\#slurp} directive (section \ref{output.slurp}) +\item Cheetah's tight integration with Webware for Python (section + \ref{webware}) +\item Cheetah's {\bf SkeletonPage framework} (section + \ref{libraries.templates.skeletonPage}) +\item Cheetah's ability to mix PSP-style code with Cheetah + Language syntax (section \ref{tips.PSP}) + Because of Cheetah's design and Python's flexibility it is + relatively easy to extend Cheetah's syntax with syntax elements from almost + any other template or embedded scripting language. +\end{itemize} + +%% @@MO: What about the new features we've been adding? + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. Velocity} +\label{comparisons.velocity} + +For a basic introduction to Velocity, visit +\url{http://jakarta.apache.org/velocity}. + +Velocity is a Java template engine. It's older than Cheetah, has a larger user +base, and has better examples and docs at the moment. Cheetah, however, has a +number of advantages over Velocity: +\begin{itemize} +\item Cheetah is written in Python. Thus, it's easier to use and extend. +\item Cheetah's syntax is closer to Python's syntax than Velocity's is to +Java's. +\item Cheetah has a powerful caching mechanism. Velocity has no equivalent. +\item It's far easier to add data/objects into the namespace where \$placeholder + values are extracted from in Cheetah. Velocity calls this namespace a 'context'. + Contexts are dictionaries/hashtables. You can put anything you want into a + context, BUT you have to use the .put() method to populate the context; + e.g., + +\begin{verbatim} +VelocityContext context1 = new VelocityContext(); +context1.put("name","Velocity"); +context1.put("project", "Jakarta"); +context1.put("duplicate", "I am in context1"); +\end{verbatim} + + Cheetah takes a different approach. Rather than require you to manually + populate the 'namespace' like Velocity, Cheetah will accept any existing + Python object or dictionary AS the 'namespace'. Furthermore, Cheetah + allows you to specify a list namespaces that will be searched in sequence + to find a varname-to-value mapping. This searchList can be extended at + run-time. + + If you add a `foo' object to the searchList and the `foo' has an attribute + called 'bar', you can simply type \code{\$bar} in the template. If the + second item in the searchList is dictionary 'foofoo' containing + \code{\{'spam':1234, 'parrot':666\}}, Cheetah will first look in the `foo' + object for a `spam' attribute. Not finding it, Cheetah will then go to + `foofoo' (the second element in the searchList) and look among its + dictionary keys for `spam'. Finding it, Cheetah will select + \code{foofoo['spam']} as \code{\$spam}'s value. + +\item In Cheetah, the tokens that are used to signal the start of + \$placeholders and \#directives are configurable. You can set them to any + character sequences, not just \$ and \#. +\end{itemize} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. WebMacro} +\label{comparisons.webmacro} + +For a basic introduction to WebMacro, visit +\url{http://webmacro.org}. + +The points discussed in section \ref{comparisons.velocity} also apply to the +comparison between Cheetah and WebMacro. For further differences please refer +to \url{http://jakarta.apache.org/velocity/differences.html}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. Zope's DTML} +\label{comparisons.dtml} + +For a basic introduction to DTML, visit +\url{http://www.zope.org/Members/michel/ZB/DTML.dtml}. + +\begin{itemize} +\item Cheetah is faster than DTML. +\item Cheetah does not use HTML-style tags; DTML does. Thus, Cheetah tags are + visible in rendered HTML output if something goes wrong. +\item DTML can only be used with ZOPE for web development; Cheetah can be + used as a standalone tool for any purpose. +\item Cheetah's documentation is more complete than DTML's. +\item Cheetah's learning curve is shorter than DTML's. +\item DTML has no equivalent of Cheetah's blocks, caching framework, + unified dotted notation, and \code{\#raw} directive. +\end{itemize} + +Here are some examples of syntax differences between DTML and Cheetah: +\begin{verbatim} +
    + +
  • +
    +
+\end{verbatim} + +\begin{verbatim} +
    +#for $animal_name in $frogQuery +
  • $animal_name
  • +#end for +
+\end{verbatim} + +\begin{verbatim} + +

There are too many monkeys!

+ +

There aren't enough monkeys!

+ +

There are just enough monkeys.

+
+\end{verbatim} + +\begin{verbatim} +#if $monkeys > $monkey_limit +

There are too many monkeys!

+#else if $monkeys < $minimum_monkeys +

There aren't enough monkeys!

+#else +

There are just enough monkeys.

+#end if +\end{verbatim} + +\begin{verbatim} + + + + + + + + + +
+ +
+\end{verbatim} + +\begin{verbatim} + +#set $evenRow = 0 +#for $file in $files('File') + #if $evenRow + + #set $evenRow = 0 + #else + + #set $evenRow = 1 + #end if + +#end for +
+ $file.title_or_id +
+\end{verbatim} + +The last example changed the name of \code{\$objectValues} to +\code{\$files} because that's what a Cheetah developer would write. +The developer would be responsible for ensuring \code{\$files} returned a +list (or tuple) of objects (or dictionaries) containing the attributes (or +methods or dictionary keys) `absolute\_url' and `title\_or\_id'. All these +names (`objectValues', `absolute\_url' and `title\_or\_id') are standard parts +of Zope, but in Cheetah the developer is in charge of writing them and giving +them a reasonable behaviour. + +Some of DTML's features are being ported to Cheetah, such as +\code{Cheetah.Tools.MondoReport}, which is based on the +\code{} tag. We are also planning an output filter as flexible as +the \code{} formatting options. However, neither of these are +complete yet. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. Zope Page Templates} +\label{comparisons.zpt} + +For a basic introduction to Zope Page Templates, please visit +\url{http://www.zope.org/Documentation/Articles/ZPT2}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. PHP's Smarty templates} +\label{comparisons.smarty} + +PHP (\url{http://www.php.net/}) is one of the few scripting languages +expressly designed for web servlets. However, it's also a full-fledged +programming language with libraries similar to Python's and Perl's. The +syntax and functions are like a cross between Perl and C plus some original +ideas (e.g.; a single array type serves as both a list and a dictionary, +\verb+$arr[]="value";+ appends to an array). + +Smarty (\url{http://smarty.php.net/}) is an advanced template engine for +PHP. ({\em Note:} this comparision is based on Smarty's on-line documentation. +The author has not used Smarty. Please send corrections or ommissions to the +Cheetah mailing list.) Like Cheetah, Smarty: + +\begin{itemize} +\item compiles to the target programming language (PHP). +\item has configurable delimeters. +\item passes if-blocks directly to PHP, so you can use any PHP expression in +them. +\item allows you to embed PHP code in a template. +\item has a caching framework (although it works quite differently). +\item can read the template definition from any arbitrary source. +\end{itemize} + +Features Smarty has that Cheetah lacks: +\begin{itemize} +\item Preprocessors, postprocessors and output filters. You can emulate a +preprocessor in Cheetah by running your template definition through a filter +program or function before Cheetah sees it. To emulate a postprocessor, run a +.py template module through a filter program/function. To emulate a Smarty +output filter, run the template output through a filter program/function. If +you want to use ``cheetah compile'' or ``cheetah fill'' in a pipeline, use +\code{-} as the input file name and \code{--stdout} to send the result to +standard output. Note that Cheetah uses the term ``output filter'' differently +than Smarty: Cheetah output filters (\code{\#filter}) operate on placeholders, +while Smarty output filters operate on the entire template output. There has +been a proposed \code{\#sed} directive that would operate on the entire output +line by line, but it has not been implemented. +\item Variable modifiers. In some cases, Python has equivalent string +methods (\code{.strip}, \code{.capitalize}, \code{.replace(SEARCH, REPL)}), +but in other cases you must wrap the result in a function call or write +a custom output filter (\code{\#filter}). +\item Certain web-specific functions, which can be emulated with +third-party functions. +\item The ability to ``plug in'' new directives in a modular way. Cheetah +directives are tightly bound to the compiler. However, third-party +{\em functions} can be freely imported and called from placeholders, and +{\em methods} can be mixed in via \code{\#extends}. Part of this is +because Cheetah distinguishes between functions and directives, while +Smarty treats them all as ``functions''. Cheetah's design does not +allow functions to have flow control effect outside the function +(e.g., \code{\#if} and \code{\#for}, which operate on template body lines), +so directives like these cannot be encoded as functions. +\item Configuration variables read from an .ini-style file. The +\code{Cheetah.SettingsManager} module can parse such a file, but you'd +have to invoke it manually. (See the docstrings in the module for +details.) In Smarty, this feature is used for +multilingual applications. In Cheetah, the developers maintain that everybody +has their own preferred way to do this (such as using Python's \code{gettext} +module), and it's not worth blessing one particular strategy in Cheetah since +it's easy enough to integrate third-party code around the template, or to add +the resulting values to the searchList. +\end{itemize} + +Features Cheetah has that Smarty lacks: +\begin{itemize} +\item Saving the compilation result in a Python (PHP) module for quick +reading later. +\item Caching individual placeholders or portions of a template. Smarty +caches only the entire template output as a unit. +\end{itemize} + +Comparisions of various Smarty constructs: +\begin{verbatim} +{assign var="name" value="Bob"} (#set has better syntax in the author's opinion) +counter (looks like equivalent to #for) +eval (same as #include with variable) +fetch: insert file content into output (#include raw) +fetch: insert URL content into output (no euqivalent, user can write + function calling urllib, call as $fetchURL('URL') ) +fetch: read file into variable (no equivalent, user can write function + based on the 'open/file' builtin, or on .getFileContents() in + Template.) +fetch: read URL content into variable (no equivalent, use above + function and call as: #set $var = $fetchURL('URL') +html_options: output an HTML option list (no equivalent, user can + write custom function. Maybe FunFormKit can help.) +html_select_date: output three dropdown controls to specify a date + (no equivalent, user can write custom function) +html_select_time: output four dropdown controls to specify a time + (no equvalent, user can write custom function) +math: eval calculation and output result (same as #echo) +math: eval calculation and assign to variable (same as #set) +popup_init: library for popup windows (no equivalent, user can write + custom method outputting Javascript) + + +Other commands: +capture (no equivalent, collects output into variable. A Python + program would create a StringIO instance, set sys.stdout to + it temporarily, print the output, set sys.stdout back, then use + .getvalue() to get the result.) +config_load (roughly analagous to #settings, which was removed + from Cheetah. Use Cheetah.SettingsManager manually or write + a custom function.) +include (same as #include, but can include into variable. + Variables are apparently shared between parent and child.) +include_php: include a PHP script (e.g., functions) + (use #extends or #import instead) +insert (same as #include not in a #cache region) +{ldelim}{rdelim} (escape literal $ and # with a backslash, + use #compiler-settings to change the delimeters) +literal (#raw) +php (``<% %>'' tags) +section (#for $i in $range(...) ) +foreach (#for) +strip (like the #sed tag which was never implemented. Strips + leading/trailing whitespace from lines, joins several lines + together.) + + +Variable modifiers: +capitalize ( $STRING.capitalize() ) +count_characters ( $len(STRING) ) +count_paragraphs/sentances/words (no equivalent, user can write function) +date_format (use 'time' module or download Egenix's mx.DateTime) +default ($getVar('varName', 'default value') ) +escape: html encode ($cgi.escape(VALUE) ) +escape: url encode ($urllib.quote_plus(VALUE) ) +escape: hex encode (no equivalent? user can write function) +escape: hex entity encode (no equivalent? user can write function) +indent: indent all lines of a var's output (may be part of future + #indent directive) +lower ($STRING.lower() ) +regex_replace ('re' module) +replace ($STRING.replace(OLD, NEW, MAXSPLIT) ) +spacify (#echo "SEPARATOR".join(SEQUENCE) ) +string_format (#echo "%.2f" % FLOAT , etc.) +strip_tags (no equivalent, user can write function to strip HTML tags, + or customize the WebSafe filter) +truncate (no equivalent, user can write function) +upper ($STRING.upper() ) +wordwrap ('writer' module, or a new module coming in Python 2.3) +\end{verbatim} + +Some of these modifiers could be added to the super output filter we +want to write someday. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. PHPLib's Template class} +\label{comparisons.php} + +PHPLib (\url(http://phplib.netuse.de/) is a collection of classes for various +web objects (authentication, shopping cart, sessions, etc), but what we're +interested in is the \code{Template} object. It's much more primitive than +Smarty, and was based on an old Perl template class. In fact, one of the +precursors to Cheetah was based on it too. Differences from Cheetah: + +\begin{itemize} +\item Templates consist of text with \code{\{placeholders\}} in braces. +\item Instead of a searchList, there is one flat namespace. Every variable + must be assigned via the \code{set\_var} method. However, you can pass + this method an array (dictionary) of several variables at once. +\item You cannot embed lookups or calculations into the template. Every + placeholder must be an exact variable name. +\item There are no directives. You must do all display logic (if, for, etc) + in the calling routine. +\item There is, however, a ``block'' construct. A block is a portion of text + between the comment markers \code{ \ldots + + + +#block writeHeadTag + +$title +$metaTags +$stylesheetTags +$javascriptTags + +#end block writeHeadTag + +#end cache header +################# + +$bodyTag + +#block writeBody +This skeleton page has no flesh. Its body needs to be implemented. +#end block writeBody + + + +\end{verbatim} + +You can redefine any of the blocks defined in this template by writing a new +template that \code{\#extends} SkeletonPage. (As you remember, using +\code{\#extends} makes your template implement the \code{.writeBody()} +method instead of \code{.respond()} -- which happens to be the same method +SkeletonPage expects the page content to be (note the writeBody block in +SkeletonPage).) + +\begin{verbatim} +#def bodyContents +Here's my new body. I've got some flesh on my bones now. +#end def bodyContents +\end{verbatim} + +%% @@MO: Is this still accurate? Does the child template really need to put a +%% #def around its whole content? Or by implementing .writeBody() does it +%% automatically insert itself as the writeBody portion of +%% SkeletonPage? @@TR 2005-01-06: it happens automatically at the moment. + +All of the \$placeholders used in the \code{SkeletonPage} template definition +are attributes or methods of the \code{SkeletonPage} class. You can reimplement +them as you wish in your subclass. Please read the source code of the file +\code{src/Templates/\_SkeletonPage.py} before doing so. + +You'll need to understand how to use the following methods of the +\code{SkeletonPage} class: \code{\$metaTags()}, \code{\$stylesheetTags()}, +\code{\$javascriptTags()}, and \code{\$bodyTag()}. They take the data you +define in various attributes and renders them into HTML tags. + +\begin{itemize} +\item {\bf metaTags()} -- Returns a formatted vesion of the self.\_metaTags + dictionary, using the formatMetaTags function from + \code{\_SkeletonPage.py}. +\item {\bf stylesheetTags()} -- Returns a formatted version of the + \code{self.\_stylesheetLibs} and \code{self.\_stylesheets} dictionaries. + The keys in \code{self.\_stylesheets} must be listed in the order that + they should appear in the list \code{self.\_stylesheetsOrder}, to ensure + that the style rules are defined in the correct order. +\item {\bf javascriptTags()} -- Returns a formatted version of the + \code{self.\_javascriptTags} and \code{self.\_javascriptLibs} dictionaries. + Each value in \code{self.\_javascriptTags} should be a either a code string + to include, or a list containing the JavaScript version number and the code + string. The keys can be anything. The same applies for + \code{self.\_javascriptLibs}, but the string should be the SRC filename + rather than a code string. +\item {\bf bodyTag()} -- Returns an HTML body tag from the entries in the dict + \code{self.\_bodyTagAttribs}. +\end{itemize} + +The class also provides some convenience methods that can be used as +\$placeholders in your template definitions: + +\begin{itemize} +\item {\bf imgTag(self, src, alt='', width=None, height=None, border=0)} -- + Dynamically generate an image tag. Cheetah will try to convert the + ``\code{src}'' argument to a WebKit serverSidePath relative to the + servlet's location. If width and height aren't specified they are + calculated using PIL or ImageMagick if either of these tools are available. + If all your images are stored in a certain directory you can reimplement + this method to append that directory's path to the ``\code{src}'' argument. + Doing so would also insulate your template definitions from changes in your + directory structure. +\end{itemize} + + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_2_src/18_editors.txt b/docs/users_guide_2_src/18_editors.txt new file mode 100755 index 0000000..84c8f03 --- /dev/null +++ b/docs/users_guide_2_src/18_editors.txt @@ -0,0 +1,39 @@ +\section{Visual Editors} +\label{visualEditors} + +This chapter is about maintaining Cheetah templates with visual editors, +and the tradeoffs between making it friendly to both text editors and visual +editors. + +Cheetah's main developers do not use visual editors. Tavis uses \code{emacs}; +Mike uses \code{vim}. So our first priority is to make templates easy to +maintain in text editors. In particular, we don't want to add features +like Zope Page Template's +placeholder-value-with-mock-text-for-visual-editors-all-in-an-XML-tag. +The syntax is so verbose it makes for a whole lotta typing just to insert a +simple placeholder, for the benefit of editors we never use. However, as users +identify features which would help their visual editing without making it +harder to maintain templates in a text editor, we're all for it. + +As it said in the introduction, Cheetah purposely does not use HTML/XML +tags for \$placeholders or \#directives. That way, when you preview the +template in an editor that interprets HTML tags, you'll still see the +placeholder and directive source definitions, which provides some ``mock text'' +even if it's not the size the final values will be, and allows you to use +your imagination to translate how the directive output will look visually in +the final. + +If your editor has syntax highlighting, turn it on. That makes a big +difference in terms of making the template easier to edit. Since no +``Cheetah mode'' has been invented yet, set your highlighting to Perl +mode, and at least the directives/placeholders will show up in different +colors, although the editor won't reliably guess where the +directive/placeholder ends and normal text begins. + +% Local Variables: +% TeX-master: "users_guide" +% End: + + + + diff --git a/docs/users_guide_2_src/A_links.txt b/docs/users_guide_2_src/A_links.txt new file mode 100755 index 0000000..1ec2f6c --- /dev/null +++ b/docs/users_guide_2_src/A_links.txt @@ -0,0 +1,112 @@ +\section{Useful Web Links} +\label{links} + +See the wiki for more links. (The wiki is also updated more often than this +chapter is.) + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah Links} +\label{links.cheetah} + +\begin{description} +\item[Home Page] -- \url{http:www.CheetahTemplate.org/} + +\item[On-line Documentation] -- \url{http:www.CheetahTemplate.org/learn.html} + +\item[SourceForge Project Page] -- \url{http:sf.net/projects/cheetahtemplate/} + +\item[Mailing List Subscription Page] -- + \url{http://lists.sourceforge.net/lists/listinfo/cheetahtemplate-discuss} + +\item[Mailing List Archive @ Geocrawler] -- + \url{http://www.geocrawler.com/lists/3/SourceForge/12986/0/} + +\item[Mailing List Archive @ Yahoo] -- + \url{http://groups.yahoo.com/group/cheetah-archive/} + +\item[CVS Repository] -- \url{http://sourceforge.net/cvs/?group\_id=28961} + +\item[CVS-commits archive] -- + \url{http://www.geocrawler.com/lists/3/SourceForge/13091/0/} + +\end{description} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Third-party Cheetah Stuff} +\label{links.thirdParty} + +\begin{itemize} +\item Steve Howell has written a photo viewer using Python. + \url{http://mountainwebtools.com/PicViewer/install.htm} +\end{itemize} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Webware Links} +\label{links.webware} + +\begin{description} +\item[Home Page] -- \url{http://webware.sf.net/} + +\item[On-line Documentation] -- \url{http://webware.sf.net/Webware/Docs/} + +\item[SourceForge Project Page] -- \url{http://sf.net/projects/webware/} + +\item[Mailing List Subscription Page] -- + \url{http://lists.sourceforge.net/lists/listinfo/webware-discuss} + +\end{description} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Python Links} +\label{links.python} + +\begin{description} +\item[Home Page] -- \url{http://www.python.org/} +\item[On-line Documentation] -- \url{http://www.python.org/doc/} +\item[SourceForge Project Page] -- \url{http://sf.net/projects/python/} +\item[The Vaults of Parnassus: Python Resources] -- + \url{http://www.vex.net/parnassus/} +\item[Python Cookbook] -- \url{http://aspn.activestate.com/ASPN/Cookbook/Python} +\end{description} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Other Useful Links} +\label{links.other} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Python Database Modules and Open Source Databases} +\label{links.database} + +\begin{description} +\item[Python Database Topic Guide] -- \url{http://python.org/topics/database/} +\item[PostgreSQL Database] -- \url{http://www.postgresql.org/index.html} +\item[MySQL Database] -- \url{http://www.mysql.com/} +\item[A comparison of PostgreSQL and MySQL] -- + \url{http://phpbuilder.com/columns/tim20001112.php3} +\end{description} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Other Template Systems} +\label{links.other.templateSystems} + +\begin{description} +\item[Chuck's ``Templates'' Summary Page] -- \url{http://webware.sf.net/Papers/Templates/} +\end{description} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Other Internet development frameworks} +\label{links.internet} + +\begin{description} +\item[ZOPE (Z Object Publishing Environment)] -- \url{http://zope.org/} +\item[Server Side Java] -- \url{http://jakarta.apache.org/} +\item[PHP] -- \url{http://php.net/} +\item[IBM Websphere] -- \url{http://www.ibm.com/websphere/} +\item[Coldfusion and Spectra] -- \url{http://www.macromedia.com/} +\end{description} + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_2_src/B_examples.txt b/docs/users_guide_2_src/B_examples.txt new file mode 100755 index 0000000..6c394fb --- /dev/null +++ b/docs/users_guide_2_src/B_examples.txt @@ -0,0 +1,24 @@ +\section{Examples} +\label{examples} + +The Cheetah distribution comes with an 'examples' directory. Browse the +files in this directory and its subdirectories for examples of how +Cheetah can be used. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Syntax examples} +The \code{Cheetah.Tests} module contains a large number of test cases that can +double as examples of how the Cheetah Language works. To view these cases go +to the base directory of your Cheetah distribution and open the file +\code{Cheetah/Tests/SyntaxAndOutput.py} in a text editor. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Webware Examples} +For examples of Cheetah in use with Webware visit the Cheetah and Webware wikis +or use google. We used to have more examples in the cheetah source tarball, but +they were out of date and confused people. + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_2_src/C_comparisions.txt b/docs/users_guide_2_src/C_comparisions.txt new file mode 100755 index 0000000..56a0fb3 --- /dev/null +++ b/docs/users_guide_2_src/C_comparisions.txt @@ -0,0 +1,451 @@ +\section{Cheetah vs. Other Template Engines} +\label{comparisons} + +This appendix compares Cheetah with various other template/emdedded scripting +languages and Internet development frameworks. As Cheetah is similar to +Velocity at a superficial level, you may also wish to read comparisons between +Velocity and other languages at +\url{http://jakarta.apache.org/velocity/ymtd/ymtd.html}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Which features are unique to Cheetah} +\label{comparisons.unique} + +\begin{itemize} +\item The {\bf block framework} (section \ref{inheritanceEtc.block}) +\item Cheetah's powerful yet simple {\bf caching framework} (section + \ref{output.caching}) +\item Cheetah's {\bf Unified Dotted Notation} and {\bf autocalling} + (sections \ref{language.namemapper.dict} and + \ref{language.namemapper.autocalling}) +\item Cheetah's searchList (section \ref{language.searchList}) + information. +\item Cheetah's \code{\#raw} directive (section \ref{output.raw}) +\item Cheetah's \code{\#slurp} directive (section \ref{output.slurp}) +\item Cheetah's tight integration with Webware for Python (section + \ref{webware}) +\item Cheetah's {\bf SkeletonPage framework} (section + \ref{libraries.templates.skeletonPage}) +\item Cheetah's ability to mix PSP-style code with Cheetah + Language syntax (section \ref{tips.PSP}) + Because of Cheetah's design and Python's flexibility it is + relatively easy to extend Cheetah's syntax with syntax elements from almost + any other template or embedded scripting language. +\end{itemize} + +%% @@MO: What about the new features we've been adding? + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. Velocity} +\label{comparisons.velocity} + +For a basic introduction to Velocity, visit +\url{http://jakarta.apache.org/velocity}. + +Velocity is a Java template engine. It's older than Cheetah, has a larger user +base, and has better examples and docs at the moment. Cheetah, however, has a +number of advantages over Velocity: +\begin{itemize} +\item Cheetah is written in Python. Thus, it's easier to use and extend. +\item Cheetah's syntax is closer to Python's syntax than Velocity's is to +Java's. +\item Cheetah has a powerful caching mechanism. Velocity has no equivalent. +\item It's far easier to add data/objects into the namespace where \$placeholder + values are extracted from in Cheetah. Velocity calls this namespace a 'context'. + Contexts are dictionaries/hashtables. You can put anything you want into a + context, BUT you have to use the .put() method to populate the context; + e.g., + +\begin{verbatim} +VelocityContext context1 = new VelocityContext(); +context1.put("name","Velocity"); +context1.put("project", "Jakarta"); +context1.put("duplicate", "I am in context1"); +\end{verbatim} + + Cheetah takes a different approach. Rather than require you to manually + populate the 'namespace' like Velocity, Cheetah will accept any existing + Python object or dictionary AS the 'namespace'. Furthermore, Cheetah + allows you to specify a list namespaces that will be searched in sequence + to find a varname-to-value mapping. This searchList can be extended at + run-time. + + If you add a `foo' object to the searchList and the `foo' has an attribute + called 'bar', you can simply type \code{\$bar} in the template. If the + second item in the searchList is dictionary 'foofoo' containing + \code{\{'spam':1234, 'parrot':666\}}, Cheetah will first look in the `foo' + object for a `spam' attribute. Not finding it, Cheetah will then go to + `foofoo' (the second element in the searchList) and look among its + dictionary keys for `spam'. Finding it, Cheetah will select + \code{foofoo['spam']} as \code{\$spam}'s value. + +\item In Cheetah, the tokens that are used to signal the start of + \$placeholders and \#directives are configurable. You can set them to any + character sequences, not just \$ and \#. +\end{itemize} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. WebMacro} +\label{comparisons.webmacro} + +For a basic introduction to WebMacro, visit +\url{http://webmacro.org}. + +The points discussed in section \ref{comparisons.velocity} also apply to the +comparison between Cheetah and WebMacro. For further differences please refer +to \url{http://jakarta.apache.org/velocity/differences.html}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. Zope's DTML} +\label{comparisons.dtml} + +For a basic introduction to DTML, visit +\url{http://www.zope.org/Members/michel/ZB/DTML.dtml}. + +\begin{itemize} +\item Cheetah is faster than DTML. +\item Cheetah does not use HTML-style tags; DTML does. Thus, Cheetah tags are + visible in rendered HTML output if something goes wrong. +\item DTML can only be used with ZOPE for web development; Cheetah can be + used as a standalone tool for any purpose. +\item Cheetah's documentation is more complete than DTML's. +\item Cheetah's learning curve is shorter than DTML's. +\item DTML has no equivalent of Cheetah's blocks, caching framework, + unified dotted notation, and \code{\#raw} directive. +\end{itemize} + +Here are some examples of syntax differences between DTML and Cheetah: +\begin{verbatim} +
    + +
  • +
    +
+\end{verbatim} + +\begin{verbatim} +
    +#for $animal_name in $frogQuery +
  • $animal_name
  • +#end for +
+\end{verbatim} + +\begin{verbatim} + +

There are too many monkeys!

+ +

There aren't enough monkeys!

+ +

There are just enough monkeys.

+
+\end{verbatim} + +\begin{verbatim} +#if $monkeys > $monkey_limit +

There are too many monkeys!

+#else if $monkeys < $minimum_monkeys +

There aren't enough monkeys!

+#else +

There are just enough monkeys.

+#end if +\end{verbatim} + +\begin{verbatim} + + + + + + + + + +
+ +
+\end{verbatim} + +\begin{verbatim} + +#set $evenRow = 0 +#for $file in $files('File') + #if $evenRow + + #set $evenRow = 0 + #else + + #set $evenRow = 1 + #end if + +#end for +
+ $file.title_or_id +
+\end{verbatim} + +The last example changed the name of \code{\$objectValues} to +\code{\$files} because that's what a Cheetah developer would write. +The developer would be responsible for ensuring \code{\$files} returned a +list (or tuple) of objects (or dictionaries) containing the attributes (or +methods or dictionary keys) `absolute\_url' and `title\_or\_id'. All these +names (`objectValues', `absolute\_url' and `title\_or\_id') are standard parts +of Zope, but in Cheetah the developer is in charge of writing them and giving +them a reasonable behaviour. + +Some of DTML's features are being ported to Cheetah, such as +\code{Cheetah.Tools.MondoReport}, which is based on the +\code{} tag. We are also planning an output filter as flexible as +the \code{} formatting options. However, neither of these are +complete yet. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. Zope Page Templates} +\label{comparisons.zpt} + +For a basic introduction to Zope Page Templates, please visit +\url{http://www.zope.org/Documentation/Articles/ZPT2}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. PHP's Smarty templates} +\label{comparisons.smarty} + +PHP (\url{http://www.php.net/}) is one of the few scripting languages +expressly designed for web servlets. However, it's also a full-fledged +programming language with libraries similar to Python's and Perl's. The +syntax and functions are like a cross between Perl and C plus some original +ideas (e.g.; a single array type serves as both a list and a dictionary, +\verb+$arr[]="value";+ appends to an array). + +Smarty (\url{http://smarty.php.net/}) is an advanced template engine for +PHP. ({\em Note:} this comparision is based on Smarty's on-line documentation. +The author has not used Smarty. Please send corrections or ommissions to the +Cheetah mailing list.) Like Cheetah, Smarty: + +\begin{itemize} +\item compiles to the target programming language (PHP). +\item has configurable delimeters. +\item passes if-blocks directly to PHP, so you can use any PHP expression in +them. +\item allows you to embed PHP code in a template. +\item has a caching framework (although it works quite differently). +\item can read the template definition from any arbitrary source. +\end{itemize} + +Features Smarty has that Cheetah lacks: +\begin{itemize} +\item Preprocessors, postprocessors and output filters. You can emulate a +preprocessor in Cheetah by running your template definition through a filter +program or function before Cheetah sees it. To emulate a postprocessor, run a +.py template module through a filter program/function. To emulate a Smarty +output filter, run the template output through a filter program/function. If +you want to use ``cheetah compile'' or ``cheetah fill'' in a pipeline, use +\code{-} as the input file name and \code{--stdout} to send the result to +standard output. Note that Cheetah uses the term ``output filter'' differently +than Smarty: Cheetah output filters (\code{\#filter}) operate on placeholders, +while Smarty output filters operate on the entire template output. There has +been a proposed \code{\#sed} directive that would operate on the entire output +line by line, but it has not been implemented. +\item Variable modifiers. In some cases, Python has equivalent string +methods (\code{.strip}, \code{.capitalize}, \code{.replace(SEARCH, REPL)}), +but in other cases you must wrap the result in a function call or write +a custom output filter (\code{\#filter}). +\item Certain web-specific functions, which can be emulated with +third-party functions. +\item The ability to ``plug in'' new directives in a modular way. Cheetah +directives are tightly bound to the compiler. However, third-party +{\em functions} can be freely imported and called from placeholders, and +{\em methods} can be mixed in via \code{\#extends}. Part of this is +because Cheetah distinguishes between functions and directives, while +Smarty treats them all as ``functions''. Cheetah's design does not +allow functions to have flow control effect outside the function +(e.g., \code{\#if} and \code{\#for}, which operate on template body lines), +so directives like these cannot be encoded as functions. +\item Configuration variables read from an .ini-style file. The +\code{Cheetah.SettingsManager} module can parse such a file, but you'd +have to invoke it manually. (See the docstrings in the module for +details.) In Smarty, this feature is used for +multilingual applications. In Cheetah, the developers maintain that everybody +has their own preferred way to do this (such as using Python's \code{gettext} +module), and it's not worth blessing one particular strategy in Cheetah since +it's easy enough to integrate third-party code around the template, or to add +the resulting values to the searchList. +\end{itemize} + +Features Cheetah has that Smarty lacks: +\begin{itemize} +\item Saving the compilation result in a Python (PHP) module for quick +reading later. +\item Caching individual placeholders or portions of a template. Smarty +caches only the entire template output as a unit. +\end{itemize} + +Comparisions of various Smarty constructs: +\begin{verbatim} +{assign var="name" value="Bob"} (#set has better syntax in the author's opinion) +counter (looks like equivalent to #for) +eval (same as #include with variable) +fetch: insert file content into output (#include raw) +fetch: insert URL content into output (no euqivalent, user can write + function calling urllib, call as $fetchURL('URL') ) +fetch: read file into variable (no equivalent, user can write function + based on the 'open/file' builtin, or on .getFileContents() in + Template.) +fetch: read URL content into variable (no equivalent, use above + function and call as: #set $var = $fetchURL('URL') +html_options: output an HTML option list (no equivalent, user can + write custom function. Maybe FunFormKit can help.) +html_select_date: output three dropdown controls to specify a date + (no equivalent, user can write custom function) +html_select_time: output four dropdown controls to specify a time + (no equvalent, user can write custom function) +math: eval calculation and output result (same as #echo) +math: eval calculation and assign to variable (same as #set) +popup_init: library for popup windows (no equivalent, user can write + custom method outputting Javascript) + + +Other commands: +capture (no equivalent, collects output into variable. A Python + program would create a StringIO instance, set sys.stdout to + it temporarily, print the output, set sys.stdout back, then use + .getvalue() to get the result.) +config_load (roughly analagous to #settings, which was removed + from Cheetah. Use Cheetah.SettingsManager manually or write + a custom function.) +include (same as #include, but can include into variable. + Variables are apparently shared between parent and child.) +include_php: include a PHP script (e.g., functions) + (use #extends or #import instead) +insert (same as #include not in a #cache region) +{ldelim}{rdelim} (escape literal $ and # with a backslash, + use #compiler-settings to change the delimeters) +literal (#raw) +php (``<% %>'' tags) +section (#for $i in $range(...) ) +foreach (#for) +strip (like the #sed tag which was never implemented. Strips + leading/trailing whitespace from lines, joins several lines + together.) + + +Variable modifiers: +capitalize ( $STRING.capitalize() ) +count_characters ( $len(STRING) ) +count_paragraphs/sentances/words (no equivalent, user can write function) +date_format (use 'time' module or download Egenix's mx.DateTime) +default ($getVar('varName', 'default value') ) +escape: html encode ($cgi.escape(VALUE) ) +escape: url encode ($urllib.quote_plus(VALUE) ) +escape: hex encode (no equivalent? user can write function) +escape: hex entity encode (no equivalent? user can write function) +indent: indent all lines of a var's output (may be part of future + #indent directive) +lower ($STRING.lower() ) +regex_replace ('re' module) +replace ($STRING.replace(OLD, NEW, MAXSPLIT) ) +spacify (#echo "SEPARATOR".join(SEQUENCE) ) +string_format (#echo "%.2f" % FLOAT , etc.) +strip_tags (no equivalent, user can write function to strip HTML tags, + or customize the WebSafe filter) +truncate (no equivalent, user can write function) +upper ($STRING.upper() ) +wordwrap ('writer' module, or a new module coming in Python 2.3) +\end{verbatim} + +Some of these modifiers could be added to the super output filter we +want to write someday. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. PHPLib's Template class} +\label{comparisons.php} + +PHPLib (\url(http://phplib.netuse.de/) is a collection of classes for various +web objects (authentication, shopping cart, sessions, etc), but what we're +interested in is the \code{Template} object. It's much more primitive than +Smarty, and was based on an old Perl template class. In fact, one of the +precursors to Cheetah was based on it too. Differences from Cheetah: + +\begin{itemize} +\item Templates consist of text with \code{\{placeholders\}} in braces. +\item Instead of a searchList, there is one flat namespace. Every variable + must be assigned via the \code{set\_var} method. However, you can pass + this method an array (dictionary) of several variables at once. +\item You cannot embed lookups or calculations into the template. Every + placeholder must be an exact variable name. +\item There are no directives. You must do all display logic (if, for, etc) + in the calling routine. +\item There is, however, a ``block'' construct. A block is a portion of text + between the comment markers \code{ \ldots + \ldots + + + +#block writeHeadTag + +$title +$metaTags +$stylesheetTags +$javascriptTags + +#end block writeHeadTag + +#end cache header +################# + +$bodyTag + +#block writeBody +This skeleton page has no flesh. Its body needs to be implemented. +#end block writeBody + + + +\end{verbatim} + +You can redefine any of the blocks defined in this template by writing a new +template that \code{\#extends} SkeletonPage. (As you remember, using +\code{\#extends} makes your template implement the \code{.writeBody()} +method instead of \code{.respond()} -- which happens to be the same method +SkeletonPage expects the page content to be (note the writeBody block in +SkeletonPage).) + +\begin{verbatim} +#def bodyContents +Here's my new body. I've got some flesh on my bones now. +#end def bodyContents +\end{verbatim} + +%% @@MO: Is this still accurate? Does the child template really need to put a +%% #def around its whole content? Or by implementing .writeBody() does it +%% automatically insert itself as the writeBody portion of +%% SkeletonPage? @@TR 2005-01-06: it happens automatically at the moment. + +All of the \$placeholders used in the \code{SkeletonPage} template definition +are attributes or methods of the \code{SkeletonPage} class. You can reimplement +them as you wish in your subclass. Please read the source code of the file +\code{src/Templates/\_SkeletonPage.py} before doing so. + +You'll need to understand how to use the following methods of the +\code{SkeletonPage} class: \code{\$metaTags()}, \code{\$stylesheetTags()}, +\code{\$javascriptTags()}, and \code{\$bodyTag()}. They take the data you +define in various attributes and renders them into HTML tags. + +\begin{itemize} +\item {\bf metaTags()} -- Returns a formatted vesion of the self.\_metaTags + dictionary, using the formatMetaTags function from + \code{\_SkeletonPage.py}. +\item {\bf stylesheetTags()} -- Returns a formatted version of the + \code{self.\_stylesheetLibs} and \code{self.\_stylesheets} dictionaries. + The keys in \code{self.\_stylesheets} must be listed in the order that + they should appear in the list \code{self.\_stylesheetsOrder}, to ensure + that the style rules are defined in the correct order. +\item {\bf javascriptTags()} -- Returns a formatted version of the + \code{self.\_javascriptTags} and \code{self.\_javascriptLibs} dictionaries. + Each value in \code{self.\_javascriptTags} should be a either a code string + to include, or a list containing the JavaScript version number and the code + string. The keys can be anything. The same applies for + \code{self.\_javascriptLibs}, but the string should be the SRC filename + rather than a code string. +\item {\bf bodyTag()} -- Returns an HTML body tag from the entries in the dict + \code{self.\_bodyTagAttribs}. +\end{itemize} + +The class also provides some convenience methods that can be used as +\$placeholders in your template definitions: + +\begin{itemize} +\item {\bf imgTag(self, src, alt='', width=None, height=None, border=0)} -- + Dynamically generate an image tag. Cheetah will try to convert the + ``\code{src}'' argument to a WebKit serverSidePath relative to the + servlet's location. If width and height aren't specified they are + calculated using PIL or ImageMagick if either of these tools are available. + If all your images are stored in a certain directory you can reimplement + this method to append that directory's path to the ``\code{src}'' argument. + Doing so would also insulate your template definitions from changes in your + directory structure. +\end{itemize} + + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_src/links.tex b/docs/users_guide_src/links.tex new file mode 100755 index 0000000..1ec2f6c --- /dev/null +++ b/docs/users_guide_src/links.tex @@ -0,0 +1,112 @@ +\section{Useful Web Links} +\label{links} + +See the wiki for more links. (The wiki is also updated more often than this +chapter is.) + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah Links} +\label{links.cheetah} + +\begin{description} +\item[Home Page] -- \url{http:www.CheetahTemplate.org/} + +\item[On-line Documentation] -- \url{http:www.CheetahTemplate.org/learn.html} + +\item[SourceForge Project Page] -- \url{http:sf.net/projects/cheetahtemplate/} + +\item[Mailing List Subscription Page] -- + \url{http://lists.sourceforge.net/lists/listinfo/cheetahtemplate-discuss} + +\item[Mailing List Archive @ Geocrawler] -- + \url{http://www.geocrawler.com/lists/3/SourceForge/12986/0/} + +\item[Mailing List Archive @ Yahoo] -- + \url{http://groups.yahoo.com/group/cheetah-archive/} + +\item[CVS Repository] -- \url{http://sourceforge.net/cvs/?group\_id=28961} + +\item[CVS-commits archive] -- + \url{http://www.geocrawler.com/lists/3/SourceForge/13091/0/} + +\end{description} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Third-party Cheetah Stuff} +\label{links.thirdParty} + +\begin{itemize} +\item Steve Howell has written a photo viewer using Python. + \url{http://mountainwebtools.com/PicViewer/install.htm} +\end{itemize} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Webware Links} +\label{links.webware} + +\begin{description} +\item[Home Page] -- \url{http://webware.sf.net/} + +\item[On-line Documentation] -- \url{http://webware.sf.net/Webware/Docs/} + +\item[SourceForge Project Page] -- \url{http://sf.net/projects/webware/} + +\item[Mailing List Subscription Page] -- + \url{http://lists.sourceforge.net/lists/listinfo/webware-discuss} + +\end{description} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Python Links} +\label{links.python} + +\begin{description} +\item[Home Page] -- \url{http://www.python.org/} +\item[On-line Documentation] -- \url{http://www.python.org/doc/} +\item[SourceForge Project Page] -- \url{http://sf.net/projects/python/} +\item[The Vaults of Parnassus: Python Resources] -- + \url{http://www.vex.net/parnassus/} +\item[Python Cookbook] -- \url{http://aspn.activestate.com/ASPN/Cookbook/Python} +\end{description} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Other Useful Links} +\label{links.other} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Python Database Modules and Open Source Databases} +\label{links.database} + +\begin{description} +\item[Python Database Topic Guide] -- \url{http://python.org/topics/database/} +\item[PostgreSQL Database] -- \url{http://www.postgresql.org/index.html} +\item[MySQL Database] -- \url{http://www.mysql.com/} +\item[A comparison of PostgreSQL and MySQL] -- + \url{http://phpbuilder.com/columns/tim20001112.php3} +\end{description} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Other Template Systems} +\label{links.other.templateSystems} + +\begin{description} +\item[Chuck's ``Templates'' Summary Page] -- \url{http://webware.sf.net/Papers/Templates/} +\end{description} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Other Internet development frameworks} +\label{links.internet} + +\begin{description} +\item[ZOPE (Z Object Publishing Environment)] -- \url{http://zope.org/} +\item[Server Side Java] -- \url{http://jakarta.apache.org/} +\item[PHP] -- \url{http://php.net/} +\item[IBM Websphere] -- \url{http://www.ibm.com/websphere/} +\item[Coldfusion and Spectra] -- \url{http://www.macromedia.com/} +\end{description} + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_src/moreverb.sty b/docs/users_guide_src/moreverb.sty new file mode 100755 index 0000000..92e34bb --- /dev/null +++ b/docs/users_guide_src/moreverb.sty @@ -0,0 +1,197 @@ +%%% moreverb.sty +%%% AJCD 20 Sep 91 +%%% adds various verbatim environments using Rainer Sch\"opf's new verbatim +%%% environment. + + +%%% Marginal hacks (RF) to work `properly' with 2e +\def\filedate{1994/12/13} +\def\fileversion{v2.0} +% +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{moreverb} + [\filedate\space \fileversion\space + LaTeX2e package for `more' verbatim enhancements] +\typeout{Package: `moreverb' + \fileversion \space <\filedate> (RF, after AJCD and RmS)} +%\typeout{English Documentation \@spaces <\docdate>} % oh no there isn't + +%%% load verbatim style if not already loaded. +\@ifundefined{verbatim@processline}{\RequirePackage{verbatim}}{} + +%%% verbatimwrite writes all text in its body to a file, the name of which it +%%% is given as an argument. Written by RmS. +\newwrite \verbatim@out +\def\verbatimwrite#1{% + \@bsphack + \immediate\openout \verbatim@out #1 + \let\do\@makeother\dospecials + \catcode`\^^M\active \catcode`\^^I=12 + \def\verbatim@processline{% + \immediate\write\verbatim@out + {\the\verbatim@line}}% + \verbatim@start} + +\def\endverbatimwrite{% + \immediate\closeout\verbatim@out + \@esphack} + +%%% Auxiliary macros and counters for expanding tabs. Use by listing and +%%% verbatimtab environments. +\newcount\tab@position \newcount\tab@size +\newcount\verbatimtabsize \verbatimtabsize=8 +\def\@xobeytab{\leavevmode\penalty\@M + {\loop\ \global\advance\tab@position-1 \ifnum\tab@position>0 \repeat}} +\begingroup + \catcode`\^^I=\active + \gdef\@vobeytabs{\catcode`\^^I\active\let^^I\@xobeytab}% +\endgroup +\def\verbatim@tabexpand#1{% + \ifx#1\@nil \let\next\par \else + \ifx#1\@xobeysp \@xobeysp\advance\tab@position-1 \else + \ifx#1\@xobeytab \@xobeytab\else + #1\advance\tab@position-1 + \fi\fi + \ifnum\tab@position=0 \tab@position\tab@size \fi + \let\next\verbatim@tabexpand + \fi\next +} + +%%% listing defines a verbatim environment with numbered lines; it takes an +%%% optional argument specifying the number of lines between numbered +%%% lines, and a mandatory argument specifying the starting line. listingcont +%%% continues from the place where listing left off. +%%% The style in which the label is set can be altered by re-defining +%%% \listinglabel. * versions are provided. +\newcount\listing@line \listing@line=1 \newcount\listing@step \listing@step=1 +% Adding an \hbox in front of the line causes a line break, so I go +% through this rigmarole to get the lines aligned nicely. I probably +% missed some obvious reason why \hboxes don't work. +\def\listinglabel#1{\rlap{\small\rm\the#1}\hskip2.5em} +\def\thelisting@line{% + \setbox0\hbox{\listinglabel\listing@line}% + \@tempcnta=\listing@line + \divide\@tempcnta\listing@step \multiply\@tempcnta\listing@step + \ifnum\listing@line=1 \unhbox0 + \else \ifnum\@tempcnta=\listing@line \unhbox0 + \else \hskip\wd0 + \fi\fi} +\def\listing{\@ifnextchar[{\@listing}{\@listing[1]}} +\def\@listing[#1]#2{% + \global\listing@line=#2\global\listing@step=#1\listingcont} +\def\listingcont{% + \tab@size=\verbatimtabsize + \def\verbatim@processline{\tab@position\tab@size + \thelisting@line \global\advance\listing@line1 + \expandafter\verbatim@tabexpand\the\verbatim@line\@nil}% + \@verbatim\frenchspacing\@vobeyspaces\@vobeytabs\verbatim@start} +\let\endlisting=\endtrivlist +\let\endlistingcont=\endtrivlist +\@namedef{listing*}{\@ifnextchar[{\@listingstar}{\@listingstar[1]}} +\def\@listingstar[#1]#2{% + \global\listing@line=#2\global\listing@step=#1\relax + \csname listingcont*\endcsname} +\@namedef{listingcont*}{% + \def\verbatim@processline{% + \thelisting@line \global\advance\listing@line1 + \the\verbatim@line\par}% + \@verbatim\verbatim@start} +\expandafter\let\csname endlisting*\endcsname =\endtrivlist +\expandafter\let\csname endlistingcont*\endcsname =\endtrivlist + +%%% file input version of listing +\def\listinginput{% + \@ifnextchar[{\@listinginput}{\@listinginput[1]}} +{\catcode`\~=\active \lccode`\~=`\^^M \lccode`\N=`\N + \lowercase{% + \gdef\@listinginput[#1]#2#3{\begingroup + \global\listing@line=#2\global\listing@step=#1 + \tab@size=\verbatimtabsize + \def\verbatim@processline{\tab@position\tab@size + \thelisting@line \global\advance\listing@line1 + \expandafter\verbatim@tabexpand\the\verbatim@line\@nil}% + \@verbatim\frenchspacing\@vobeyspaces\@vobeytabs + \def\verbatim@addtoline##1~{% + \verbatim@line\expandafter{\the\verbatim@line##1}}% + \openin\verbtab@in=#3 + \ifeof\verbtab@in\typeout{No file #3.}\else + \verbtab@oktrue + \loop + \read\verbtab@in to \verbtab@line + \ifeof\verbtab@in\verbtab@okfalse\else + \expandafter\verbatim@addtoline\verbtab@line + \verbatim@processline + \verbatim@startline + \fi + \ifverbtab@ok\repeat + \closein\verbtab@in\fi + \endtrivlist\endgroup\@doendpe}}} + +%%% verbatimcmd is a verbatim environment with the exception of the escape and +%%% grouping characters \, {, }. +\def\verbatimcmd{% + \@verbatim \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 + \frenchspacing\@vobeyspaces\verbatim@start +} +\def\endverbatimcmd{% + \let\par\relax + \def\verbatim@{\endtrivlist\endgroup}% + \begingroup} + +%%% boxedverbatim produces a verbatim environment in a framed box. +%%% written by Victor Eijkhout +\def\boxedverbatim{% + % redefine `processline' to produce only a line as wide + % as the natural width of the line + \def\verbatim@processline{% + {\setbox0=\hbox{\the\verbatim@line}% + \hsize=\wd0 \the\verbatim@line\par}}% + % save the verbatim code in a box + \setbox0=\vbox\bgroup \verbatim +} +\def\endboxedverbatim{% + \endverbatim + \egroup % close the box and `fbox' it + \fbox{\box0}% <<<=== change here for centering,... +} + +%%% verbatimtab is a verbatim environment which expands tab characters; it +%%% takes an optional argument specifying the width of tab stops +\def\verbatimtab{\futurelet\next\@verbatimtab} +\def\@verbatimtab{\if\next[ \let\next\@@verbatimtab\else + \def\next{\@@verbatimtab[\the\verbatimtabsize]}\fi\next} +\def\@@verbatimtab[#1]{% + \do@verbatimtab{#1}{% + \@verbatim\frenchspacing\@vobeyspaces\@vobeytabs\verbatim@start}% +} +\def\do@verbatimtab#1#2{% + \tab@size=#1 + \def\verbatim@processline{\tab@position\tab@size + \expandafter\verbatim@tabexpand\the\verbatim@line\@nil}#2 +} +\let\endverbatimtab=\endtrivlist + +%%% file input version of verbatimtab +\newread\verbtab@in \newif\ifverbtab@ok +\def\verbatimtabinput{% + \@ifnextchar[{\@verbatimtabinput}{\@verbatimtabinput[\the\verbatimtabsize]}} +{\catcode`\~=\active \lccode`\~=`\^^M \lccode`\N=`\N + \lowercase{% + \gdef\@verbatimtabinput[#1]#2{\begingroup + \do@verbatimtab{#1}{% + \@verbatim\frenchspacing\@vobeyspaces\@vobeytabs}% + \def\verbatim@addtoline##1~{% + \verbatim@line\expandafter{\the\verbatim@line##1}}% + \openin\verbtab@in=#2 + \ifeof\verbtab@in\typeout{No file #2.}\else + \verbtab@oktrue + \loop + \read\verbtab@in to \verbtab@line + \ifeof\verbtab@in\verbtab@okfalse\else + \expandafter\verbatim@addtoline\verbtab@line + \verbatim@processline + \verbatim@startline + \fi + \ifverbtab@ok\repeat + \closein\verbtab@in\fi + \endtrivlist\endgroup\@doendpe}}} diff --git a/docs/users_guide_src/nonHtml.tex b/docs/users_guide_src/nonHtml.tex new file mode 100755 index 0000000..b618ab0 --- /dev/null +++ b/docs/users_guide_src/nonHtml.tex @@ -0,0 +1,17 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Non-HTML Output} +\label{nonHTML} + +Cheetah can also output any other text format besides HTML. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Python source code} +\label{nonHTML.python} + +To be written. We're in the middle of working on an autoindenter to +make it easier to encode Python indentation in a Cheetah template. + +% Local Variables: +% TeX-master: "users_guide" +% End: +%# vim: sw=4 ts=4 expandtab diff --git a/docs/users_guide_src/optikLicense.tex b/docs/users_guide_src/optikLicense.tex new file mode 100755 index 0000000..db63682 --- /dev/null +++ b/docs/users_guide_src/optikLicense.tex @@ -0,0 +1,43 @@ +\section{Optik license} +\label{optikLicense} + +The optik package (Cheetah.Utils.optik) is based on Optik 1.3, +\url{http://optik.sourceforge.net/}, \copyright 2001 Gregory P Ward +$<$gward@python.net$>$. It's unmodified from the original version except +the \code{import} statements, which have been adjusted to make them work in +this location. The following license applies to optik: + +\begin{quotation} +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +\begin{itemize} +\item Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +\item Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +\item Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +\end{itemize} + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\end{quotation} + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_src/otherHtml.tex b/docs/users_guide_src/otherHtml.tex new file mode 100755 index 0000000..89fd58a --- /dev/null +++ b/docs/users_guide_src/otherHtml.tex @@ -0,0 +1,95 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{non-Webware HTML output} +\label{otherHTML} + +Cheetah can be used with all types of HTML output, not just with Webware. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Static HTML Pages} +\label{otherHTML.static} + +Some sites like Linux Gazette (\url{http://www.linuxgazette.com/}) require +completely static pages because they are mirrored on servers running completely +different software from the main site. Even dynamic sites may have one or +two pages that are static for whatever reason, and the site administrator may +wish to generate those pages from Cheetah templates. + +There's nothing special here. Just create your templates as usual. Then +compile and fill them whenever the template definition changes, and fill them +again whenever the placeholder values change. You may need an extra step to +copy the .html files to their final location. A Makefile (chapter +\ref{tips.Makefile}) can help encapsulate these steps. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{CGI scripts} +\label{otherHTML} + +Unlike Webware servlets, which don't have to worry about the HTTP headers, +CGI scripts must emit their own headers. To make a template CGI aware, add +this at the top: +\begin{verbatim} +#extends Cheetah.Tools.CGITemplate +#implements respond +$cgiHeaders#slurp +\end{verbatim} + +Or if your template is inheriting from a Python class: +\begin{verbatim} +#extends MyPythonClass +#implements respond +$cgiHeaders#slurp +\end{verbatim} + +A sample Python class: +\begin{verbatim} +from Cheetah.Tools import CGITemplate +class MyPythonClass(CGITemplate): + def cgiHeadersHook(self): + return "Content-Type: text/html; charset=koi8-r\n\n" +\end{verbatim} + + +Compile the template as usual, put the .py template module in your +cgi-bin directory and give it execute permission. \code{.cgiHeaders()} is +a ``smart'' method that outputs the headers if the module is called as a +CGI script, or outputs nothing if not. Being ``called as a CGI script'' +means the environmental variable \code{REQUEST\_METHOD} exists and +\code{self.isControlledByWebKit} is false. If you don't agree with that +definition, override \code{.isCgi()} and provide your own. + +The default header is a simple \verb+Content-type: text/html\n\n+, which works +with all CGI scripts. If you want to customize the headers (e.g., to +specify the character set), override \code{.cgiHeadersHook()} and return +a string containing all the headers. Don't forget to include the extra +newline at the end of the string: the HTTP protocol requires this empty +line to mark the end of the headers. + +To read GET/POST variables from form input, use the \code{.webInput()} method +(section \ref{webware.webInput}), or extract them yourself using Python's +\code{cgi} module or your own function. Although \code{.webInput()} was +originally written for Webware servlets, it now handles CGI scripts too. There +are a couple behavioral differences between CGI scripts and Webware servlets +regarding input variables: + +\begin{enumerate} +\item CGI scripts, using Python's \code{cgi} module, believe + \code{REQUEST\_METHOD} and recognize {\em either} GET variables {\em or} + POST variables, not both. Webware servlets, doing additional processing, + ignore \code{REQUEST\_METHOD} and recognize both, like PHP does. +\item Webware servlets can ask for cookies or session variables instead of + GET/POST variables, by passing the argument \code{src='c'} or + \code{src='s'}. CGI scripts get a \code{RuntimeError} if they try to do + this. +\end{enumerate} + +If you keep your .tmpl files in the same directory as your CGI scripts, make +sure they don't have execute permission. Apache at least refuses to serve +files in a \code{ScriptAlias} directory that don't have execute permission. + + +% Local Variables: +% TeX-master: "users_guide" +% End: +%# vim: sw=4 ts=4 expandtab diff --git a/docs/users_guide_src/output.tex b/docs/users_guide_src/output.tex new file mode 100755 index 0000000..742291e --- /dev/null +++ b/docs/users_guide_src/output.tex @@ -0,0 +1,548 @@ +\section{Generating, Caching and Filtering Output} +\label{output} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Output from complex expressions: \#echo} +\label{output.echo} + +Syntax: +\begin{verbatim} +#echo EXPR +\end{verbatim} + +The \code{\#echo} directive is used to echo the output from expressions that +can't be written as simple \$placeholders. + +\begin{verbatim} +Here is my #echo ', '.join(['silly']*5) # example +\end{verbatim} + +This produces: + +\begin{verbatim} +Here is my silly, silly, silly, silly, silly example. +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Executing expressions without output: \#silent} +\label{output.silent} + +Syntax: +\begin{verbatim} +#silent EXPR +\end{verbatim} + +\code{\#silent} is the opposite of \code{\#echo}. It executes an expression +but discards the output. + +\begin{verbatim} +#silent $myList.reverse() +#silent $myList.sort() +Here is #silent $covertOperation() # nothing +\end{verbatim} + +If your template requires some Python code to be executed at the beginning; +(e.g., to calculate placeholder values, access a database, etc), you can put +it in a "doEverything" method you inherit, and call this method using +\code{\#silent} at the top of the template. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{One-line \#if} +\label{output.oneLineIf} + +Syntax: +\begin{verbatim} +#if EXPR1 then EXPR2 else EXPR3# +\end{verbatim} + +The \code{\#if} flow-control directive (section \ref{flowControl.if}) has a +one-line counterpart akin to Perl's and C's \code{?:} operator. +If \code{EXPR1} is true, it evaluates \code{EXPR2} and outputs the result (just +like \code{\#echo\ EXPR2\#}). Otherwise it evaluates \code{EXPR3} and outputs +that result. This directive is short-circuiting, meaning the expression that +isn't needed isn't evaluated. + +You MUST include both 'then' and 'else'. If this doesn't work for you or you +don't like the style use multi-line \code{\#if} directives (section +\ref{flowControl.if}). + +The trailing \code{\#} is the normal end-of-directive character. As usual +it may be omitted if there's nothing after the directive on the same line. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Caching Output} +\label{output.caching} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Caching individual placeholders} +\label{output.caching.placeholders} + +By default, the values of each \$placeholder is retrieved and +interpolated for every request. However, it's possible to cache the values +of individual placeholders if they don't change very often, in order to +speed up the template filling. + +To cache the value of a single \code{\$placeholder}, add an asterisk after the +\$; e.g., \code{\$*var}. The first time the template is +filled, \code{\$var} is looked up. Then whenever the template is filled again, +the cached value is used instead of doing another lookup. + +The \code{\$*} format caches ``forever''; that is, as long as the template +instance remains in memory. It's also possible to cache for a certain time +period using the form \code{\$**variable}, where \code{} is +the interval. The time interval can be specified in seconds (5s), minutes +(15m), hours (3h), days (2d) or weeks (1.5w). The default is minutes. + +\begin{verbatim} + +$title + + +$var ${var} ## dynamic - will be reinterpolated for each request +$*var2 $*{var2} ## static - will be interpolated only once at start-up +$*5*var3 $*5*{var3} ## timed refresh - will be updated every five minutes. + + + +\end{verbatim} + +Note that ``every five minutes'' in the example really means every five +minutes: the variable is looked up again when the time limit is reached, +whether the template is being filled that frequently or not. Keep this in +mind when setting refresh times for CPU-intensive or I/O intensive +operations. + +If you're using the long placeholder syntax, \verb+${}+, the braces go only +around the placeholder name: \verb+$*.5h*{var.func('arg')}+. + +Sometimes it's preferable to explicitly invalidate a cached item whenever +you say so rather than at certain time intervals. You can't do this with +individual placeholders, but you can do it with cached regions, which will +be described next. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Caching entire regions} +\label{output.caching.regions} + +Syntax: +\begin{verbatim} +#cache [id=EXPR] [timer=EXPR] [test=EXPR] +#end cache +\end{verbatim} + +The \code{\#cache} directive is used to cache a region of +content in a template. The region is cached as a single unit, after +placeholders and directives inside the region have been evaluated. If there +are any \code{\$**var} placholders inside the cache +region, they are refreshed only when {\em both} the cache region {\em and} the +placeholder are simultaneously due for a refresh. + +Caching regions offers more flexibility than caching individual placeholders. +You can specify the refresh interval using a placeholder or +expression, or refresh according to other criteria rather than a certain +time interval. + +\code{\#cache} without arguments caches the region statically, the same +way as \code{\$*var}. The region will not be automatically refreshed. + +To refresh the region at an interval, use the \code{timer=EXPRESSION} argument, +equivalent to \code{\$**}. The expression should evaluate to a +number or string that is a valid interval (e.g., 0.5, '3m', etc). + +To refresh whenever an expression is true, use \code{test=EXPRESSION}. +The expression can be a method/function returning true or false, a boolean +placeholder, several of these joined by \code{and} and/or \code{or}, or any +other expression. If the expression contains spaces, it's easier to +read if you enclose it in \code{()}, but this is not required. + +To refresh whenever you say so, use \code{id=EXPRESSION}. Your program can +then call \code{.refreshCache(ID)} whenever it wishes. This is useful if the +cache depends on some external condition that changes infrequently but has just +changed now. + +You can combine arguments by separating them with commas. For instance, you can +specify both \code{id=} and \code{interval=}, or \code{id=} and \code{test=}. +(You can also combine interval and test although it's not very useful.) +However, repeating an argument is undefined. + +\begin{verbatim} +#cache +This is a static cache. It will not be refreshed. +$a $b $c +#end cache + +#cache timer='30m', id='cache1' +#for $cust in $customers +$cust.name: +$cust.street - $cust.city +#end for +#end cache + +#cache id='sidebar', test=$isDBUpdated +... left sidebar HTML ... +#end cache + +#cache id='sidebar2', test=($isDBUpdated or $someOtherCondition) +... right sidebar HTML ... +#end cache +\end{verbatim} + + +The \code{\#cache} directive cannot be nested. + +We are planning to add a \code{'varyBy'} keyword argument in the future that +will allow a separate cache instances to be created for a variety of conditions, +such as different query string parameters or browser types. This is inspired by +ASP.net's varyByParam and varyByBrowser output caching keywords. + +% @@MO: Can we cache by Webware sessions? What about sessions where the +% session ID is encoded as a path prefix in the URI? Need examples. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#raw} +\label{output.raw} + +Syntax: +\begin{verbatim} +#raw +#end raw +\end{verbatim} + +Any section of a template definition that is inside a \code{\#raw \ldots +\#end raw} tag pair will be printed verbatim without any parsing of +\$placeholders or other directives. This can be very useful for debugging, or +for Cheetah examples and tutorials. + +\code{\#raw} is conceptually similar to HTML's \code{
} tag and LaTeX's
+\code{\\verbatim\{\}} tag, but unlike those tags, \code{\#raw} does not cause
+the body to appear in a special font or typeface.  It can't, because Cheetah
+doesn't know what a font is.  
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{\#include}
+\label{output.include}
+
+Syntax:
+\begin{verbatim}
+#include [raw] FILENAME_EXPR
+#include [raw] source=STRING_EXPR
+\end{verbatim}
+
+The \code{\#include} directive is  used to include text from outside the
+template definition.  The text can come from an external file or from a
+\code{\$placeholder} variable.  When working with external files, Cheetah will
+monitor for changes to the included file and update as necessary.  
+
+This example demonstrates its use with external files:
+\begin{verbatim}
+#include "includeFileName.txt"
+\end{verbatim}
+The content of "includeFileName.txt" will be parsed for Cheetah syntax.
+
+And this example demonstrates use with \code{\$placeholder} variables:
+\begin{verbatim}
+#include source=$myParseText
+\end{verbatim}
+The value of \code{\$myParseText} will be parsed for Cheetah syntax. This is not
+the same as simply placing the \$placeholder tag ``\code{\$myParseText}'' in
+the template definition.  In the latter case, the value of \$myParseText would
+not be parsed.
+
+By default, included text will be parsed for Cheetah tags.  The argument
+``\code{raw}'' can be used to suppress the parsing.
+
+\begin{verbatim}
+#include raw "includeFileName.txt"
+#include raw source=$myParseText
+\end{verbatim}
+
+Cheetah wraps each chunk of \code{\#include} text inside a nested
+\code{Template} object.  Each nested template has a copy of the main
+template's searchList.  However, \code{\#set} variables are visible
+across includes only if the defined using the \code{\#set global} keyword.
+
+All directives must be balanced in the include file.  That is, if you start
+a \code{\#for} or \code{\#if} block inside the include, you must end it in
+the same include.  (This is unlike PHP, which allows unbalanced constructs
+in include files.)
+
+% @@MO: What did we decide about #include and the searchList?  Does it really
+% use a copy of the searchList, or does it share the searchList with the
+% parent?
+
+% @@MO: deleted
+%These nested templates share the same \code{searchList}
+%as the top-level template. 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{\#slurp}
+\label{output.slurp}
+
+Syntax:
+\begin{verbatim}
+#slurp
+\end{verbatim}
+
+The \code{\#slurp} directive eats up the trailing newline on the line it
+appears in, joining the following line onto the current line.
+
+
+It is particularly useful in \code{\#for} loops:
+\begin{verbatim}
+#for $i in range(5)
+$i #slurp
+#end for
+\end{verbatim}
+outputs:
+\begin{verbatim}
+0 1 2 3 4
+\end{verbatim}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{\#indent}
+\label{output.indent}
+
+This directive is not implemented yet.  When/if it's completed, it will allow
+you to 
+\begin{enumerate}
+\item indent your template definition in a natural way (e.g., the bodies
+    of \code{\#if} blocks) without affecting the output
+\item add indentation to output lines without encoding it literally in the
+    template definition.  This will make it easier to use Cheetah to produce
+    indented source code programmatically (e.g., Java or Python source code).  
+\end{enumerate}
+
+There is some experimental code that recognizes the \code{\#indent}
+directive with options, but the options are purposely undocumented at this
+time.  So pretend it doesn't exist.  If you have a use for this feature
+and would like to see it implemented sooner rather than later, let us know
+on the mailing list.
+
+The latest specification for the future \code{\#indent} directive is in the
+TODO file in the Cheetah source distribution.
+
+% @@MO: disabled because it's not implemented and the spec is changing
+% \code{\#indent} decouples the indentation in the template definition from the
+% indentation in the output.  Normally, Cheetah outputs indentation exactly as
+% it sees it, no matter whether the indentation is on the first line of a 
+% paragraph, in front of a directive, or wherever.  \code{\#indent} has two main
+% uses:
+% \begin{enumerate}
+% \item To strip all indentation from source lines.  This lets you indent
+%     multiline directives (e.g., \code{\#if}, \code{\#for}) in a natural way
+%     without having that indentation appear in the output.
+% \item To indent every text line in the output according to a user-specified
+%     ``indentation level'', independent of whatever indentation the source lines
+%     may have.  This is useful for producing Python output, or any language that
+%     requires strict indentation levels at certain places.  To accomplish this,
+%     Cheetah adds a call to an indentation method at the beginning of every
+%     affected source line.
+% \end{enumerate}
+% 
+% To accomplish the first part, Cheetah removes leading whitespace from the
+% affected source lines before the compiler see them.  To accomplish the second
+% part, Cheetah keeps track of the current indentation level, a value you have
+% full control over.  At the beginning of every affected text line, Cheetah calls
+% a method that outputs the appropriate indentation string.  This affects only
+% lines in the template definition itself, not multiline placeholder values.  
+% See the \code{Indent} filter below to indent multiline placeholder values.
+% 
+% All \code{\#indent} commands operate on the lines physically below them in
+% the template definition until the next \code{\#indent}, regardless of scope.
+% This means they work thorugh all other directives (\code{\#def}, \code{\#for},
+% \code{\#if}, etc) -- so that if you turn on indentation inside a \code{\#def},
+% it remains in effect past the \code{\#end def}.
+% 
+% The following commands turn indentation on and off:
+% \begin{description}
+% \item{\code{\#indent on}}  Strip leading whitespace and add indentation to the
+%     following lines.  This fulfills use \#2 above.
+% \item{\code{\#indent off}} Do not strip leading whitespace or add indentation.
+%     This is Cheetah's default behavior.
+% \item{\code{\#indent strip}}  Strip leading whitespace but do {\em not} add
+%     indentation.  This fulfills use \#1 above.
+% \end{description}
+% 
+% Indentation by default uses real tabs.  But you can change the indentation
+% string thus:
+% \begin{verbatim}
+% ## Output four spaces for each indentation level.
+% #indent chars '    '
+% ## Output the mail reply prefix for each indentation level.
+% #indent chars '> '
+% ## Use a placeholder.
+% #indent chars $indentChars
+% ## Return to the default behavior.
+% #indent chars '\t'
+% \end{verbatim}
+% 
+% 
+% The following commands change the indentation level, which is a non-negative
+% integer initially at zero.  All of these commands implicitly do an 
+% \code{\#indent on}:
+% \begin{description}
+% \item{\code{\#indent ++}}  Increment the current indentation level.
+% \item{\code{\#indent --}}  Decrement the current indentation level.
+% \item{\code{\#indent +3}}  Add three indentation levels (or any number).
+% \item{\code{\#indent -3}}  Subtract three indentation levels (or any number).
+% \item{\code{\#indent =3}}   Set the indentation level to 3.
+% \item{\code{\#indent push +2}}  Save the current indentation level on a stack
+%     and add two.  
+% \item{\code{\#indent pop}}  Return to the most recently pushed level.  Raise
+%     \code{IndentationStackEmptyError} if there is no previous level.
+% \end{description}
+% 
+% The expressions after \code{+}/\code{-}/\code{=} may be numeric literals or
+% Cheetah expressions.  The effect is undefined if the value is negative.  There
+% may be whitespace after the \code{+}/\code{-}/\code{=} symbol.
+% The initial implementation uses a simple preprocessor that doesn't understand
+% newline characters in expressions.  \code{\\n} is fine, but not a real newline.
+% 
+% To indent multiline placeholder values using the current indentation level,
+% use the \code{Indent} filter:
+% \begin{verbatim}
+% #filter Indent
+% \end{verbatim}
+% It works like the default filter but adds indentation after every newline.  It
+% does not strip any leading whitespace.  It hooks into \code{\$self.\_indenter},
+% defined in \code{Cheetah.Utils.Indenter}.  This object keeps track of the
+% current indentation level.  Specifically, the filter calls
+% \code{\$self.\_indent()}, which is a shortcut to the indenter's
+% \code{.indent()} method.  This is the same thing \code{\#indent} does.
+% However, the filter is usable even when indentation is in
+% \code{off} or \code{strip} mode.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Ouput Filtering and \#filter}
+\label{output.filter}
+
+Syntax:
+\begin{verbatim}
+#filter FILTER_CLASS_NAME
+#filter $PLACEHOLDER_TO_A_FILTER_INSTANCE
+#filter None
+\end{verbatim}
+
+
+Output from \$placeholders is passed through an ouput filter.  The default
+filter merely returns a string representation of the placeholder value,
+unless the value is \code{None}, in which case the filter returns an empty
+string.  Only top-level placeholders invoke the filter; placeholders inside
+expressions do not.
+
+Certain filters take optional arguments to modify their behaviour.  To pass
+arguments, use the long placeholder syntax and precede each filter argument by
+a comma.  By convention, filter arguments don't take a \code{\$} prefix, to
+avoid clutter in the placeholder tag which already has plenty of dollar signs.
+For instance, the MaxLen filter takes an argument 'maxlen':
+
+\begin{verbatim}
+${placeholderName, maxlen=20}
+${functionCall($functionArg), maxlen=$myMaxLen}
+\end{verbatim}
+
+To change the output filter, use the \code{'filter'} keyword to the
+\code{Template} class constructor, or the \code{\#filter}
+directive at runtime (details below).  You may use \code{\#filter} as often as
+you wish to switch between several filters, if certain \code{\$placeholders}
+need one filter and other \code{\$placeholders} need another.
+
+The standard filters are in the module \code{Cheetah.Filters}.  Cheetah
+currently provides:
+
+\begin{description}
+\item{\code{Filter}}
+     \\ The default filter, which converts None to '' and everything else to
+     \code{str(whateverItIs)}.  This is the base class for all other filters,
+     and the minimum behaviour for all filters distributed with Cheetah.
+\item{\code{ReplaceNone}}
+     \\ Same.
+\item{\code{MaxLen}}
+     \\ Same, but truncate the value if it's longer than a certain length.
+     Use the 'maxlen' filter argument to specify the length, as in the
+     examples above.  If you don't specify 'maxlen', the value will not be
+     truncated.
+\item{\code{Pager}}
+     \\ Output a "pageful" of a long string.  After the page, output HTML
+     hyperlinks to the previous and next pages.  This filter uses several
+     filter arguments and environmental variables, which have not been 
+     documented yet.
+\item{\code{WebSafe}}
+     \\ Same as default, but convert HTML-sensitive characters ('$<$', '\&',
+     '$>$')
+     to HTML entities so that the browser will display them literally rather
+     than interpreting them as HTML tags.  This is useful with database values
+     or user input that may contain sensitive characters.  But if your values
+     contain embedded HTML tags you want to preserve, you do not want this 
+     filter.
+     
+     The filter argument 'also' may be used to specify additional characters to
+     escape.  For instance, say you want to ensure a value displays all on one
+     line.  Escape all spaces in the value with '\ ', the non-breaking
+     space:
+\begin{verbatim}
+${$country, also=' '}}
+\end{verbatim}
+\end{description}
+
+To switch filters using a class object, pass the class using the
+{\bf filter} argument to the Template constructor, or via a placeholder to the
+\code{\#filter} directive: \code{\#filter \$myFilterClass}.  The class must be
+a subclass of \code{Cheetah.Filters.Filter}.  When passing a class object, the
+value of {\bf filtersLib} does not matter, and it does not matter where the
+class was defined.
+
+To switch filters by name, pass the name of the class as a string using the
+{\bf filter} argument to the Template constructor, or as a bare word (without
+quotes) to the \code{\#filter} directive: \code{\#filter TheFilter}.  The
+class will be looked up in the {\bf filtersLib}.
+
+The filtersLib is a module containing filter classes, by default
+\code{Cheetah.Filters}.  All classes in the module that are subclasses of
+\code{Cheetah.Filters.Filter} are considered filters.  If your filters are in
+another module, pass the module object as the {\bf filtersLib} argument to the
+Template constructor.  
+
+Writing a custom filter is easy: just override the \code{.filter} method.
+\begin{verbatim}
+    def filter(self, val, **kw):     # Returns a string.
+\end{verbatim}
+Return the {\em string} that should be output for `val'.  `val' may be any
+type.  Most filters return `' for \code{None}.  Cheetah passes one keyword
+argument: \verb+kw['rawExpr']+ is the placeholder name as it appears in
+the template definition, including all subscripts and arguments.  If you use
+the long placeholder syntax, any options you pass appear as keyword
+arguments.  Again, the return value must be a string.
+
+You can always switch back to the default filter this way:
+\code{\#filter None}.  This is easy to remember because "no filter" means the
+default filter, and because None happens to be the only object the default
+filter treats specially.
+
+We are considering additional filters; see
+\url{http://webware.colorstudy.net/twiki/bin/view/Cheetah/MoreFilters}
+for the latest ideas.
+
+%% @@MO: Is '#end filter' implemented?  Will it be?  Can filters nest?
+%% Will '#end filter' and '#filter None' be equivalent?
+
+%% @@MO: Tavis TODO: fix the description of the Pager filter.  It needs a howto.
+
+%% @@MO: How about using settings to provide default arguments for filters?
+%% Each filter could look up FilterName (or FilterNameDefaults) setting,
+%% whose value would be a dictionary containing keyword/value pairs.  These
+%% would be overridden by same-name keys passed by the placeholder.
+
+%% @@MO: If sed-filters (#sed) get added to Cheetah, give them a section here.
+
+% Local Variables:
+% TeX-master: "users_guide"
+% End:      
+
+% vim: shiftwidth=4 tabstop=4 expandtab
diff --git a/docs/users_guide_src/parserInstructions.tex b/docs/users_guide_src/parserInstructions.tex
new file mode 100755
index 0000000..bfd6bc2
--- /dev/null
+++ b/docs/users_guide_src/parserInstructions.tex
@@ -0,0 +1,116 @@
+\section{Instructions to the Parser/Compiler}
+\label{parserInstructions}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{\#breakpoint}
+\label{parserInstructions.breakpoint}
+
+Syntax:
+\begin{verbatim}
+#breakpoint
+\end{verbatim}
+
+
+\code{\#breakpoint} is a debugging tool that tells the parser to stop
+parsing at a specific point. All source code from that point on will be ignored.
+
+The difference between \code{\#breakpoint} and \code{\#stop} is that
+\code{\#stop} occurs in normal templates (e.g., inside an \code{\#if}) but
+\code{\#breakpoint} is used only when debugging Cheetah.  Another difference is
+that \code{\#breakpoint} operates at compile time, while \code{\#stop} is
+executed at run time while filling the template.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{\#compiler-settings}
+\label{parserInstructions.compiler-settings}
+
+Syntax:
+\begin{verbatim}
+#compiler-settings
+key = value    (no quotes)
+#end compiler-settings
+
+#compiler-settings reset
+\end{verbatim}
+
+
+The \code{\#compiler-settings} directive overrides Cheetah's standard settings,
+changing how it parses source code and generates Python code.  This
+makes it possible to change the behaviour of Cheetah's parser/compiler for a
+certain template, or within a portion of the template.
+
+The \code{reset} argument reverts to the default settings.  With \code{reset},
+there's no end tag.
+
+Here are some examples of what you can do:
+\begin{verbatim}
+$myVar
+#compiler-settings
+cheetahVarStartToken = @
+#end compiler-settings
+@myVar
+#compiler-settings reset
+$myVar
+\end{verbatim}
+
+
+\begin{verbatim}
+## normal comment
+#compiler-settings
+commentStartToken = //
+#end compiler-settings
+
+// new style of comment
+
+#compiler-settings reset
+
+## back to normal comments
+\end{verbatim}
+
+\begin{verbatim}
+#slurp
+#compiler-settings
+directiveStartToken = %
+#end compiler-settings
+
+%slurp
+%compiler-settings reset
+
+#slurp
+\end{verbatim}
+
+Here's a partial list of the settings you can change:
+\begin{enumerate}
+\item syntax settings
+     \begin{enumerate}
+     \item cheetahVarStartToken
+     \item commentStartToken
+     \item multilineCommentStartToken
+     \item multilineCommentEndToken
+     \item directiveStartToken
+     \item directiveEndToken
+     \end{enumerate}
+\item code generation settings
+     \begin{enumerate}
+     \item commentOffset
+     \item outputRowColComments
+     \item defDocStrMsg
+     \item useNameMapper
+     \item useAutocalling
+     \item reprShortStrConstants
+     \item reprNewlineThreshold
+     \end{enumerate}
+\end{enumerate}
+The meaning of these settings and their default values will be documented in
+the future.
+
+
+% Local Variables:
+% TeX-master: "users_guide"
+% End:      
+
+
+
+
diff --git a/docs/users_guide_src/tipsAndTricks.tex b/docs/users_guide_src/tipsAndTricks.tex
new file mode 100755
index 0000000..8a16fb4
--- /dev/null
+++ b/docs/users_guide_src/tipsAndTricks.tex
@@ -0,0 +1,544 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\section{Tips, Tricks and Troubleshooting}
+\label{tips}
+
+This chapter contains short stuff that doesn't fit anywhere else.
+
+See the Cheetah FAQ for more specialized issues and for troubleshooting tips.
+Check the wiki periodically for recent tips contributed by users.  If you
+get stuck and none of these resources help, ask on the mailing list.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Placeholder Tips}
+\label{tips.placeholder}
+
+Here's how to do certain important lookups that may not be obvious.
+For each, we show first the Cheetah expression and then the Python equivalent,
+because you can use these either in templates or in pure Python subclasses.
+The Cheetah examples use NameMapper shortcuts (uniform dotted notation, 
+autocalling) as much as possible.
+
+To verify whether a variable exists in the searchList:
+\begin{verbatim}
+$varExists('theVariable')
+self.varExists('theVariable')
+\end{verbatim}
+This is useful in \code{\#if} or \code{\#unless} constructs to avoid a
+\code{\#NameMapper.NotFound} error if the variable doesn't exist.  For instance,
+a CGI GET parameter that is normally supplied but in this case the user typed
+the URL by hand and forgot the parameter (or didn't know about it).
+(\code{.hasVar} is a synonym for \code{.varExists}.)
+
+To look up a variable in the searchList from a Python method:
+\begin{verbatim}
+self.getVar('theVariable')
+self.getVar('theVariable', myDefault)
+\end{verbatim}
+This is the equivalent to \code{\$theVariable} in the template.  If the 
+variable is missing, it returns the second argument, \code{myDefault}, if 
+present, or raises \code{NameMapper.NotFound} if there is no second argument.
+However, it usually easier to write your method so that all needed searchList
+values come in as method arguments.  That way the caller can just use a
+\code{\$placeholder} to specify the argument, which is less verbose than you
+writing a getVar call.
+
+To do a ``safe'' placeholder lookup that returns a default value if the
+variable is missing:
+\begin{verbatim}
+$getVar('theVariable', None)
+$getVar('theVariable', $myDefault)
+\end{verbatim}
+
+To get an environmental variable, put \code{os.environ} on the searchList as a
+container.  Or read the envvar in Python code and set a placeholder variable
+for it.
+
+Remember that variables found earlier in the searchList override same-name
+variables located in a later searchList object.  Be careful when adding objects
+containing other variables besides the ones you want (e.g., \code{os.environ},
+CGI parameters).  The "other" variables may override variables your application
+depends on, leading to hard-to-find bugs.  Also, users can inadvertently or
+maliciously set an environmental variable or CGI parameter you didn't expect,
+screwing up your program.  To avoid all this, know what your namespaces
+contain, and place the namespaces you have the most control over first.  For
+namespaces that could contain user-supplied "other" variables, don't put the
+namespace itself in the searchList; instead, copy the needed variables into
+your own "safe" namespace.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Diagnostic Output}
+\label{tips.diagnostic}
+
+If you need send yourself some debugging output, you can use \code{\#silent} to
+output it to standard error:
+\begin{verbatim}
+#silent $sys.stderr.write("Incorrigible var is '$incorrigible'.\n")
+#silent $sys.stderr.write("Is 'unknown' in the searchList? " +
+    $getVar("unknown", "No.") + "\n" )
+\end{verbatim}
+(Tip contributed by Greg Czajkowski.)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{When to use Python methods}
+\label{tips.pythonMethods}
+
+You always have a choice whether to code your methods as Cheetah \code{\#def}
+methods or Python methods (the Python methods being located in a class your
+template inherits).  So how do you choose?
+
+Generally, if the method consists mostly of text and placeholders, use a 
+Cheetah method (a \code{\#def} method).  That's why \code{\#def} exists, to
+take the tedium out of writing those kinds of methods.  And if you have a
+couple \code{\#if} stanzas to \code{\#set} some variables, followed by a
+\code{\#for} loop, no big deal.  But if your method consists mostly of
+directives and only a little text, you're better off writing it in Python.
+Especially be on the watch for extensive use of \code{\#set}, \code{\#echo} and
+\code{\#silent} in a Cheetah method--it's a sure sign you're probably using the
+wrong language.  Of course, though, you are free to do so if you wish.  
+
+Another thing that's harder to do in Cheetah is adjacent or nested
+multiline stanzas (all those directives with an accompanying \code{\#end}
+directive).  Python uses indentation to show the beginning and end of nested
+stanzas, but Cheetah can't do that because any indentation shows up in the
+output, which may not be desired.  So unless all those extra spaces and tabs
+in the output are acceptable, you have to keep directives flush with the left
+margin or the preceding text.  
+
+The most difficult decisions come when you have conflicting goals.  What if
+a method generates its output in parts (i.e., output concatenation), contains
+many searchList placeholders and lots of text, {\em and} requires lots of
+\code{\#if \ldots \#set \ldots \#else \#set \ldots \#end if} stanzas.  A Cheetah
+method would be more advantageous in some ways, but a Python method in others.
+You'll just have to choose, perhaps coding groups of methods all the same
+way.  Or maybe you can split your method into two, one Cheetah and one Python,
+and have one method call the other.  Usually this means the Cheetah method
+calling the Python method to calculate the needed values, then the Cheetah
+method produces the output.  One snag you might run into though is that
+\code{\#set} currently can set only one variable per statement, so if your
+Python method needs to return multiple values to your Cheetah method, you'll
+have to do it another way.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Calling superclass methods, and why you have to}
+\label{tips.callingSuperclassMethods}
+
+If your template or pure Python class overrides a standard method or attribute
+of \code{Template} or one of its base classes, you should call the superclass
+method in your method to prevent various things from breaking.  The most common
+methods to override are \code{.awake} and \code{.\_\_init\_\_}.  \code{.awake}
+is called automatically by Webware early during the web transaction, so it makes
+a convenient place to put Python initialization code your template needs.
+You'll definitely want to call the superclass \code{.awake} because it sets up
+many wonderful attributes and methods, such as those to access the CGI input
+fields.
+
+There's nothing Cheetah-specific to calling superclass methods, but
+because it's vital, we'll recap the standard Python techniques
+here. We mention only the solution for old-style classes because
+Cheetah classes are old-style (in other Python documentation, you will
+find the technique for new-style classes, but they are not listed here
+because they cannot be used with Cheetah if you use
+dynamically-compiled templates).
+
+\begin{verbatim}
+from Cheetah.Template import Template
+class MyClass(Template):
+	def awake(self, trans):
+		Template.awake(self, trans)
+		... great and exciting features written by me ...
+\end{verbatim}
+
+[ @@MO: Need to test this.  .awake is in Servlet, which is a superclass
+of Template.  Do we really need both imports?  Can we call
+Template.awake? ]
+
+To avoid hardcoding the superclass name, you can use this
+function \code{callbase()}, which emulates \code{super()} for older versions of
+Python.  It also works even \code{super()} does exist, so you don't have to
+change your servlets immediately when upgrading.  Note that the argument
+sequence is different than \code{super} uses.
+
+\begin{verbatim}
+===========================================================================
+# Place this in a module SOMEWHERE.py .  Contributed by Edmund Lian.
+class CallbaseError(AttributeError):
+    pass
+
+def callbase(obj, base, methodname='__init__', args=(), kw={},
+    raiseIfMissing=None):
+    try: method = getattr(base, methodname)
+    except AttributeError:
+        if raiseIfMissing:
+            raise CallbaseError, methodname
+        return None
+    if args is None: args = ()
+    return method(obj, *args, **kw)
+===========================================================================
+# Place this in your class that's overriding .awake (or any method).
+from SOMEWHERE import callbase
+class MyMixin:
+        def awake(self, trans):
+                args = (trans,)
+                callbase(self, MyMixin, 'awake', args)
+                ... everything else you want to do ...
+===========================================================================
+\end{verbatim}
+
+% @@MO: Edmund wants us to mention delegation too, as an alternative to
+% inheritance.  Contact elian@inbrief.net for details.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{All methods}
+\label{tips.allMethods}
+
+Here is a list of all the standard methods and attributes that can be accessed
+from a placeholder.  Some of them exist for you to call, others are mainly used
+by Cheetah internally but you can call them if you wish, and others are only
+for internal use by Cheetah or Webware.  Do not use these method names in mixin
+classes (\code{\#extends}, section \ref{inheritanceEtc.extends}) unless you
+intend to override the standard method.  
+
+Variables with a star prefix ({\bf *}) are frequently used in templates or in
+pure Python classes.
+
+\paragraph*{Inherited from Cheetah.Template}
+
+\begin{description}
+\item{{\bf compile(source=None, file=None, moduleName=None, 
+    mainMethodName='respond')}}  Compile the template.  Automatically called
+    by \code{.\_\_init\_\_}.
+\item{{\bf generatedModuleCode()}}  Return the module code the compiler
+    generated, or \code{None} if no compilation took place.
+\item{{\bf generatedClassCode()}}   Return the class code the compiler
+    generated, or \code{None} if no compilation took place.
+\item{{\bf * searchList()}}  Return a reference to the underlying search list.
+    (a list of objects).  Use this to print out your searchList for debugging.
+    Modifying the returned list will affect your placeholder searches!
+\item{{\bf * errorCatcher()}}  Return a reference to the current error
+    catcher.
+\item{{\bf * refreshCache(cacheKey=None)}}  If 'cacheKey' is not \code{None},
+    refresh that item in the cache.  If \code{None}, delete all items in the
+    cache so they will be recalculated the next time they are encountered.
+\item{{\bf * shutdown()}}  Break reference cycles before discarding a servlet.
+\item{{\bf * getVar(varName, default=NoDefault, autoCall=True)}}  Look up a
+    variable in the searchList.  Same as \code{\$varName} but allows you to
+    specify a default value and control whether autocalling occurs.
+\item{{\bf * varExists(varName, autoCall=True)}}
+\item{{\bf * getFileContents(path)}}  Read the named file.  If used as a
+    placeholder, inserts the file's contents in the output without
+    interpretation, like \code{\#include\ raw}.  If used in an expression,
+    returns the file's content (e.g., to assign it to a variable).
+\item{{\bf runAsMainProgram()}}  This is what happens if you run a
+    .py template module as a standalone program.
+\end{description}
+
+%Private methods: {\bf \_bindCompiledMethod}, {\bf \_bindFunctionAsMethod},
+%{\bf \_includeCheetahSource}, {\bf \_genTmpFilename}, 
+%{\bf \_importAsDummyModule}, {\bf \_makeDummyPackageForDir},
+%{\bf \_importFromDummyPackage}, {\bf \_importModuleFromDirectory}.
+%
+%Other private attributes:
+%\begin{description}
+%\item{{\bf * \_fileMtime}}  Time the template definition was modified, in
+%    Unix ticks.  \code{None} if the template definition came from a string or
+%    file handle rather than a named file, same for the next three variables.
+%\item{{\bf * \_fileDirName}}  The directory containing the template definition.
+%\item{{\bf * \_fileBaseName}}  The basename of the template definition  file.
+%\item{{\bf * \_filePath}}  The directory+filename of the template definition.
+%\end{description}
+
+\paragraph*{Inherited from Cheetah.Utils.WebInputMixin}
+
+\begin{description}
+\item{{\bf nonNumericInputError}}  Exception raised by \code{.webInput}.
+\item{{\bf * webInput(...)}}  Convenience method to access GET/POST variables
+    from a Webware servlet or CGI script, or Webware cookie or session
+    variables.  See section \ref{webware.webInput} for usage information.
+\end{description}
+
+\paragraph*{Inherited from Cheetah.SettingsManager}
+
+\begin{description}
+\item{{\bf setting(name, default=NoDefault)}}  Get a compiler setting.
+\item{{\bf hasSetting(name)}}  Does this compiler setting exist?
+\item{{\bf setSetting(name, value)}}  Set setting 'name' to 'value'.
+    See \code{\#compiler-settings}, section 
+    \ref{parserInstructions.compiler-settings}.
+\item{{\bf settings()}}  Return the underlying settings dictionary.  (Warning:
+    modifying this dictionary will change Cheetah's behavior.)
+\item{{\bf copySettings()}}  Return a copy of the underlying settings
+    dictionary.
+\item{{\bf deepcopySettings()}}  Return a deep copy of the underlying settings
+    dictionary.  See Python's \code{copy} module.
+\item{{\bf updateSettings(newSettings, merge=True)}}  Update Cheetah's 
+    compiler settings from the 'newSettings' dictionary.  If 'merge' is true,
+    update only the names in newSettings and leave the other names alone.
+    (The SettingsManager is smart enough to update nested dictionaries one
+    key at a time rather than overwriting the entire old dictionary.)
+    If 'merge' is false, delete all existing settings so that the new ones are
+    the only settings.
+\item{{\bf updateSettingsFromPySrcStr(theString, merge=True)}}  Same, 
+    but pass a string of \code{name=value} pairs rather
+    than a dictionary, the same as you would provide in a
+    \code{\#compiler-settings} directive, section
+    \ref{parserInstructions.compiler-settings}.
+\item{{\bf updateSettingsFromPySrcFile(path, merge=True)}}  Same, but
+    exec a Python source file and use the variables it contains as the new
+    settings.  (e.g., \code{cheetahVarStartToken\ =\ "@"}).
+\item{{\bf updateSettingsFromConfigFile(path, **kw)}}  Same, but get the new
+    settings from a text file in ConfigParser format (similar to Windows'
+    *.ini file format).  See Python's \code{ConfigParser} module.
+\item{{\bf updateSettingsFromConfigFileObj}}  Same, but read the open file
+    object 'inFile' for the new settings.  
+\item{{\bf updateSettingsFromConfigStr(configStr, convert=True, merge=True}}
+    Same, but read the new settings from a string in ConfigParser format.
+\item{{\bf writeConfigFile(path)}}  Write the current compiler settings to
+    a file named 'path' in *.ini format.
+\item{{\bf getConfigString()}}  Return a string containing the current
+    compiler settings in *.ini format.
+\end{description}
+
+\paragraph*{Inherited from Cheetah.Servlet}
+
+{\em Do not override these in a subclass or assign to them as attributes
+if your template will be used as a servlet,} otherwise Webware will behave
+unpredictably.  However, it {\em is} OK to put same-name variables in the
+searchList, because Webware does not use the searchList.
+
+EXCEPTION: It's OK to override {\bf awake} and {\bf sleep} as long as you
+call the superclass methods.  (See section
+\ref{tips.callingSuperclassMethods}.)
+
+\begin{description}
+\item{{\bf * isControlledByWebKit}}  True if this template instance is
+    part of a live transaction in a running WebKit servlet.
+\item{{\bf * isWebwareInstalled}}  True if Webware is installed and the
+    template instance inherits from WebKit.Servlet.  If not, it inherits
+    from Cheetah.Servlet.DummyServlet.
+\item{{\bf * awake(transaction)}}  Called by WebKit at the beginning of
+    the web transaction.
+\item{{\bf * sleep(transaction)}}  Called by WebKit at the end of the
+    web transaction.
+\item{{\bf * respond(transaction)}}  Called by WebKit to produce the 
+    web transaction content.  For a template-servlet, this means
+    filling the template.
+\item{{\bf shutdown()}}  Break reference cycles before deleting instance.
+\item{{\bf * serverSidePath()}}  The filesystem pathname of the 
+    template-servlet (as opposed to the URL path).
+\item{{\bf transaction}}  The current Webware transaction.
+\item{{\bf application}}  The current Webware application.
+\item{{\bf response}}  The current Webware response.
+\item{{\bf request}}  The current Webware request.
+\item{{\bf session}}  The current Webware session.
+\item{{\bf write}}  Call this method to insert text in the filled template
+    output.
+\end{description}
+
+Several other goodies are available to template-servlets under the 
+\code{request} attribute, see section \ref{webware.input}.
+
+\code{transaction}, \code{response}, \code{request} and \code{session} are
+created from the current transaction when WebKit calls \code{awake}, and don't
+exist otherwise.  Calling \code{awake} yourself (rather than letting WebKit
+call it) will raise an exception because the \code{transaction} argument won't
+have the right attributes.  
+
+\paragraph*{Inherited from WebKit.Servlet}
+These are accessible only if Cheetah knows Webware is installed.  This 
+listing is based on a CVS snapshot of Webware dated 22 September 2002, and
+may not include more recent changes.
+
+The same caveats about overriding these methods apply.
+
+\begin{description}
+\item{name()}  The simple name of the class.  Used by Webware's logging and
+    debugging routines.
+\item{log()}  Used by Webware's logging and debugging routines.
+\item{canBeThreaded()}  True if the servlet can be multithreaded.
+\item{canBeReused()}  True if the servlet can be used for another transaction
+    after the current transaction is finished.
+\item{serverSideDir()}  Depreciated by \code{.serverSidePath()}.
+\end{description}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Optimizing templates}
+\label{tips.optimizing}
+
+Here are some things you can do to make your templates fill faster and user
+fewer CPU cycles.  Before you put a lot of energy into this, however, make
+sure you really need to.  In many situations, templates appear to initialize
+and fill instantaneously, so no optimization is necessary.  If you do find a
+situation where your templates are filling slowly or taking too much memory or
+too many CPU cycles, we'd like to hear about it on the mailing list.
+
+Cache \$placeholders whose values don't change frequently.  (Section
+\ref{output.caching}).
+
+Use \code{\#set} for values that are very frequently used, especially if they
+come out of an expensive operation like a deeply.nested.structure or a database
+lookup.  \code{\#set} variables are set to Python local variables, which have a
+faster lookup time than Python globals or values from Cheetah's searchList.
+
+Moving variable lookups into Python code may provide a speedup in certain
+circumstances.  If you're just reading \code{self} attributes, there's no
+reason to use NameMapper lookup (\$placeholders) for them.  NameMapper does
+a lot more work than simply looking up a \code{self} attribute.  
+
+On the other hand, if you don't know exactly where the value will come from
+(maybe from \code{self}, maybe from the searchList, maybe from a CGI input
+variable, etc), it's easier to just make that an argument to your method, and
+then the template can handle all the NameMapper lookups for you:
+\begin{verbatim}
+#silent $myMethod($arg1, $arg2, $arg3)
+\end{verbatim}
+Otherwise you'd have to call \code{self.getVar('arg1')} etc in your
+method, which is more wordy, and tedious.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{PSP-style tags}
+\label{tips.PSP}
+
+\code{<\%= \ldots \%>} and \code{<\% \ldots \%>} allow an escape
+to Python syntax inside the template.  You do not need it to use Cheetah
+effectively, and we're hard pressed to think of a case to recommend it.
+Nevertheless, it's there in case you encounter a situation you can't
+express adequately in Cheetah syntax.  For instance, to set a local
+variable to an elaborate initializer.  
+
+\code{<\%= \ldots \%>} encloses a Python expression whose result will
+be printed in the output.  
+
+\code{<\% \ldots \%>} encloses a Python statement or expression (or set of
+statements or expressions) that will be included as-is into the generated
+method.  The statements themselves won't produce any output, but you can use
+the local function \code{write(EXPRESSION)} to produce your own output.
+(Actually, it's a method of a file-like object, but it looks like a local
+function.) This syntax also may be used to set a local variable with a
+complicated initializer.
+
+To access Cheetah services, you must use Python code like you would in an
+inherited Python class.  For instance, use \code{self.getVar()} to look up
+something in the searchList.
+
+{\em Warning:} {\bf No error checking is done!}  If you write:
+\begin{verbatim}
+<% break %>      ## Wrong!
+\end{verbatim}
+you'll get a \code{SyntaxError} when you fill the template, but that's what you
+deserve.
+
+Note that these are PSP-{\em style} tags, not PSP tags.  A Cheetah template
+is not a PSP document, and you can't use PSP commands in it.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Makefiles}
+\label{tips.Makefile}
+
+If your project has several templates and you get sick of typing
+``cheetah compile FILENAME.tmpl'' all the time--much less remembering which
+commands to type when--and your system has the \code{make}
+command available, consider building a Makefile to make your life easier.
+
+Here's a simple Makefile that controls two templates, ErrorsTemplate and
+InquiryTemplate.  Two external commands, \code{inquiry} and \code{receive},
+depend on ErrorsTemplate.py.  Aditionally, InquiryTemplate
+itself depends on ErrorsTemplate.
+
+\begin{verbatim}
+all:  inquiry  receive
+
+.PHONY:  all  receive  inquiry  printsource
+
+printsource:
+        a2ps InquiryTemplate.tmpl ErrorsTemplate.tmpl
+
+ErrorsTemplate.py:  ErrorsTemplate.tmpl
+        cheetah compile ErrorsTemplate.tmpl
+
+InquiryTemplate.py:  InquiryTemplate.tmpl ErrorsTemplate.py
+        cheetah compile InquiryTemplate.tmpl
+
+inquiry: InquiryTemplate.py  ErrorsTemplate.py
+
+receive: ErrorsTemplate.py
+\end{verbatim}
+
+Now you can type \code{make} anytime and it will recompile all the templates
+that have changed, while ignoring the ones that haven't.  Or you can
+recompile all the templates \code{receive} needs by typing \code{make receive}.
+Or you can recompile only ErrorsTemplate by typing
+\code{make ErrorsTemplate}.  There's also another target, ``printsource'':
+this sends a Postscript version of the project's source files to the printer.
+The .PHONY target is explained in the \code{make} documentation; essentially,
+you have it depend on every target that doesn't produce an output file with
+the same name as the target.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Using Cheetah in a Multi-Threaded Application}
+\label{tips.threads}
+
+Template classes may be shared freely between threads.  However, template
+instances should not be shared unless you either:
+\begin{itemize}
+\item Use a lock (mutex) to serialize template fills, to prevent two threads
+from filling the template at the same time.
+\item Avoid thread-unsafe features:
+    \begin{itemize}
+    \item Modifying searchList values or instance variables.
+    \item Caching (\code{\$*var}, \code{\#cache}, etc).
+    \item \code{\#set global}, \code{\#filter}, \code{\#errorCatcher}.
+    \end{itemize}
+    Any changes to these in one thread will be visible in other threads,
+    causing them to give inconsistent output.
+\end{itemize}
+
+About the only advantage in sharing a template instance is building up the
+placeholder cache.  But template instances are so low overhead that it
+probably wouldn't take perceptibly longer to let each thread instantiate its
+own template instance.  Only if you're filling templates several times a
+second would the time difference be significant, or if some of the placeholders
+trigger extremely slow calculations (e.g., parsing a long text file each time).
+The biggest overhead in Cheetah is importing the \code{Template} module in
+the first place, but that has to be done only once in a long-running
+application.
+
+You can use Python's \code{mutex} module for the lock, or any similar
+mutex.  If you have to change searchList values or instance variables
+before each fill (which is usually the case), lock the mutex before 
+doing this, and unlock it only after the fill is complete.
+
+For Webware servlets, you're probably better off using Webware's servlet
+caching rather than Cheetah's caching.  Don't override the servlet's
+\code{.canBeThreaded()} method unless you avoid the unsafe operations
+listed above.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Using Cheetah with gettext}
+\label{tips.gettext}
+
+{\bf gettext} is a project for creating internationalized applications.  For 
+more details, visit \url{http://docs.python.org/lib/module-gettext.html}.
+gettext can be used with Cheetah to create internationalized applications, even
+for CJK character sets, but you must keep a couple things in mind:
+\begin{itemize}
+\item xgettext is used on compiled templates, not on the templates themselves.
+\item The way the NameMapper syntax gets compiled to Python gets in the way of 
+the syntax that xgettext recognizes.  Hence, a special case exists for the
+functions \code{_}, \code{N_}, and \code{ngettext}.  If you need to use a
+different set of functions for marking strings for translation, you must set
+the Cheetah setting \code{gettextTokens} to a list of strings representing the
+names of the functions you are using to mark strings for translation.
+\end{itemize}
+
+
+% Local Variables:
+% TeX-master: "users_guide"
+% End:      
diff --git a/docs/users_guide_src/users_guide.tex b/docs/users_guide_src/users_guide.tex
new file mode 100755
index 0000000..74949cf
--- /dev/null
+++ b/docs/users_guide_src/users_guide.tex
@@ -0,0 +1,54 @@
+
+\documentclass{howto}
+\usepackage{moreverb}                   %% Verbatim Code Listings
+
+\title{Cheetah Users' Guide}
+\release{0.9.17rc1}
+
+\author{Edited by Mike Orr and Tavis Rudd}
+\authoraddress{\email{cheetahtemplate-discuss@lists.sourceforge.net}}
+
+\begin{document}
+\maketitle
+
+% @@MO: Picture of cheetah from web site.
+
+\tableofcontents
+
+\copyright{Copyright 2001-2005, The Cheetah Development Team.
+      This document may be copied and modified under the terms of the
+      {\bf Open Publication License} \url{http://www.opencontent.org/openpub/} }
+
+    %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    \include{introduction}
+    \include{glossary}
+    \include{gettingStarted}
+    \include{howItWorks}
+    \include{language}
+    \include{comments}
+    \include{output}
+    \include{inheritanceEtc}
+    \include{flowControl}
+    \include{errorHandling}
+    \include{parserInstructions}
+    \include{moduleFormatting}
+    \include{tipsAndTricks}
+    \include{webware}
+    \include{otherHtml}
+    \include{nonHtml}
+    \include{nonHTML}
+    \include{libraries}
+    \include{editors}
+
+    %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    \appendix
+    \include{links}
+    \include{examples}
+    \include{comparisons}
+    \include{optikLicense}
+
+\end{document}
+
+% Local Variables:
+% TeX-master: "users_guide"
+% End:      
diff --git a/docs/users_guide_src/webware.tex b/docs/users_guide_src/webware.tex
new file mode 100755
index 0000000..a5702d8
--- /dev/null
+++ b/docs/users_guide_src/webware.tex
@@ -0,0 +1,575 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\section{Using Cheetah with Webware}
+\label{webware}
+
+{\bf Webware for Python} is a 'Python-Powered Internet Platform' that runs
+servlets in a manner similar to Java servlets.  {\bf WebKit} is the name of
+Webware's application server.  For more details, please visit
+\url{http://webware.sourceforge.net/}.
+
+All comments below refer to the official version of Webware, the DamnSimple!
+offshoot at ?, and the now-abandoned WebwareExperimental implementation at
+\url{http://sourceforge.net/projects/expwebware/}, except where noted.  All the
+implementations are 95\% identical to the servlet writer: their differences lie
+in their internal structure and configuration files.  One difference is that
+the executable you run to launch standard Webware is called \code{AppServer},
+whereas in WebwareExperimental it's called \code{webkit}. But to servlets
+they're both "WebKit, Webware's application server", so it's one half dozen to
+the other.  In this document, we generally use the term {\bf WebKit} to refer
+to the currently-running application server.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Installing Cheetah on a Webware system}
+\label{webware.installing}
+
+Install Cheetah after you have installed Webware, following the instructions in
+chapter \ref{gettingStarted}.
+
+The standard Cheetah test suite ('cheetah test') does not test Webware features.
+We plan to build a test suite that can run as a Webware servlet, containing
+Webware-specific tests, but that has not been built yet.  In the meantime, you
+can make a simple template containing something like "This is a very small
+template.", compile it, put the *.py template module in a servlet
+directory, and see if Webware serves it up OK.  
+
+{\em You must not have a Webware context called "Cheetah".}  If you do, Webware
+will mistake that directory for the Cheetah module directory, and all 
+template-servlets will bomb out with a "ImportError: no module named Template".
+(This applies only to the standard Webware; WebwareExperimental does not have
+contexts.)
+
+If Webware complains that it cannot find your servlet, make sure
+'.tmpl' is listed in 'ExtensionsToIgnore' in your 'Application.config' file.
+
+% @@MO: Should explain extension cascading and how without it, standard
+% Webware pretends a file doesn't exist if it finds two or more servable files
+% that match the URL.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Containment vs Inheritance}
+\label{webware.background}
+
+Because Cheetah's core is flexible, there are many ways to integrate it with
+Webware servlets.  There are two broad strategies: the {\bf Inheritance
+approach} and the {\bf Containment approach}.  The difference is
+that in the Inheritance approach, your template object \code{\em is} the
+servlet, whereas in the Containment approach, the servlet is not a template but
+merely {\em uses} template(s) for portion(s) of its work.
+
+The Inheritance approach is recommended for new sites because it's simpler, and
+because it scales well for large sites with a
+site->section->subsection->servlet hierarchy.  The Containment approach is
+better for existing servlets that you don't want to restructure.  For instance,
+you can use the Containment approach to embed a discussion-forum table at the
+bottom of a web page.  
+
+However, most people who use Cheetah extensively seem
+to prefer the Inheritance approach because even the most analytical servlet
+needs to produce {\em some} output, and it has to fit the site's look and feel
+{\em anyway}, so you may as well use a template-servlet as the place to put the
+output.  Especially since it's so easy to add a template-servlet to a site once
+the framework is established.  So we recommend you at least evaluate the
+effort that would be required to convert your site framework to template
+superclasses as described below, vs the greater flexibility and manageability
+it might give the site over the long term.  You don't necessarily have to
+convert all your existing servlets right away: just build common site templates
+that are visually and behaviorally compatible with your specification, and use
+them for new servlets.  Existing servlets can be converted later, if at all.
+
+Edmund Liam is preparing a section on a hybrid approach, in which the 
+servlet is not a template, but still calls template(s) in an inheritance
+chain to produce the output.  The advantage of this approach is that you
+aren't dealing with \code{Template} methods and Webware methods in the
+same object.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection{The Containment Approach}
+\label{webware.containment}
+
+In the Containment approach, your servlet is not a template.  Instead, it 
+it makes its own arrangements to create and use template object(s) for whatever
+it needs.  The servlet must explicitly call the template objects'
+\code{.respond()} (or \code{.\_\_str\_\_()}) method each time it needs to fill
+the template.  This does not present the output to the user; it merely gives
+the output to the servlet.  The servlet then calls its
+\code{\#self.response().write()} method to send the output to the user.
+
+The developer has several choices for managing her templates.  She can store the
+template definition in a string, file or database and call
+\code{Cheetah.Template.Template} manually on it.  Or she can put the
+template definition in a *.tmpl file and use {\bf cheetah compile} (section
+\ref{howWorks.cheetah-compile}) to convert it to a Python class in a *.py
+module, and then import it into her servlet.
+
+Because template objects are not thread safe, you should not store one
+in a module variable and allow multiple servlets to fill it simultaneously.
+Instead, each servlet should instantiate its own template object.  Template
+{\em classes}, however, are thread safe, since they don't change once created.
+So it's safe to store a template class in a module global variable.
+
+% @@MO: Example of containment.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection{The Inheritance Approach}
+\label{webware.inheritance}
+
+In the Inheritance approach, your template object doubles as as Webware 
+servlet, thus these are sometimes called {\bf template-servlets}.  {\bf cheetah
+compile} (section \ref{howWorks.cheetah-compile}) automatically creates modules
+containing valid Webware servlets.  A servlet is a subclass of Webware's
+\code{WebKit.HTTPServlet} class, contained in a module with the same name as
+the servlet.  WebKit uses the request URL to find the module, and then
+instantiates the servlet/template.  The servlet must have a \code{.respond()}
+method (or \code{.respondToGet()}, \code{.respondToPut()}, etc., but the
+Cheetah default is \code{.respond()}).  Servlets created by \code{cheetah
+compile} meet all these requirements.
+
+(Cheetah has a Webware plugin that automatically converts a \code{.tmpl servlet
+file} into a \code{.py servlet file} when the \code{.tmpl servlet file} is
+requested by a browser.  However, that plugin is currently unavailable because
+it's being redesigned.  For now, use \code{cheetah compile} instead.)
+
+What about logic code?  Cheetah promises to keep content (the placeholder
+values), graphic design (the template definition and is display logic), and
+algorithmic logic (complex calculations and side effects) separate.  How?
+Where do you do form processing?
+
+The answer is that your template class can inherit from a pure Python class
+containing the analytical logic.  You can either use the \code{\#extends}
+directive in Cheetah to indicate the superclass(es), or write a Python
+\code{class} statement to do the same thing.  See the template
+\code{Cheetah.Templates.SkeletonPage.tmpl} and its pure Python class
+\code{Cheetah.Templates.\_SkeletonPage.py} for an example of a template
+inheriting logic code.  (See sections \ref{inheritanceEtc.extends} and
+\ref{inheritanceEtc.implements} for more information about \code{\#extends} and
+\code{\#implements}.  They have to be used a certain right way.)
+
+If \code{\#WebKit.HTTPServlet} is not available, Cheetah fakes it with a
+dummy class to satisfy the dependency.  This allows servlets to be tested on
+the command line even on systems where Webware is not installed.  This works
+only with servlets that don't call back into WebKit for information about the
+current web transaction, since there is no web transaction.  Trying to access
+form input, for instance, will raise an exception because it depends on a
+live web request object, and in the dummy class the request object is
+\code{None}.
+
+Because Webware servlets must be valid Python modules, and ``cheetah compile''
+can produce only valid module names, if you're converting an existing site that
+has .html filenames with hyphens (-), extra dots (.), etc, you'll have to
+rename them (and possibly use redirects).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Site frameworks}
+\label{webware.siteFrameworks}
+
+Web sites are normally arranged hierarchically, with certain features common 
+to every page on the site, other features common to certain sections or
+subsections, and others unique to each page.  You can model this easily with
+a hierarchy of classes, with specific servlets inheriting from their more
+general superclasses.  Again, you can do this two ways, using Cheetah's
+{\bf Containment} approach or {\bf Inheritance} approach.
+
+In the Inheritance approach, parents provide \code{\#block}s and children
+override them using \code{\#def}.  Each child \code{\#extend}s its immediate
+parent.  Only the leaf servlets need to be under WebKit's document root
+directory.  The superclass servlets can live anywhere in the filesystem
+that's in the Python path.  (You may want to modify your WebKit startup 
+script to add that library directory to your \code{PYTHONPATH} before starting
+WebKit.)
+
+% @@MO Examples: simple, IronSite, SkeletonPage.
+
+Section \ref{libraries.templates.skeletonPage} contains information on a stock
+template that simplifies defining the basic HTML structure of your web
+page templates.  
+
+In the Containment approach, your hierarchy of servlets are not templates, but
+each uses one or more templates as it wishes.  Children provide callback
+methods to to produce the various portions of the page that are their
+responsibility, and parents call those methods.  Webware's \code{WebKit.Page}
+and \code{WebKit.SidebarPage} classes operate like this.
+
+% @@MO Show examples of WebKit.Page and WebKit.SidebarPage.
+
+Note that the two approaches are not compatible!  \code{WebKit.Page} was not
+designed to intermix with \code{Cheetah.Templates.SkeletonPage}.  Choose either
+one or the other, or expect to do some integration work.  
+
+If you come up with a different strategy you think is worth noting in this
+chapter, let us know.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Directory structure}
+\label{webware.directoryStructure}
+
+Here's one way to organize your files for Webware+Cheetah.
+
+\begin{verbatim}
+www/                         # Web root directory.
+    site1.example.com/       # Site subdirectory.
+        apache/              # Web server document root (for non-servlets).
+        www/                 # WebKit document root. 
+           index.py          # http://site1.example.com/
+           index.tmpl        # Source for above.
+           servlet2.py       # http://site1.example.com/servlet2
+           servlet2.tmpl     # Source for above.
+        lib/                 # Directory for helper classes.
+           Site.py           # Site superclass ("#extends Site").
+           Site.tmpl         # Source for above.
+           Logic.py          # Logic class inherited by some template.
+        webkit.config        # Configuration file (for WebwareExperimental).
+        Webware/             # Standard Webware's MakeAppWorkDir directory.
+           AppServer         # Startup program (for standard Webware).
+           Configs/          # Configuration directory (for standard Webware).
+               Application.config
+                             # Configuration file (for standard Webware). 
+    site2.example.org/       # Another virtual host on this computer....
+\end{verbatim}
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Initializing your template-servlet with Python code}
+\label{webware.calculations}
+
+If you need a place to initialize variables or do calculations for your
+template-servlet, you can put it in an \code{.awake()} method because WebKit
+automatically calls that early when processing the web transaction.  If you
+do override \code{.awake()}, be sure to call the superclass \code{.awake}
+method.  You probably want to do that first so that you have access to the
+web transaction data \code{Servlet.awake} provides.  You don't have to worry
+about whether your parent class has its own \code{.awake} method, just call
+it anyway, and somebody up the inheritance chain will respond, or at minimum
+\code{Servlet.awake} will respond.  Section
+\ref{tips.callingSuperclassMethods} gives examples of how to call a
+superclass method.
+
+As an alternative, you can put all your calculations in your own method and
+call it near the top of your template.  (\code{\#silent}, section
+\ref{output.silent}).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Form processing}
+\label{webware.form}
+
+There are many ways to display and process HTML forms with Cheetah.
+But basically, all form processing involves two steps.
+\begin{enumerate}
+\item{} Display the form.  
+\item{} In the next web request, read the parameters the user submitted,
+check for user errors, perform any side effects (e.g., reading/writing a
+database or session data) and present the user an HTML response or another
+form.  
+\end{enumerate}
+
+The second step may involve choosing between several templates to fill (or
+several servlets to redirect to), or a big if-elif-elif-else construct to
+display a different portion of the template depending on the situation.
+
+In the oldest web applications, step 1 and step 2 were handled by separate
+objects.  Step 1 was a static HTML file, and step 2 was a CGI script.
+Frequently, a better strategy is to have a single servlet handle both steps.
+That way, the servlet has better control over the entire situation, and if
+the user submits unacceptable data, the servlet can redisplay the form with a
+"try again" error message at the top and and all the previous input filled in.
+The servlet can use the presence or absence of certain CGI parameters (e.g.,
+the submit button, or a hidden mode field) to determine which step to take.
+
+One neat way to build a servlet that can handle both the form displaying and
+form processing is like this:
+
+\begin{enumerate}
+\item Put your form HTML into an ordinary template-servlet.  In each input 
+    field, use a placeholder for the value of the \code{VALUE=} attribue.
+    Place another placeholder next to each field, for that field's error
+    message.
+\item Above the form, put a \code{\$processFormData} method call.
+\item Define that method in a Python class your template \code{\#extend}s.  (Or
+    if it's a simple method, you can define it in a \code{\#def}.)  The method
+    should:
+    \begin{enumerate}
+    \item Get the form input if any.
+    \item If the input variable corresponding to the submit field is empty,
+        there is no form input, so we're showing the form for the first time.
+        Initialize all VALUE= variables to their default value (usually ""),
+        and all error variables to "".  Return "", which will be the value for
+        \code{\$processFormData}.
+    \item If the submit variable is not empty, fill the VALUE= variables with
+        the input data the user just submitted.
+    \item Now check the input for errors and put error messages in the error
+        placeholders.  
+    \item If there were any user errors, return a general error message
+        string; this will be the value for \code{\$processFormData}.
+    \item If there were no errors, do whatever the form's job is (e.g., update
+        a database) and return a success message; this will be the value for
+        \code{\$processFormData}.
+    \end{enumerate}
+\item The top of the page will show your success/failure message (or nothing
+the first time around), with the form below.  If there are errors, the user
+will have a chance to correct them.  After a successful submit, the form will
+appear again, so the user can either review their entry, or change it and
+submit it again.  Depending on the application, this may make the servlet
+update the same database record again, or it may generate a new record.
+\end{enumerate}
+
+% @@MO: Example of a template that shows a form and then processes the input.
+
+\code{FunFormKit} is a third-party Webware package that makes it easier to
+produce forms and handle their logic.  It has been successfully been used with
+Cheetah.  You can download FunFormKit from
+\url{http://colorstudy.net/software/funformkit/} and try it out for yourself.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Form input, cookies, session variables and web server variables}
+\label{webware.input}
+
+General variable tips that also apply to servlets are in section
+\ref{tips.placeholder}.
+
+To look up a CGI GET or POST parameter (with POST overriding):
+\begin{verbatim}
+$request.field('myField')     
+self.request().field('myField')
+\end{verbatim}
+These will fail if Webware is not available, because \code{\$request}
+(aka \code{self.request()} will be \code{None} rather than a Webware
+\code{WebKit.Request} object.  If you plan to read a lot of CGI parameters,
+you may want to put the \code{.fields} method into a local variable for
+convenience:
+\begin{verbatim}
+#set $fields = $request.fields
+$fields.myField
+\end{verbatim}
+But remember to do complicated calculations in Python, and assign the results
+to simple variables in the searchList for display.  These \code{\$request}
+forms are useful only for occasions where you just need one or two simple
+request items that going to Python for would be overkill.
+
+To get a cookie or session parameter, subsitute ``cookie'' or ``session'' for
+``field'' above.  To get a dictionary of all CGI parameters, substitute
+``fields'' (ditto for ``cookies'').  To verify a field exists,
+substitute ``hasField'' (ditto for ``hasCookie'').  
+
+Other useful request goodies:
+\begin{verbatim}
+## Defined in WebKit.Request
+$request.field('myField', 'default value')
+$request.time              ## Time this request began in Unix ticks.
+$request.timeStamp         ## Time in human-readable format ('asctime' format).
+## Defined in WebKit.HTTPRequest
+$request.hasField.myField  ## Is a CGI parameter defined?
+$request.fields            ## Dictionary of all CGI parameters.
+$request.cookie.myCookie   ## A cookie parameter (also .hasCookie, .cookies).
+$request.value.myValue     ## A field or cookie variable (field overrides)
+                           ## (also .hasValue).
+$request.session.mySessionVar  # A session variable.
+$request.extraURLPath      ## URL path components to right of servlet, if any.
+$request.serverDictionary  ## Dict of environmental vars from web server.
+$request.remoteUser        ## Authenticated username.  HTTPRequest.py source
+                           ## suggests this is broken and always returns None.
+$request.remoteAddress  ## User's IP address (string).
+$request.remoteName     ## User's domain name, or IP address if none.
+$request.urlPath        ## URI of this servlet.
+$request.urlPathDir     ## URI of the directory containing this servlet.
+$request.serverSidePath ## Absolute path of this servlet on local filesystem.
+$request.serverURL      ## URL of this servlet, without "http://" prefix,
+                        ## extra path info or query string.
+$request.serverURLDir   ## URL of this servlet's directory, without "http://".
+$log("message")         ## Put a message in the Webware server log.  (If you
+                        ## define your own 'log' variable, it will override
+                        ## this; use $self.log("message") in that case.
+\end{verbatim}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection{.webInput()}
+\label{webware.webInput}
+
+From the method docstring:
+
+\begin{verbatim}
+    def webInput(self, names, namesMulti=(), default='', src='f',
+        defaultInt=0, defaultFloat=0.00, badInt=0, badFloat=0.00, debug=False):
+
+This method places the specified GET/POST fields, cookies or session variables
+into a dictionary, which is both returned and put at the beginning of the
+searchList.  It handles:
+    * single vs multiple values
+    * conversion to integer or float for specified names
+    * default values/exceptions for missing or bad values
+    * printing a snapshot of all values retrieved for debugging
+All the 'default*' and 'bad*' arguments have "use or raise" behavior, meaning 
+that if they're a subclass of Exception, they're raised.  If they're anything
+else, that value is substituted for the missing/bad value.  
+
+The simplest usage is:
+
+    #silent $webInput(['choice'])
+    $choice
+
+    dic = self.webInput(['choice'])
+    write(dic['choice'])
+
+Both these examples retrieves the GET/POST field 'choice' and print it.  If you
+leave off the "#silent", all the values would be printed too.  But a better way
+to preview the values is
+
+    #silent $webInput(['name'], $debug=1)
+
+because this pretty-prints all the values inside HTML 
 tags.
+
+Since we didn't specify any coversions, the value is a string.  It's a "single"
+value because we specified it in 'names' rather than 'namesMulti'.  Single
+values work like this:
+    * If one value is found, take it.
+    * If several values are found, choose one arbitrarily and ignore the rest.
+    * If no values are found, use or raise the appropriate 'default*' value.
+
+Multi values work like this:
+    * If one value is found, put it in a list.
+    * If several values are found, leave them in a list.
+    * If no values are found, use the empty list ([]).  The 'default*' 
+      arguments are *not* consulted in this case.
+
+Example: assume 'days' came from a set of checkboxes or a multiple combo box
+on a form, and the user chose "Monday", "Tuesday" and "Thursday".
+
+    #silent $webInput([], ['days'])
+    The days you chose are: #slurp
+    #for $day in $days
+    $day #slurp
+    #end for
+
+    dic = self.webInput([], ['days'])
+    write("The days you chose are: ")
+    for day in dic['days']:
+        write(day + " ")
+
+Both these examples print:  "The days you chose are: Monday Tuesday Thursday".
+
+By default, missing strings are replaced by "" and missing/bad numbers by zero.
+(A "bad number" means the converter raised an exception for it, usually because
+of non-numeric characters in the value.)  This mimics Perl/PHP behavior, and
+simplifies coding for many applications where missing/bad values *should* be
+blank/zero.  In those relatively few cases where you must distinguish between
+""/zero on the one hand and missing/bad on the other, change the appropriate
+'default*' and 'bad*' arguments to something like: 
+    * None
+    * another constant value
+    * $NonNumericInputError/self.NonNumericInputError
+    * $ValueError/ValueError
+(NonNumericInputError is defined in this class and is useful for
+distinguishing between bad input vs a TypeError/ValueError
+thrown for some other reason.)
+
+Here's an example using multiple values to schedule newspaper deliveries.
+'checkboxes' comes from a form with checkboxes for all the days of the week.
+The days the user previously chose are preselected.  The user checks/unchecks
+boxes as desired and presses Submit.  The value of 'checkboxes' is a list of
+checkboxes that were checked when Submit was pressed.  Our task now is to
+turn on the days the user checked, turn off the days he unchecked, and leave
+on or off the days he didn't change.
+
+    dic = self.webInput([], ['dayCheckboxes'])
+    wantedDays = dic['dayCheckboxes'] # The days the user checked.
+    for day, on in self.getAllValues():
+        if   not on and wantedDays.has_key(day):
+            self.TurnOn(day)
+            # ... Set a flag or insert a database record ...
+        elif on and not wantedDays.has_key(day):
+            self.TurnOff(day)
+            # ... Unset a flag or delete a database record ...
+
+'source' allows you to look up the variables from a number of different
+sources:
+    'f'   fields (CGI GET/POST parameters)
+    'c'   cookies
+    's'   session variables
+    'v'   "values", meaning fields or cookies
+
+In many forms, you're dealing only with strings, which is why the
+'default' argument is third and the numeric arguments are banished to
+the end.  But sometimes you want automatic number conversion, so that
+you can do numeric comparisons in your templates without having to
+write a bunch of conversion/exception handling code.  Example:
+
+    #silent $webInput(['name', 'height:int'])
+    $name is $height cm tall.
+    #if $height >= 300
+    Wow, you're tall!
+    #else
+    Pshaw, you're short.
+    #end if
+
+    dic = self.webInput(['name', 'height:int'])
+    name = dic[name]
+    height = dic[height]
+    write("%s is %s cm tall." % (name, height))
+    if height > 300:
+        write("Wow, you're tall!")
+    else:
+        write("Pshaw, you're short.")
+
+To convert a value to a number, suffix ":int" or ":float" to the name.  The
+method will search first for a "height:int" variable and then for a "height"
+variable.  (It will be called "height" in the final dictionary.)  If a numeric
+conversion fails, use or raise 'badInt' or 'badFloat'.  Missing values work
+the same way as for strings, except the default is 'defaultInt' or
+'defaultFloat' instead of 'default'.
+
+If a name represents an uploaded file, the entire file will be read into 
+memory.  For more sophisticated file-upload handling, leave that name out of
+the list and do your own handling, or wait for Cheetah.Utils.UploadFileMixin.
+
+This mixin class works only in a subclass that also inherits from 
+Webware's Servlet or HTTPServlet.  Otherwise you'll get an AttributeError
+on 'self.request'.
+
+EXCEPTIONS: ValueError if 'source' is not one of the stated characters.
+TypeError if a conversion suffix is not ":int" or ":float".
+\end{verbatim}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{More examples}
+\label{webware.examples}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection*{Example A -- a standalone servlet}
+%\label{}
+
+% @@MO:
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection*{Example B -- a servlet under a site framework}
+%\label{}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection*{Example C -- several servlets with a common template}
+%\label{}
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Other Tips}
+\label{webware.otherTips}
+
+If your servlet accesses external files (e.g., via an \code{\#include}
+directive), remember that the current directory is not necessarily directory
+the servlet is in.  It's probably some other directory WebKit chose.  To find a
+file relative to the servlet's directory, prefix the path with whatever
+\code{self.serverSidePath()} returns (from \code{Servlet.serverSidePath()}.
+
+If you don't understand how \code{\#extends} and \code{\#implements} work, and
+about a template's main method, read the chapter on inheritance (sections
+\ref{inheritanceEtc.extends} and \ref{inheritanceEtc.implements}).  This may
+help you avoid buggy servlets.
+
+% Local Variables:
+% TeX-master: "users_guide"
+% End:      
+%# vim: sw=4 ts=4 expandtab
-- 
cgit v1.2.1