diff options
author | R. Tyler Ballance <tyler@monkeypox.org> | 2009-11-16 21:09:13 -0800 |
---|---|---|
committer | R. Tyler Ballance <tyler@monkeypox.org> | 2009-11-16 21:09:13 -0800 |
commit | d9ce7916e309e2393d824e249f512d2629e5e181 (patch) | |
tree | 6b7ad5cd6292f6e017e048fbeb4551facbabd174 | |
parent | e43765a679b84c52df875e9629d303e304af50a1 (diff) | |
download | python-cheetah-docs.tar.gz |
Revert "Delete the "old" docs directory to make way for fancy smancy sphinx"docs
This reverts commit 5dc95cfcd015628665d3672e56d0551943b5db6b.
86 files changed, 16663 insertions, 0 deletions
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) <year> by <author's name or designee>. 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 @@ +<!-- OnePageTutorial.html : + Originally this was Chuck Esterbrook's tutorial for his template + maintainers. Eventually this may expand into the future Cheetah + Quick Reference or Beginners' Guide. +--> + +<html> + +<head> +<title>Cheetah Template One-Page Tutorial</title> + +<style type="text/css"> +<!-- + +/* Document-wide styles */ + +BODY { + background-color: white; +} + + +/* Header styles */ + +TD.banner-top { + background-color: #A43403; +} +TD.banner-bottom { + background-color: #C75509; + color: #EFA84B; + font-family: sans-serif; + font-weight: normal; + font-size: 14px; +} +TD.banner-bottom-active { + background-color: #C75509; + color: #EFA84B; + font-family: sans-serif; + font-weight: normal; + font-size: 14px; +} +TD.banner-bottom-inactive { + background-color: #C75509; + color: #EFA84B; + font-family: sans-serif; + font-weight: normal; + font-size: 14px; +} +SPAN.banner-bottom-active { + background-color: #A43403; + color: #EFA84B; + font-family: sans-serif; + font-weight: bold; + font-size: 14px; +} +SPAN.banner-bottom-inactive { + background-color: #C75509; + color: #EFA84B; + font-family: sans-serif; + font-weight: bold; + font-size: 14px; +} + + + +TD.banner-menu { + background-color: #A43403; + color: #EFA84B; + font-family: sans-serif; + font-weight: normal; + font-size: 14px; +} +SPAN.banner-menu { + background-color: #A43403; + color: #EFA84B; + font-family: sans-serif; + font-weight: bold; + font-size: 14px; +} + + + + + +/* Interface body styles */ + + +A:link { + color: #00638E; + font-family: sans-serif; + font-weight: bold; + text-decoration: none; +} + +/* A:visited */ +/* A:active */ + +TD.action-header { + color: #7A311C; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-weight: bold; + font-size: 16px; +} + +TD.body { + color: #C75509; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-weight: normal; + font-size: 14px; +} +SPAN.doc_title { + color: #666666; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-weight: normal; + font-size: 12px; +} + +P.instructions { + color: #C75509; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-weight: normal; + font-size: 12px; +} + + + /* + * Top level page + */ + + body { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 80%; + background-color: #FFFFFF; + color: black; + } + + p { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 12px; + color: black; + } + + table.banner { + width: 100%; + } + + td.bannerLogo { + color: #FFA; + background-color: orange; + text-align: center; + border: 2px solid #FFA; + padding-left: 3px; + padding-right: 3px; + letter-spacing: -2px; + white-space: nowrap; + font-family: Arial, Helvetica, sans-serif; + font-weight: bold; + font-size: 18px; + } + + td.bannerTitle { + width: 95%; + color: darkorange; + text-align: center; + font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; + font-weight: bold; + font-size: 24px; + } + + td.bannerStuff { + text-align: right; + white-space: nowrap; + font-family: Arial, Helvetica, sans-serif; + } + + a.bannerStuff { + text-decoration: none; + } + + a.bannerStuff:hover { + text-decoration: underline; + } + + span.pageFooter { + } + + a.mainMenuLink { + font-size: 175%; + } + + .error { + color: red; + } + + /* + * Tab navigation + */ + + tr.tabTop { + font-size: 14px; + } + + tr.tabBottom { + background-color: #149; + } + + td.activeTab { + font-family: Arial, Helvetica, sans-serif; + font-weight: bold; + color: #FFA; + background-color: #149; + } + + td.inactiveTab { + font-family: Arial, Helvetica, sans-serif; + color: #FFA; + background-color: #DEF; + } + + a.activeTab { + color: #FFA; + text-decoration: none; + } + + a.activeTab:hover { + color: #FFA; + text-decoration: underline; + } + + a.inactiveTab { + color: black; + text-decoration: none; + } + + a.inactiveTab:hover { + color: black; + text-decoration: underline; + } + + /* + * Panels + */ + + table.panel { + } + + tr.panelTitle { + font-weight: bold; + background-color: lightblue; + } + + td.panelTitle { + } + + tr.panelBody { + background-color: #EEEEEE; + } + + + /* + * Other + */ + + table.ObjectBrowser { + } + + tr.ObjectBrowser{ + } + + /* This is for a body row of the document list table */ + td.ObjectBrowserBody { + background-color: #EEE; + } + + /* This is for the header row of the document list table */ + td.ObjectBrowserHeader { + background-color: #C6EFF7; + font-weight: bold; + } + + td.ObjectBrowserLink { + background-color: #DEF3BD; + font-weight: bold; + } + + table.ObjectViewer { + } + + tr.ObjectViewer { + } + + /* This is for the name column of the object view table */ + td.ObjectViewerName { + background-color: #C6EFF7; + font-weight: bold; + } + + /* This is for the value column of the object view table */ + td.ObjectViewerValue { + background-color: #EEE; + } + + /* This is for the info column of the object view table */ + td.ObjectViewerInfo { + background-color: white; + } + + table.ObjectEditor { + } + + tr.ObjectEditor { + } + + /* This is for the section label of the document edit table */ + td.ObjectEditorSection { + background-color: #E6E6E6; + font-weight: bold; + font-size: 18px; + color: #AC003B; + } + + /* This is for the field name column of the document edit table */ + td.ObjectEditorName { + background-color: white; + font-weight: bold; + } + + /* This is for the field value column of the document edit table */ + td.ObjectEditorValue { + background-color: white; + } + + /* This is for the info column of the object edit table */ + td.ObjectEditorInfo { + background-color: white; + } + + /* This is for the error column of the object edit table */ + td.ObjectEditorError { + background-color: white; + color: red; + font-weight: bold; + font-size: 12px; + } + + + /* + * Help + */ + + blockquote.example { + background-color: #EEE; + } + + + /*********************** from other site *********************/ + + td.ColumnHeading { + font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; + font-size: 150%; + font-weight: bold; + background-color: #FFFF77; + } + + + /* + * Sidebar + */ + + span.SidebarHeading { + font-weight: bold; + } + + a.SidebarLink { + } + + + /* + * News + */ + + span.NewsHeading { + font-family: Tahoma; + font-size: 14px; + font-weight: bold; + } + + + /* + * Headings + */ + + h1 { + font-family: Arial, Helvetica; + font-size: 14px; + padding-top: 1em; + padding-bottom: 0; + } + + /* + * Other + */ + + h2 { font-family: Arial, Helvetica; + font-size: 14px; + color: darkblue; + padding-top: 1em; + padding-bottom: 0; + } + h3 { font-family: Arial, Helvetica; + font-size: 13px; + padding-top: 1em; + padding-bottom: 0; + } + h4 { font-family: Arial, Helvetica; + font-size: 12px; + padding-top: 1em; + padding-bottom: 0; + } + dl { padding-left: 2em; + } + ol { padding-left: 0.5em; + } + ul { list-style-type: disc; + padding-left: 1.0em; + } + li { padding-top: 0em; + } + table { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 100%; + color: black; + } + +--> +</style> + +</head> + +<body> + +<h1>Cheetah Template One-Page Tutorial<BR> +<SMALL>By Chuck Esterbrook, now maintained by Mike Orr<BR> +Updated May 17, 2002</SMALL></h1> + +<h2>Substitution</h2> + +<p> The most commonly used templating feature is substitution: + +<blockquote class=example><pre> +My name is $name +</pre></blockquote> + +<p> You can use <i>dotted notation</i> to traverse objects. For example: + +<blockquote class=example><pre> +$author.person.primaryEmail +</pre></blockquote> + +<p> When a variable name is flush against other text you must use curly braces to separate it: + +<blockquote class=example><pre> +Jim is a ${vice}maniac. +</pre></blockquote> + +<p> However, the template language is savvy enough to handle sentence endings and variables: + +<blockquote class=example><pre> +My name is $name. +$foo$bar +</pre></blockquote> + + +<h2>#if (conditional)</h2> + +<p> The <i>#if</i> 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. + +<blockquote class=example><pre> +#if $keywords + $keywords +#else + There are no keywords! +#end if +</pre></blockquote> + +<p> The #else part is optional: + +<blockquote class=example><pre> +#if $keywords + <span class=keywords>$keywords</span> +#end if +</blockquote> + + +<h2>#for (looping)</h2> + +<p> The <i>#for</i> statement is used to loop through any kind of list. + +<blockquote class=example><pre> +#for $author in $authors + $author.person.fullName +#end for +</pre></blockquote> + + +<h2>Combining statements</h2> + +<p> You can combine statements. For example, + +<p> Template.html: +<blockquote class=example><pre> +$name + +<p> $content + +#include "authors.html" +</pre></blockquote> + +Authors.html: +<blockquote class=example><pre> +#if $authors + <table class=Author> + #for $author in $authors + <tr class=Author> <td class=Author> + $author + </td> </tr> + #end for + </table> +#end if +</pre></blockquote> + + +<h2>Examples</h2> + +<p> 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. + +<blockquote class=example><pre> +#set sep = '' +#for $author in $authors +${sep}${author.person}#slurp +#set sep = ', ' +#end for +</pre></blockquote> + +</body> + +</html> 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': <NameMapper.NotFound instance at 0x8170ecc>, + 'lineCol': (3, 1), + 'rawCode': '$noValue', + 'time': 'Wed May 15 00:38:23 2002'}, + {'code': 'VFS(SL,"anotherMissingValue.really",1)', + 'exc_val': <NameMapper.NotFound instance at 0x816d0fc>, + '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 <built-in function xrange>. + +>>> print t.generatedModuleCode() + 1 #!/usr/bin/env python + + 2 """ + 3 Autogenerated by CHEETAH: The Python-Powered Template Engine + 4 CHEETAH VERSION: 0.9.12 + 5 Generation time: Sun Apr 21 00:53:01 2002 + 6 """ + + 7 __CHEETAH_genTime__ = 'Sun Apr 21 00:53:01 2002' + 8 __CHEETAH_version__ = '0.9.12' + + 9 ################################################## + 10 ## DEPENDENCIES + + 11 import sys + 12 import os + 13 import os.path + 14 from os.path import getmtime, exists + 15 import time + 16 import types + 17 from Cheetah.Template import Template + 18 from Cheetah.DummyTransaction import DummyTransaction + 19 from Cheetah.NameMapper import NotFound, valueForName, + valueFromSearchList + 20 import Cheetah.Filters as Filters + 21 import Cheetah.ErrorCatchers as ErrorCatchers + + 22 ################################################## + 23 ## MODULE CONSTANTS + + 24 try: + 25 True, False + 26 except NameError: + 27 True, False = (1==1), (1==0) + + 28 ################################################## + 29 ## CLASSES + + 30 class GenTemplate(Template): + 31 """ + 32 + 33 Autogenerated by CHEETAH: The Python-Powered Template Engine + 34 """ + + 35 ################################################## + 36 ## GENERATED METHODS + +\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} +<ul> +<dtml-in frogQuery> + <li><dtml-var animal_name></li> +</dtml-in> +</ul> +\end{verbatim} + +\begin{verbatim} +<ul> +#for $animal_name in $frogQuery + <li>$animal_name</li> +#end for +</ul> +\end{verbatim} + +\begin{verbatim} +<dtml-if expr="monkeys > monkey_limit"> + <p>There are too many monkeys!</p> +<dtml-elif expr="monkeys < minimum_monkeys"> + <p>There aren't enough monkeys!</p> +<dtml-else> + <p>There are just enough monkeys.</p> +</dtml-if> +\end{verbatim} + +\begin{verbatim} +#if $monkeys > $monkey_limit + <p>There are too many monkeys!</p> +#else if $monkeys < $minimum_monkeys + <p>There aren't enough monkeys!</p> +#else + <p>There are just enough monkeys.</p> +#end if +\end{verbatim} + +\begin{verbatim} +<table> +<dtml-in expr="objectValues('File')"> + <dtml-if sequence-even> + <tr bgcolor="grey"> + <dtml-else> + <tr> + </dtml-if> + <td> + <a href="&dtml-absolute_url;"><dtml-var title_or_id></a> + </td></tr> +</dtml-in> +</table> +\end{verbatim} + +\begin{verbatim} +<table> +#set $evenRow = 0 +#for $file in $files('File') + #if $evenRow + <tr bgcolor="grey"> + #set $evenRow = 0 + #else + <tr> + #set $evenRow = 1 + #end if + <td> + <a href="$file.absolute_url">$file.title_or_id</a> + </td></tr> +#end for +</table> +\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{<dtml-in>} tag. We are also planning an output filter as flexible as +the \code{<dtml-var>} 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{<!-- BEGIN blockName --> \ldots + <!-- END blockName>}. The \code{set\_block} method extracts this text + into a namespace variable and puts a placeholder referring to it in the + template. This has a few parallels with Cheetah's \code{\#block} + directive but is overall quite different. +\item To do the equivalent of \code{\#if}, extract the block. Then if true, do + nothing. If false, assign the empty string to the namespace variable. +\item To do the equivalent of \code{\#for}, extract the block. Set any + namespace variables needed inside the loop. To parse one iteration, use + the \code{parse} method to fill the block variable (a mini-template) into + another namespace variable, appending to it. Refresh the namespace + variables needed inside the loop and parse again; repeat for each + iteration. You'll end up with a mini-result that will be plugged into the + main template's placeholder. +\item To read a template definition from a file, use the \code{set\_file} + method. This places the file's content in a namespace variable. + To read a template definition from a string, assign it to a namespace + variable. +\item Thus, for complicated templates, you are doing a lot of recursive block + filling and file reading and parsing mini-templates all into one flat + namespace as you finally build up values for the main template. In + Cheetah, all this display logic can be embedded into the template using + directives, calling out to Python methods for the more complicated tasks. +\item Although you can nest blocks in the template, it becomes tedious and + arguably hard to read, because all blocks have identical syntax. Unless + you choose your block names carefully and put comments around them, it's + hard to tell which blocks are if-blocks and which are for-blocks, or what + their nesting order is. +\item PHPLib templates do not have caching, output filters, etc. +\end{itemize} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. PSP, PHP, ASP, JSP, Embperl, etc.} +\label{comparisons.pspEtc} + +\begin{description} +\item[Webware's PSP Component] -- \url{http://webware.sourceforge.net/Webware/PSP/Docs/} +\item[Tomcat JSP Information] -- \url{http://jakarta.apache.org/tomcat/index.html} +\item[ASP Information at ASP101] -- \url{http://www.asp101.com/} +\item[Embperl] -- \url{http://perl.apache.org/embperl/} +\end{description} + + +Here's a basic Cheetah example: +\begin{verbatim} +<TABLE> +#for $client in $service.clients +<TR> +<TD>$client.surname, $client.firstname</TD> +<TD><A HREF="mailto:$client.email" >$client.email</A></TD> +</TR> +#end for +</TABLE> +\end{verbatim} + +Compare this with PSP: + +\begin{verbatim} +<TABLE> +<% for client in service.clients(): %> +<TR> +<TD><%=client.surname()%>, <%=client.firstname()%></TD> +<TD><A HREF="mailto:<%=client.email()%>"><%=client.email()%></A></TD> +</TR> +<%end%> +</TABLE> +\end{verbatim} + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_2_src/01_introduction.txt b/docs/users_guide_2_src/01_introduction.txt new file mode 100755 index 0000000..34beeb6 --- /dev/null +++ b/docs/users_guide_2_src/01_introduction.txt @@ -0,0 +1,291 @@ +Introduction +============ + +.. + :label: intro + +Who should read this Guide? +--------------------------- + +.. + :label: intro.whoShouldRead + +This Users' Guide is for Python programmers. Part I is a tutorial/reference +and should be read by everybody. Part II is a cookbook of of techniques for +using Cheetah with various web frameworks and various non-HTML output formats, +plus some technical appendices. The PDF version of this Guide is distributed +as two files so you can print Part I to read offline without having to print a +lot of pages from Part II that don't apply to you. + +What is Cheetah? +---------------- + +.. + :label: intro.whatIs + +Cheetah is a template engine for Python. A template engine is like Python's +``%`` operator for strings: it has fixed parts which are output verbatim, and +*placeholders* which are replaced by their values:: + + # Python's "%" operator (not Cheetah) + >>> "The king is a %(noun)s!" % {"noun": "fink"} + 'The king is a fink!" + +Templates are useful for form letters, dynamic web pages, customized source +code or SQL, and innumerable other tasks. Cheetah is like a super-powered +``%`` operator, but it also has many other features needed in real-world +templating situations. + +Viewed another way, Cheetah is an alternate source format for Python modules, +one that's friendlier for large chunks of text. Compiled templates are +ordinary Python modules which can be imported. Cheetah is one of Python's +oldest template engines and perhaps the most widely used. This is mainly due +to its speed (hence the name Cheetah), stability, and suitability for many +output formats. Cheetah has been used in production environments since 2001 +(0.9.9a1), and changes are committed conservatively, so even the CVS version is +usually more bug-free than the previous release. + +Cheetah's syntax uses ``$`` before placeholders and a ``#`` +before control structures (directives), although these characters can be +changed. This differs from Python's other template systems which generally use +XML tags (Kid and Tal) or a function syntax (PTL and QPY). The difference +allows Cheetah to be more suitable for a variety of output formats, and even +users of the other systems often use Cheetah for non-HTML output such as +text, Python source code, or SQL. Cheetah's syntax and behavior was +inspired most directly by Velocity, a Java template engine. In PHP, Smarty is +Cheetah's closest equivalent. Cheetah templates tend to be function-driven: +define a method with ``#def``, and call it via a placeholder with arguments. +Cheetah also has PSP-style tags (``<% %>``) and ``#include``, which will be +familiar to people coming from ASP/JSP/PHP. However, we'll argue that these +should be used sparingly, since there are other constructs which are more +readable. + + +Cheetah: + +* generates HTML, SGML, XML, SQL, Postscript, form email, LaTeX, or any + other text-based format. It has also been used to produce Python, Java + and PHP source code. + +* cleanly separates content, graphic design, and program code. This leads + to highly modular, flexible, and reusable site architectures; faster + development time; and HTML and program code that is easier to understand + and maintain. It is particularly well suited for team efforts. + +* blends the power and flexibility of Python with a simple template language + that non*programmers can understand. + +* gives template writers full access in their templates to any Python data + structure, module, function, object, or method. + +* makes code reuse easy by providing an object-oriented interface to + templates that is accessible from Python code or other Cheetah templates. + One template can subclass another and selectively reimplement sections of + it. A compiled template {\em is} a Python class, so it can subclass a + pure Python class and vice*versa. + +* provides a simple yet powerful caching mechanism + +Here's a simple example of a Cheetah template:: + + <HTML> + <HEAD><TITLE>$title</TITLE></HEAD> + <BODY> + + <TABLE> + #for client in clients + <TR> + <TD>$client.surname, $client.firstname</TD> + <TD><A HREF="mailto:$client.email">$client.email</A></TD> + </TR> + #end for + </TABLE> + + </BODY> + </HTML> + +* has a lot of features but most of them are optional. Cheetah is easy to use + in simple cases, and scales well to complex cases. Most of Cheetah's + features were added due to demonstrated needs in production environments + where Cheetah was already runing. + +Cheetah is distributed under a BSD-style open-source license. See appendix E +(E_license.txt) for details. Cheetah exists thanks to the help of many +open-source volunteers (http://cheetahtemplate.sourceforge.net/credits.html). + + + +What is the philosophy behind Cheetah? +-------------------------------------- + +.. + :label: intro.philosophy + +Cheetah's design was guided by these principles: + +* Python for the back end (business logic), Cheetah for the front end + (presentation format). Cheetah was designed to complement Python, not + replace it. + +* Cheetah's core syntax should be easy for non-programmers to learn. + +* Cheetah should make code reuse easy by providing an object-oriented + interface to templates that is accessible from Python code or other + Cheetah templates. + +* Python objects, functions, and other data structures should be fully + accessible in Cheetah. + +* Cheetah should provide flow control and error handling. Logic + that belongs in the front end shouldn't be relegated to the + back end simply because it's complex. + +* It should be easy to {\bf separate} content, graphic design, and program + code, but also easy to {\bf integrate} them. + + A clean separation makes it easier for a team of content writers, + HTML/graphic designers, and programmers to work together without stepping + on each other's toes and polluting each other's work. The HTML framework + and the content it contains are two separate things, and analytical + calculations (program code) is a third thing. Each team member should be + able to concentrate on their specialty and to implement their changes + without having to go through one of the others (i.e., the dreaded + "webmaster bottleneck"). + + While it should be easy to develop content, graphics and program + code separately, it should be easy to integrate them together into a + website. In particular, it should be easy: + + - for {\bf programmers} to create reusable components and functions + that are accessible and understandable to designers. + - for {\bf designers} to mark out placeholders for content and + dynamic components in their templates. + - for {\bf designers} to soft-code aspects of their design that are + either repeated in several places or are subject to change. + - for {\bf designers} to reuse and extend existing templates and thus + minimize duplication of effort and code. + - and, of course, for {\bf content writers} to use the templates that + designers have created. + +* Features are added only to support a demonstrated need in production + applications, and generally only if the feature is useful for a wide variety + of situations and output formats. This prevents Cheetah from accumulating + lots of esoteric features which are used only rarely. + + +Why Cheetah doesn't use HTML-style tags +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +.. + :label: intro.htmlStyleTags + +Cheetah does not use HTML/XML-style tags for flow control, unlike some other +Python template engines, for the following reasons: + +* Cheetah is not limited to HTML, +* HTML-style tags are hard to distinguish from real HTML tags, +* HTML-style tags are not visible in rendered HTML when something goes wrong, +* HTML-style tags often lead to invalid HTML (e.g., + \code{<img src="<template*directive>">}), + +Cheetah tags are less verbose and easier to understand than HTML-style tags, +and HTML-style tags aren't compatible with most WYSIWYG editors. In a WSYWIG +editor, Cheetah tags appear to be literal text. + +Besides being much more compact, Cheetah also has some advantages over +languages that put information inside the HTML tags, such as Zope Page +Templates or PHP: + +* HTML or XML-bound languages do not work well with other languages, +* While ZPT-like syntaxes work well in many ways with WYSIWYG HTML editors, + they also give up a significant advantage of those editors -- concrete + editing of the document. When logic is hidden away in (largely + inaccessible) tags it is hard to understand a page simply by viewing it, + and it is hard to confirm or modify that logic. + + +How stable is Cheetah? How do I upgrade? +----------------------------------------- + +.. + :label: intro.stable + +Cheetah 2.0 was released [MONTH] [YEAR] with internal restructuring, +easier-to-understand usage, updated documentation, and many other improvements. +Cheetah 1.0 was released December 2005 after a three-year stable beta. +Production sites have been using Cheetah since 2001. Most changes since then +have been based on requests from production sites: things they need that we +hadn't considered. + +Templates and calling code from Cheetah 1.0 remain 100% compatible. Those from +pre-1.0 versions since December 2001 (0.9.9) remain compatible except in rare +cases. + +.. important:: + You must recompile all precompiled templates when upgrading + to Cheetah 2.0. + +Upgrades from 2.0 to a future version may or may not require +recompilation. Try filling a single precompiled template and see if you get a +version exception. If you do, recompile them all. Or to be safe on a +production site, just recompile them all anyway. + +Cheetah's development version is normally as stable as the last release if not +better. All CVS checkins are installed and run through the test suite before +being checked in. + +Additional information is in these files in the Cheetah source distribution: + +CHANGES: + All changes in each version. +BUGS: + Known bugs we haven't fixed yet. +TODO: + Enhancements we're planning, thing's like to do someday, and user requests + we haven't committed to. + + +Web site and mailing list +------------------------- + +.. + :label: intro.news + +Cheetah releases and other stuff can be obtained from the the Cheetah +{\bf Web site}: +\url{http://CheetahTemplate.sourceforge.net} + +Cheetah discussions take place on the {\bf mailing list} +\email{cheetahtemplate-discuss@lists.sourceforge.net}. This is where to hear +the latest news first. + +If you encounter difficulties, or are unsure about how to do something, +please post a detailed message to the list. Also please share your +experiences, tricks, customizations, and frustrations. And if you have a +success story for the "Who Is Using Cheetah" +(http://cheetahtemplate.sourceforge.net/whouses.html) or +"Testimonials" (http://cheetahtemplate.sourceforge.net/praise.html) +page on the website, send it to the mailing list. + + +Bug reports, patches, and the test suite +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +If you think there is a bug in Cheetah, send a message to the mailing list +with the following information: + +* a description of what you were trying to do and what happened +* all tracebacks and error output +* your version of Cheetah +* your version of Python +* your operating system +* whether you have changed anything in the Cheetah installation + +Cheetah is packaged with a regression testing suite that is run with each +new release to ensure that everything is working as expected and that recent +changes haven't broken anything. The test cases are in the Cheetah.Tests +module. If you find a reproduceable bug please consider writing a test case +that will pass only when the bug is fixed. Send any new test cases to the email +list with the subject-line "new test case for Cheetah". (@@MO Shorten +paragraph, link to testing section.) + diff --git a/docs/users_guide_2_src/02_glossary.txt b/docs/users_guide_2_src/02_glossary.txt new file mode 100644 index 0000000..49988fd --- /dev/null +++ b/docs/users_guide_2_src/02_glossary.txt @@ -0,0 +1,66 @@ +Glossary +======== + +.. + :label: glossary + +**Template** is an informal term meaning a template definition, a template +class or a template instance. A **template definition** is what the human +maintainer writes: a file or string consisting of text, placeholders and +directives. **Placeholders** are variables that will be looked up when the +template is filled. **Directives** are commands to be executed when the +template is filled, or instructions to the Cheetah compiler. Placeholders +normally start with "$"; directives with "#". The conventional suffix for a +file containing a template definition is **.tmpl**. + +To use a template, you first **compile** the template definition into +**template class**. Then you instantiate the class and **fill** it by calling +one of its instance methods. Filling does all the placeholder lookups and +returns the finished result. Templates can be compiled in memory or written to +a Python module, called a **precompiled template**. + +Every template has a **main** method that fills the entire template. The main +method is usually ``.respond()``. Calling ``str()`` or ``unicode()`` on a +template instance is the same as calling the main method. Templates can also +contain **#def methods** (via ``#def`` or ``#block``), which can be called +directly. + +A **placeholder** consists of one or more **identifiers** separated by periods. +Identifiers must follow the same rules as Python variable names, and may be +followed by the usual ``[]`` and ``()`` as in Python. Example with three +identifiers: ``a.b[2].c("arg")``. The value discovered at fill time is the +**placeholder value**. + +The first (or only) identifier of a placeholder name represents a **variable** +to be looked up. If Cheetah's **NameMapper** is turned on (the default), it +looks in various **namespaces** including the template instance's ``self``, +Python variables local/global to the template method, and an arbitrary list of +**user-defined namespaces** you may have passed to the template constructor. +A user-defined namespace is any Python object; Cheetah searches its attributes +and keys for a matching name. ``#set`` and ``#for`` create local +variables. ``#import`` and ``#set module global`` create global variables. +``#attr``, ``#def``, and ``#block`` create ``self`` variables. When the +NameMapper is turned off, only local/global variables are accessible. + +The NameMapper also handles universal dotted notation and autocalling. +**Universal dotted notation** means that keys may be written as if they were +attributes: ``a.b`` instead of ``a['b']``. **Autocalling** means that +if any identifier's value is found to be a function or method, Cheetah will +call it without arguments if there is no ``()`` following. More about the +NameMapper is in section \ref{language.namemapper}. + +Cheetah 1 used the term "searchList" for user-defined namespaces. However, +Cheetah has another **search list** internally: the actual list of namespaces +it consults. This is almost the same thing but not quite. To avoid confusion, +this Guide uses the term "search list" only for the internal list. + +Some directives are multi-line, meaning they have a matching **\#end** tag. +The lines of text between the start and end tags is the **body** of the +directive. Arguments on the same line as the start tag, in contrast, are +considered part of the directive tag. + +A **template-servlet** is a Webware_-specific construct. Any .py template +module in a Webware servlet directory can be filled directly through the web by +requesting the URL. + +.. _Webware: http://www.webwareforpython.org/ diff --git a/docs/users_guide_2_src/03_gettingStarted.txt b/docs/users_guide_2_src/03_gettingStarted.txt new file mode 100755 index 0000000..6e447c2 --- /dev/null +++ b/docs/users_guide_2_src/03_gettingStarted.txt @@ -0,0 +1,262 @@ +Getting Started +======================================== + +.. + :label: gettingStarted + + +Requirements +---------------------------------------- + +.. + :label: gettingStarted.requirements + +Cheetah requires Python release 2.2 or newer, and has been tested with all +versions through 2.4.2. It should run everywhere Python runs, and has been +tested on Linux, Windows NT/98/XP, FreeBSD, Solaris, and Mac OS X. + +99% of Cheetah is written in Python. There is one small C module +(``_namemapper.so``) for speed, but Cheetah automatically falls back to a +Python equivalent (``NameMapper.py``) if the C module is not available. + + +Installation +---------------------------------------- + +.. + :label: gettingStarted.install + +If you have ``easy_install`` +(http://peak.telecommunity.com/DevCenter/EasyInstall) set up, this command will +download and install the latest version of Cheetah as a Python Egg +(http://peak.telecommunity.com/DevCenter/PythonEggs):: + + # easy_install Cheetah + +Or from an already-downloaded tarball:: + + # easy_install Cheetah-2.0.tar.gz + +Or from an unpacked source directory or CVS sandbox:: + + # easy_install . + +If you don't have ``easy_install``, you'll have to install Cheetah manually:: + + # tar xzvf Cheetah-2.0.tar.gz + # cd Cheetah-2.0 + # python setup.py install + +You can also specify non-default locations:: + + # python setup.py install --install-lib=/home/tavis/python + # python setup.py install --home=/home/tavis + # python setup.py install --help + +.. tip:: + + If you install Cheetah manually and then install an egg that depends on + Cheetah (like TurboCheetah_), ``easy_install`` may *reinstall* + Cheetah as an egg. This leaves two copies of Cheetah on your system, + possibly different versions. Python will use whichever version comes + first in the Python path. To avoid this, use ``easy_install``'s + **--no-deps** option or delete the copy you don't wish to use. + + +Uninstalling +---------------------------------------- + +.. + :label: gettingstarted.uninstalling + +To uninstall Cheetah: + +1. Delete the "cheetah" program +from whichever bin/ directory it was put in (perhaps /usr/local/bin/). + +2. If Cheetah was installed as an egg, delete the egg directory +(e.g., /usr/local/lib/python2.4/site-packages/Cheetah-2.0-py2.4.egg/), and +remove the "Cheetah" line in **easy-install.pth** in the same directory. + +3. If Cheetah was not installed as an egg, delete the package directory +(e.g., /usr/local/lib/python2.4/site-packages/Cheetah/). + + +The 'cheetah' command +---------------------------------------- + +.. + :label: gettingStarted.cheetah + +Cheetah comes with a utility "cheetah" that provides a command-line +interface to various housekeeping tasks. The command's first argument is +the name of the task. The following commands are currently supported:: + + cheetah compile [options] [FILES ...] : Compile template definitions + cheetah fill [options] [FILES ...] : Fill template definitions + cheetah help : Print this help message + cheetah options : Print options help message + cheetah test : Run Cheetah's regression tests + cheetah version : Print Cheetah version number + +You only have to type the first letter of the command: +``cheetah c`` is the same as ``cheetah compile``. + +The test suite is described in the next section. The ``compile`` +command in section \ref{howWorks.cheetah-compile}, +and the ``fill`` command in section \ref{howWorks.cheetah-fill}. + + +Testing your installation +---------------------------------------- + +.. + :label: gettingStarted.test + +After installing Cheetah, you can run its self-test routine to verify it's +working properly on your system. First cd to to any directory you have write +permission in (the tests write temporary files) *except* the unpacked Cheetah +source directory (it might produce spurious errors). Type the following at the +command prompt:: + + $ cheetah test + +The tests will run for about three minutes and print a success/failure +message. If the tests pass, start Python in interactive mode and try the +example in the next section. + +Sometimes the CheetahWrapper tests fail on Windows because they can't execute +"cheetah" via ``os.system()``. Ignore these; you won't be doing this when +you use Cheetah. + +If any other tests fail, please send a message to the e-mail list with a copy +of the test output and the following details about your installation: + +* your version of Cheetah +* your version of Python +* your operating system +* whether you have changed anything in the Cheetah installation + + + +Quickstart tutorial +---------------------------------------- + +.. + :label: gettingStarted.tutorial + +This tutorial briefly introduces how to use Cheetah from the Python prompt. +The following chapters will discuss other ways to use templates and more of +Cheetah's features. + +The core of Cheetah is the ``Template`` class in the ``Cheetah.Template`` +module. The following example shows how to use the ``Template`` class in an +interactive Python session. ``t`` is the Template instance. Lines prefixed +with ``>>>`` and ``...`` are user input. The remaining lines are Python +output. :: + + >>> from Cheetah.Template import Template + >>> templateDef = """ + ... <HTML> + ... <HEAD><TITLE>$title</TITLE></HEAD> + ... <BODY> + ... $contents + ... ## this is a single-line Cheetah comment and won't appear in the output + ... #* This is a multi-line comment and won't appear in the output + ... blah, blah, blah + ... *# + ... </BODY> + ... </HTML>""" + >>> namespace = {'title': 'Hello World Example', 'contents': 'Hello World!'} + >>> t = Template(templateDef, namespaces=[namespace]) + >>> print t + + <HTML> + <HEAD><TITLE>Hello World Example</TITLE></HEAD> + <BODY> + Hello World! + </BODY> + </HTML> + >>> print t # print it as many times as you want + [ ... same output as above ... ] + >>> namespace['title'] = 'Example #2' + >>> namespace['contents'] = 'Hiya Planet Earth!' + >>> print t # Now with different plug-in values. + <HTML> + <HEAD><TITLE>Example #2</TITLE></HEAD> + <BODY> + Hiya Planet Earth! + </BODY> + </HTML> + +Because Cheetah is extremely flexible, you can achieve the same result this +way:: + + >>> t2 = Template(templateDef) + >>> t2.title = 'Hello World Example!' + >>> t2.contents = 'Hello World' + >>> print t2 + [ ... same output as the first example above ... ] + >>> t2.title = 'Example #2' + >>> t2.contents = 'Hello World!' + >>> print t2 + [ ... same as Example #2 above ... ] + +Or the values can be extracted from an object's attributes. + + >>> myInstance.title + 'Hello World Example!' + >>> myInstance.contents = 'Hello World!' + >>> t2 = Template(templateDef, namespaces=[myInstance]) + +The template will search your namespaces in order, then its own ``self`` +attributes, until it finds a match. The template definition can also +come from a file rather than a string. + +Let's look at the ``Template`` constructor again:: + + t = Template(templateDef, namespaces=[namespace]) + +This does more than it appears. It compiles the template definition into a +template class, a subclass of ``Template``, and instantiates it. Sometimes +it's desirable to separate these operations, and the ``.compile`` class method +does this:: + + tclass = Template.compile(templateDef) + t = tclass(namespaces=[namespace]) + +The first line compiles the template class; the second line instantiates it. +You can also do this on one line:: + + t = Template.compile(templateDef)(namespaces=[namespace]) + +You can use either ``Template()`` or ``Template.compile()`` in your programs, +but you should learn both styles so you'll recognize them in other people's +code. + +This is all fine for short templates, but for long templates or for an +application that depends on many templates, it's easier to store the templates +in separate \*.tmpl files and use the **cheetah** program to compile +them into Python modules. This will be covered in section +\ref{howWorks.cheetah-compile}. Here's how you use a precompiled template:: + + >>> from MyPrecompiledTemplate import MyPrecompiledTemplate + >>> t = MyPrecompiledTemplate() + >>> t.name = "Fred Flintstone" + >>> t.city = "Bedrock City" + >>> print t + +Or:: + + >>> from MyPrecompiledTemplate import MyPrecompiledTemplate + >>> namespace = {"name": "Fred Flintstone", "city": "Bedrock City"} + >>> t = MyPrecompiledTemplate(namespaces=[namespace]) + >>> print t + +For the minimalists out there, here's a template compilation, +instantiation and filling all in one Python statement:: + + >>> print Template("Templates are pretty useless without placeholders.") + Templates are useless without placeholders. + +.. _TurboCheetah: http://python.org/pypi/TurboCheetah/ diff --git a/docs/users_guide_2_src/04_howItWorks.txt b/docs/users_guide_2_src/04_howItWorks.txt new file mode 100755 index 0000000..17ee3d5 --- /dev/null +++ b/docs/users_guide_2_src/04_howItWorks.txt @@ -0,0 +1,369 @@ +How Cheetah Works +================= + +.. + :label: howWorks + + + +Constructing Template Objects +----------------------------- + +.. + :label: howWorks.templateClass + +.. + :label: howWorks.constructing + +The heart of Cheetah is the ``Template`` class in the +``Cheetah.Template`` module. There are several ways to construct templates, +each with slightly different arguments. Where *source* is shown, it's always +the first argument and may be specified positionally. The order of the +other arguments may change, so always specify them as keyword arguments. + +``Template()`` accepts the following arguments: + + source + The template definition as a string. The source can be a string + literal in your module, or perhaps a string you read from a database + or other data structure. + + file + A filename or file object containing the template definition. A + filename must be a string, and a file object must be open for reading. + By convention, template definition files have the extension **.tmpl**. + + namespaces, searchList + A list of objects which Cheetah will search for placeholder values. + (Cheetah also searches certain other objects automatically; see the + "Placeholders" chapter for details.) Use either argument; they both + mean the same thing. + + filter + Equivalent to putting ``#filter`` at the top of the template. The + argument may be a subclass of ``Cheetah.Filters.Filter``, or a string + naming a class in filtersLib (the next argument below). See + ``#filter`` for details. + + filtersLib + A module containing the filters Cheetah should look up by name. The + default is ``Cheetah.Filters``. All classes in this module that are + subclasses of ``Cheetah.Filters.Filter`` are considered filters. + + errorCatcher + Equivalent to putting ``#errorCatcher`` at the top of the template. + The object may be a subclass of ``Cheetah.ErrorCatchers.ErrorCatcher``, + or a string naming a class in ``Cheetah.ErrorCatchers``. See + ``#errorCatcher`` for details. + + compilerSettings + Equivalent to putting ``#compiler-settings`` at the top of the + template. The argument is a dictionary or nesting of dictionaries. + See ``#compiler-settings`` for details. + +A template class returned by ``Cheetah.compile`` or precompiled via "cheetah +compile" takes the same constructor arguments as above, except "source" and +"file" which are not allowed. Use keyword arguments for all arguments +because their order may change. + +The class method ``Template.compile()`` takes the following +arguments: + + source, file, compilerSettings + Same as above. *These are the only arguments most users will ever + use.* The other args below are for specialized advanced uses. + + returnAClass + If true (default), return a subclass of ``Template`` specific to this + template definition. If false, return the Python source of a module + containing this class; i.e., what "cheetah compile" would write to a + file. + + moduleName, className, mainMethodName + Override the default names. For instance, TurboCheetah (a third-party + library) requires its templates to have a fixed class name, so it uses + *className*. + + compilerClass + Use an You'll probably never need this. + + baseclass + Equivalent to putting ``#extends`` at the top of the template. + ``#extends`` overrides this, unlike other arguments. + + moduleGlobals + In case you want to sneak in some extra variables that don't require + the NameMapper. + + preprocessors + A list of filter functions which will modify the template definition + before Cheetah's compiler sees it. See chapter @@MO for details. + + compilerClass, cacheCompilationResults, useCache, cacheModuleFilesForTracebacks, cacheDirForModuleFiles, keepRefToGeneratedCode + You'll probably never need these. They are used to provide an + alternate compiler, disable Cheetah's template caching (*not* related + to ``#cache``), or modify Cheetah's enhanced traceback reporting. See + the ``Template.compile()`` docstring for details. + +Here are typical ways to create a template instance: + +``t = Template("The king is a \$placeholder1.")`` + Pass the template definition as a string. +``t = Template(file="fink.tmpl")`` + Read the template definition from a file named "fink.tmpl". +``t = Template(file=f)`` + Read the template definition from file-like object 'f'. +``t = Template("The king is a \$placeholder1.", namespaces=[dict, obj])`` + Pass the template definition as a string. Also pass two namespaces for + the namespaces: a dictionary 'dict' and an instance 'obj'. +``t = Template(file="fink.txt", namespaces=[dict, obj])`` + Same, but pass a filename instead of a string. +``t = Template(file=f, namespaces=[dict, obj])`` + Same with a file object. + +Filling templates and extracting data +------------------------------------- + +There are several ways to fill a template. Assume ``t`` is a template +instance:: + + 1 output = t.respond() + 2 output = str(t) # Shortcut for "str(t.respond())". + 3 output = unicode(t) # Shortcut for "unicode(t.respond())". + 4 print t # Shortcut for "print str(t.respond())". + 4 sys.stderr.write( unicode(t).encode('latin1') ) + 5 result = t.my_def_method(arg1, arg2) + +These all assume the template's main method is ``.respond``, which is true +in the normal case. [#]_ ``str()`` and +``unicode()`` will always call the main method whatever it's named. + +If the output contains non-ASCII characters, examples 2 and 4 will raise +an exception. Use one of the other examples instead. + +Example 5 calls a ``#def`` method with arguments. Only that method's output +is returned. + +If the template contains ``#attr`` attributes, you can access those directly:: + + title = t.title + author = t.author + + +.. [#] See the Inheritance chapter... (#implements, mainMethodName, + inheritance). + +"cheetah compile" and precompiled templates +------------------------------------------- + +.. + :label: howWorks.cheetah-compile + +To create a precompiled template module, do either of these:: + + cheetah compile [options] [FILES ...] + cheetah c [options] [FILES ...] + +There are several advantages of precompiled templates: + +- Precompiled templates are easier to debug because you can see the generated + Python code, and the line numbers in error messages will correspond to the + actual line in the template definition file. (If the template definition is + embedded in a string literal inside a module, you'll have to count down from + the first line in the string to find the error line.) + +- Data analysis programs can import the template classes and query their + attributes, which can be set via ``#attr``. Example: a directory of + templates can each contain ``.title`` and ``.author`` attributes, and + another program can read them all and make an index page. + +- Slightly faster performance since the compilation is done before + the user runs your application, and Python will optimize this further + with .pyc or .pyo files. The actual speed difference is minimal -- + Cheetah appears to compile templates instantaneously anyway, and it caches + templates in memory if possible, but precompiling templates will make + some developers feel better for conserving electrons. + +- ``#extends`` requires that the base template be precompiled, or the + child template cannot be instantiated. (@@MO: The *baseclass* constructor + arg can be used to set the parent class for a dynamically-compiled + template.) + +- Only precompiled templates may be used as Webware servlets. + +Some of Cheetah's developers use only precompiled templates and recommend the +same. However, it's your choice whether to do this. + +The following options are supported:: + + --idir DIR, --odir DIR : input/output directories (default: current dir) + --iext EXT, --oext EXT : input/output filename extensions + (default input: tmpl, default output: py) + -R : recurse subdirectories looking for input files + --debug : print lots of diagnostic output to standard error + --flat : no destination subdirectories + --nobackup : don't make backups + --stdout, -p : output to standard output (pipe) + --settings : a string representing the compiler settings to use + e.g. --settings='useNameMapper=False,useFilters=False' + This string is eval'd in Python so it should contain + valid Python syntax. + --templateAPIClass : a string representing a subclass of + Cheetah.Template:Template to use for compilation + +.. tip:: + If Cheetah can't find your input files, or if it puts output files + in the wrong place, use the ``--debug`` option to see how Cheetah + interpreted your command line. + +The most basic usage is:: + + cheetah compile a.tmpl : writes a.py + cheetah compile a.tmpl b.tmpl : writes a.py and b.py + + +Cheetah will automatically add the default input extension (.tmpl) if the exact +file is not found. So the following two examples are the same as above if +"a" and "b" don't exist:: + + cheetah compile a : writes a.py (from a.tmpl) + cheetah compile a b : writes a.py and b.py + + +Use the ``-R`` option to recurse subdirectories:: + + cheetah compile dir1 : error, file is a directory + cheetah compile -R dir1 : look under `dir1' for files to compile + cheetah compile : error, no file specified + cheetah compile -R : compile all templates under current + directory and subdirectories + cheetah compile -R a b dir1 : compile files and recurse + +When recursing, only regular files that end in the input extension (.tmpl) are +considered source files. All other filenames are ignored. + +The options ``--idir`` and ``--odir`` allow you to specify that +the source (and/or destination) paths are relative to a certain directory +rather than to the current directory. This is useful if you keep your +\*.tmpl and \*.py files in separate directory hierarchies. After editing a +source file, just run one of these (or put the command in a script or +Makefile):: + + cheetah compile --odir /var/webware a.tmpl + cheetah compile -R --odir /var/webware + cheetah c --odir /var/webware sub/a.tmpl + : writes /var/webware/sub/a.py + + +"cheetah compile" overwrites any existing ``.py`` file it finds, after +backing it up to FILENAME.py_bak (unless you specify ``--nobackup``). For +this reason, you should make changes to the ``.tmpl`` version of the +template rather than to the ``.py`` version. + +For the same reason, if your template requires custom Python methods or +other Python code, don't put it in the ``FILENAME.py`` file or it will be +overwritten! Instead, put it in a separate base class and use +``#extends`` to inherit from it. + +Because FILENAME will be used as a class and module name, it must be a valid +Python identifier. For instance, ``cheetah compile spam-eggs.tmpl`` is +illegal because of the hyphen ("-"). This is sometimes inconvenient when +converting a site of HTML files into Webware servlets. Fortunately, the +*directory* it's in does not have to be an identifier. (*Hint:* for +date-specific files, try converting 2002/04/12.html to 2002/04/12/index.tmpl. +This also gives you a directory to store images or supplemental files.) + +Occasionally you may want output files put directly into the output directory +(or current directory), rather than into subdirectories parallel to the input +file. The ``--flat`` option does this. This may cause several input files +might map to the same output file. Cheetah checks for output file collisions +before writing any files, and aborts if there are any collisions. :: + + cheetah c sub/a.py : writes sub/a.py + cheetah c --flat sub/a.py : writes a.py + cheetah c --odir DEST sub/a.tmpl + : writes DEST/sub/a.py + cheetah c --flat --odir DEST sub/a.tmpl + : writes DEST/a.py + cheetah c --idir /home/henry sub/rollins.tmpl + : writes sub/rollins.py + cheetah c --flat --idir /home/henry sub/rollins.tmpl + : writes rollins.py + cheetah c --idir /home/henry --odir /home/henry sub/rollins.tmpl + : writes /home/henry/sub/rollins.py + cheetah c --flat --idir /home/henry --odir /home/henry sub/rollins.tmpl + : writes /home/henry/rollins.py + + +Whenever "cheetah compile" has to create an output directory or subdirectory, +it also creates an __init__.py file in it. This file is necessary in order +to make Python treat the directory as a Python package. + +Chapter @@MO has a look inside a precompiled template module. + +"cheetah fill" +-------------- + +.. + :label: howWorks.cheetah-fill + +You can fill templates from the command line with "cheetah fill". The most +common example is static HTML files which are generated from templates. The +output extension is .html by default. The compiled template modules are not +written to disk. All the options to "cheetah compile" are allowed. + +Examples:: + + cheetah fill a.tmpl : writes a.html + cheetah fill a.tmpl b.tmpl : writes a.html and b.html + cheetah f --oext txt a : writes a.txt (from a.tmpl) + +You can't specify user-defined namespaces the normal way, so the templates must +be written to have default values for all variables. However, there is limited +support for gathering placeholder values from operating-system resources:: + + --env : make the environment variables a user-defined namespace + --pickle FILE : unpickle FILE and make that object a user-defined namespace + +Using ``--env`` may have security or reliability implications because the +environment normally contains lots of variables you inherited rather than +defining yourself. If any of these variables override any of yours (say a +``#def``), you will get incorrect output, may reveal private information, +and may get an exception due to the variable being an unexpected type +(environment variables are always strings). Your calling program may wish +to clear out the environment before setting environment variables for the +template. + +There are two other differences between "cheetah compile" and "cheetah fill". +Cheetah doesn't create __init__.py files when creating directories in +fill mode. Also, the source filenames don't have to be identifiers. This +allows you to create any .html filename even if it contains characters like "-" +that are illegal in identifiers. + + +Running a .py template module as a standalone program +----------------------------------------------------- + +.. + :label: howWorks.standalone + +In addition to importing your .py template module file into a Python +script or using it as a Webware servlet, you can also run it from the +command line as a standalone program. The program will print the filled +template on standard output. This is useful while debugging the template, +and for producing formatted output in shell scripts. + +When running the template as a program, you cannot provide a searchList or +set ``self.`` attributes in the normal way, so you must take +alternative measures to ensure that every placeholder has a value. +Otherwise, you will get the usual ``NameMapper.NotFound`` exception at +the first missing value. You can either set default values in the template +itself (via the ``\#attr`` or ``\#def`` directives) or in a Python +superclass, or use the ``--env`` or ``--pickle`` command-line options, +which work just like their "cheetah fill" counterparts. + +Run ``python FILENAME.py --help`` to see all the command-line +options your .py template module accepts. + + + diff --git a/docs/users_guide_2_src/05_language.txt b/docs/users_guide_2_src/05_language.txt new file mode 100755 index 0000000..673abca --- /dev/null +++ b/docs/users_guide_2_src/05_language.txt @@ -0,0 +1,651 @@ +\section{Language Overview} +\label{language} + +Cheetah's basic syntax was inspired by the Java-based template engines Velocity +and WebMacro. It has two types of tags: {\bf \$placeholders} and {\bf +\#directives}. Both types are case-sensitive. + +Placeholder tags begin with a dollar sign (\code{\$varName}) and are similar to +data fields in a form letter or to the \code{\%(key)s} fields on the left side +of Python's \code{\%} operator. When the template is filled, the placeholders +are replaced with the values they refer to. + +Directive tags begin with a hash character (\#) and are used for comments, +loops, conditional blocks, includes, and all other advanced features. +({\em Note:} you can customize the start and end delimeters for placeholder +and directive tags, but in this Guide we'll assume you're using the default.) + +Placeholders and directives can be escaped by putting a backslash before them. +\verb+\$var+ and \verb+\#if+ will be output as literal text. + +A placeholder or directive can span multiple physical lines, following the same +rules as Python source code: put a backslash (\verb+\+) at the end of all +lines except the last line. However, if there's an unclosed parenthesis, +bracket or brace pending, you don't need the backslash. + +\begin{verbatim} +#if $this_is_a_very_long_line and $has_lots_of_conditions \ + and $more_conditions: +<H1>bla</H1> +#end if + +#if $country in ('Argentina', 'Uruguay', 'Peru', 'Colombia', + 'Costa Rica', 'Venezuela', 'Mexico') +<H1>Hola, senorita!</H1> +#else +<H1>Hey, baby!</H1> +#end if +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Language Constructs -- Summary} +\label{language.constructs} + +\begin{enumerate} +\item Comments and documentation strings + \begin{enumerate} + \item \code{\#\# single line} + \item \code{\#* multi line *\#} + \end{enumerate} + +\item Generation, caching and filtering of output + \begin{enumerate} + \item plain text + \item look up a value: \code{\$placeholder} + \item evaluate an expression: \code{\#echo} \ldots + \item same but discard the output: \code{\#silent} \ldots + \item one-line if: \code{\#if EXPR then EXPR else EXPR} + \item gobble the EOL: \code{\#slurp} + \item parsed file includes: \code{\#include} \ldots + \item raw file includes: \code{\#include raw} \ldots + \item verbatim output of Cheetah code: \code{\#raw} \ldots \code{\#end raw} + \item cached placeholders: \code{\$*var}, \code{\$*<interval>*var} + \item cached regions: \code{\#cache} \ldots \code{\#end cache} + \item set the output filter: \code{\#filter} \ldots + \item control output indentation: \code{\#indent} \ldots ({\em not +implemented yet}) + \end{enumerate} + +\item Importing Python modules and objects: \code{\#import} \ldots, + \code{\#from} \ldots + +\item Inheritance + \begin{enumerate} + \item set the base class to inherit from: \code{\#extends} + \item set the name of the main method to implement: \code{\#implements} +\ldots + \end{enumerate} + +\item Compile-time declaration + \begin{enumerate} + \item define class attributes: \code{\#attr} \ldots + \item define class methods: \code{\#def} \ldots \code{\#end def} + \item \code{\#block} \ldots \code{\#end block} provides a simplified + interface to \code{\#def} \ldots \code{\#end def} + \end{enumerate} + +\item Run-time assignment + \begin{enumerate} + \item local vars: \code{\#set} \ldots + \item global vars: \code{\#set global} \ldots + \item deleting local vars: \code{\#del} \ldots + \end{enumerate} + +\item Flow control + \begin{enumerate} + \item \code{\#if} \ldots \code{\#else} \ldots \code{\#else if} (aka + \code{\#elif}) \ldots \code{\#end if} + \item \code{\#unless} \ldots \code{\#end unless} + \item \code{\#for} \ldots \code{\#end for} + \item \code{\#repeat} \ldots \code{\#end repeat} + \item \code{\#while} \ldots \code{\#end while} + \item \code{\#break} + \item \code{\#continue} + \item \code{\#pass} + \item \code{\#stop} + \end{enumerate} + +\item error/exception handling + \begin{enumerate} + \item \code{\#assert} + \item \code{\#raise} + \item \code{\#try} \ldots \code{\#except} \ldots \code{\#else} \ldots + \code{\#end try} + \item \code{\#try} \ldots \code{\#finally} \ldots \code{\#end try} + \item \code{\#errorCatcher} \ldots set a handler for exceptions raised by +\$placeholder calls. + \end{enumerate} + +\item Instructions to the parser/compiler + \begin{enumerate} + \item \code{\#breakpoint} + \item \code{\#compiler-settings} \ldots \code{\#end compiler-settings} + \end{enumerate} + +\item Escape to pure Python code + \begin{enumerate} + \item evalute expression and print the output: \code{<\%=} \ldots + \code{\%>} + \item execute code and discard output: \code{<\%} \ldots \code{\%>} + \end{enumerate} + +\item Fine control over Cheetah-generated Python modules + \begin{enumerate} + \item set the source code encoding of compiled template modules: \code{\#encoding} + \item set the sh-bang line of compiled template modules: \code{\#shBang} + \end{enumerate} + +\end{enumerate} + +The use of all these constructs will be covered in the next several chapters. + +%% @@MO: TODO: reconcile the order of this summary with the order in the +%% detail sections. + +% @@MO: PSP chapter with examples. What does write() do? Print? + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Placeholder Syntax Rules} +\label{language.placeholders.syntax} + +\begin{itemize} + +\item Placeholders follow the same syntax rules as Python variables except + that they are preceded by \code{\$} (the short form) or enclosed in + \code{\$\{\}} (the long form). + Examples: +\begin{verbatim} +$var +${var} +$var2.abc['def']('gh', $subplaceholder, 2) +${var2.abc['def']('gh', $subplaceholder, 2)} +\end{verbatim} + We recommend \code{\$} in simple cases, and \code{\$\{\}} when followed + directly by a letter or when Cheetah or a human template maintainer might + get confused about where the placeholder ends. You may alternately use + \verb+$()+ or \verb+$[]+, although this may confuse the (human) template + maintainer: +\begin{verbatim} +$(var) +$[var] +$(var2.abc['def']('gh', $subplaceholder, 2)) +$[var2.abc['def']('gh', $subplaceholder, 2)] +\end{verbatim} + {\em Note:} Advanced users can change the delimiters to anything they + want via the \code{\#compiler} directive. + + {\em Note 2:} The long form can be used only with top-level placeholders, + not in expressions. See section \ref{language.placeholders.positions} + for an elaboration on this. + +\item To reiterate Python's rules, placeholders consist of one or more + identifiers separated by periods. Each identifier must start with a letter + or an underscore, and the subsequent characters must be letters, digits or + underscores. Any identifier may be followed by arguments enclosed in + \verb+()+ and/or keys/subscripts in \verb+[]+. + +\item Identifiers are case sensitive. \code{\$var} does not equal \code{\$Var} + or \code{\$vAr} or \code{\$VAR}. + +\item Arguments inside \verb+()+ or \verb+[]+ are just like in Python. + Strings may be quoted using any Python quoting style. Each argument is an + expression and may use any of Python's expression operators. Variables + used in argument expressions are placeholders and should be prefixed with + \code{\$}. This also applies to the *arg and **kw forms. However, you do + {\em not} need the \code{\$} with the special Python constants \code{None}, + \code{True} and \code{False}. + Examples: +\begin{verbatim} +$hex($myVar) +$func($arg=1234) +$func2($*args, $**kw) +$func3(3.14159, $arg2, None, True) +$myList[$mySubscript] +\end{verbatim} + +\item Trailing periods are ignored. Cheetah will recognize that the placeholder + name in \code{\$varName.} is \code{varName}, and the period will be left + alone in the template output. + +\item The syntax \code{\$\{placeholderName, arg1="val1"\}} passes arguments to + the output filter (see \code{\#filter}, section \ref{output.filter}. + The braces and comma are required in this case. It's conventional to + omit the \code{\$} before the keyword arguments (i.e. \code{arg1}) in this + case. + +\item Cheetah ignores all dollar signs (\code{\$}) that are not followed by a + letter or an underscore. + +\end{itemize} + +The following are valid \$placeholders: +\begin{verbatim} +$a $_ $var $_var $var1 $_1var $var2_ $dict.key $list[3] +$object.method $object.method() $object.method +$nest($nest($var)) +\end{verbatim} + +These are not \$placeholders but are treated as literal text: +\begin{verbatim} +$@var $^var $15.50 $$ +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Where can you use placeholders?} +\label{language.placeholders.positions} + +There are three places you can use placeholders: top-level position, +expression position and LVALUE position. Each has slightly different +syntax rules. + +Top-level position means interspersed in text. This is the only place +you can use the placeholder long form: \code{\$\{var\}}. + +{\em Expression position} means inside a Cheetah expression, which is the same +as a Python expression. The placeholder names a searchList or other variable +to be read. Expression position occurs inside () and $[]$ arguments within +placeholder tags (i.e., a placeholder inside a placeholder), and in several +directive tags. + +{\em LVALUE position} means naming a variable that will be written to. LVALUE +is a computer science term meaning ``the left side of an assignment +statement''. The first argument of directives \code{\#set}, \code{\#for}, +\code{\#def}, \code{\#block} and \code{\#attr} is an LVALUE. + +This stupid example shows the three positions. Top-level position is shown +in \code{courier}, expression position is {\em italic}, and LVALUE position is +{\bf bold}. + +\begin{quote} +\#for {\bf \$count} in {\em \$range}({\em \$ninetyNine}, 0, -1)\\ +\#set {\bf \$after} = {\em \$count} - 1\\ +\code{\$count} bottles of beer on the wall. \code{\$count} bottles of beer!\\ +~~~~Take one down, pass it around. \code{\$after} bottles of beer on the wall.\\ +\#end for\\ +\code{\$hex}({\em \$myVar}, {\bf \$default}={\em None}) +\end{quote} + +The output of course is: +\begin{verbatim} +99 bottles of beer on the wall. 99 bottles of beer! + Take one down, pass it around. 98 bottles of beer on the wall. +98 bottles of beer on the wall. 98 bottles of beer! + Take one down, pass it around. 97 bottles of beer on the wall. +... +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Are all those dollar signs really necessary?} +\label{language.placeholders.dollar-signs} + +\code{\$} is a ``smart variable prefix''. When Cheetah sees \code{\$}, it +determines both the variable's position and whether it's a searchList value or +a non-searchList value, and generates the appropriate Python code. + +In top-level position, the \code{\$} is {\em required}. Otherwise there's +nothing to distinguish the variable from ordinary text, and the variable name +is output verbatim. + +In expression position, the \code{\$} is {\em required} if the value comes from +the searchList or a ``\#set global'' variable, {\em recommended} for +local/global/builtin variables, and {\em not necessary} for the special +constants \code{None}, \code{True} and \code{False}. This works because +Cheetah generates a function call for a searchList placeholder, but a bare +variable name for a local/global/builtin variable. + +In LVALUE position, the \code{\$} is {\em recommended}. Cheetah knows where +an LVALUE is expected, so it can handle your variable name whether it has +\code{\$} or not. + +EXCEPTION: Do {\em not} use the \code{\$} prefix for intermediate variables in +a Python list comprehensions. This is a limitation of Cheetah's parser; it +can't tell which variables in a list comprehension are the intermediate +variables, so you have to help it. For example: +\begin{verbatim} +#set $theRange = [x ** 2 for x in $range(10)] +\end{verbatim} +\code{\$theRange} is a regular \code{\#set} variable. \code{\$range} is a +Python built-in function. But \code{x} is a scratch variable internal to +the list comprehension: if you type \code{\$x}, Cheetah will miscompile +it. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{NameMapper Syntax} +\label{language.namemapper} + +One of our core aims for Cheetah was to make it easy for non-programmers to +use. Therefore, Cheetah uses a simplified syntax for mapping placeholders +in Cheetah to values in Python. It's known as the {\bf NameMapper syntax} +and allows for non-programmers to use Cheetah without knowing (a) the +difference between an instance and a dictionary, (b) what functions and methods +are, and (c) what 'self' is. A side benefit is that you can change the +underlying data structure (e.g., instance to dictionary or vice-versa) without +having to modify the templates. + +NameMapper syntax is used for all variables in Cheetah placeholders and +directives. If desired, it can be turned off via the \code{Template} class' +\code{'useNameMapper'} compiler setting. But it's doubtful you'd ever want to +turn it off. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Example} +\label{language.namemapper.example} + +Consider this scenario: + +You are building a customer information system. The designers with you want to +use information from your system on the client's website --AND-- they want to +understand the display code and so they can maintian it themselves. + +You write a UI class with a 'customers' method that returns a dictionary of all +the customer objects. Each customer object has an 'address' method that returns +the a dictionary with information about the customer's address. The designers +want to be able to access that information. + +Using PSP, the display code for the website would look something like the +following, assuming your servlet subclasses the class you created for managing +customer information: + +\begin{verbatim} + <%= self.customer()[ID].address()['city'] %> (42 chars) +\end{verbatim} + +With Cheetah's NameMapper syntax, you can use any of the following: + +\begin{verbatim} + $self.customers()[$ID].address()['city'] (39 chars) + --OR-- + $customers()[$ID].address()['city'] + --OR-- + $customers()[$ID].address().city + --OR-- + $customers()[$ID].address.city + --OR-- + $customers[$ID].address.city (27 chars) +\end{verbatim} + +Which of these would you prefer to explain to the designers, who have no +programming experience? The last form is 15 characters shorter than the PSP +version and -- conceptually -- far more accessible. With PHP or ASP, the +code would be even messier than with PSP. + +This is a rather extreme example and, of course, you could also just implement +\code{\$getCustomer(\$ID).city} and obey the Law of Demeter (search Google for more +on that). But good object orientated design isn't the point of this example. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Dictionary Access} +\label{language.namemapper.dict} + +NameMapper syntax allows access to dictionary items with the same dotted +notation used to access object attributes in Python. This aspect of NameMapper +syntax is known as 'Unified Dotted Notation'. +For example, with Cheetah it is possible to write: +\begin{verbatim} + $customers()['kerr'].address() --OR-- $customers().kerr.address() +\end{verbatim} +where the second form is in NameMapper syntax. + +This works only with dictionary keys that also happen to be valid Python +identifiers. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Autocalling} +\label{language.namemapper.autocalling} + +Cheetah automatically detects functions and methods in Cheetah \$variables and +calls them if the parentheses have been left off. Our previous example can be +further simplified to: +\begin{verbatim} + $customers.kerr.address +\end{verbatim} + +As another example, if 'a' is an object, 'b' is a method +\begin{verbatim} + $a.b +\end{verbatim} + +is equivalent to + +\begin{verbatim} + $a.b() +\end{verbatim} + +If b returns a dictionary, then following variations are possible +\begin{verbatim} + $a.b.c --OR-- $a.b().c --OR-- $a.b()['c'] +\end{verbatim} +where 'c' is a key in the dictionary that a.b() returns. + +Further notes: +\begin{itemize} +\item When Cheetah autocalls a function/method, it calls it without any +arguments. Thus, the function/method must have been declared without arguments +(except \code{self} for methods) or to provide default values for all arguments. +If the function requires arguments, you must use the \code{()}. + +\item Cheetah autocalls only functions and methods. Classes and other callable +objects are not autocalled. The reason is that the primary purpose of a +function/method is to call it, whereas the primary purpose of an instance is to +look up its attributes or call its methods, not to call the instance itself. +And calling a class may allocate large sums of memory uselessly or have other +side effects, depending on the class. For instance, consider +\code{\$myInstance.fname}. Do we want to look up \code{fname} in the namespace +of \code{myInstance} or in the namespace of whatever \code{myinstance} returns? +It could go either way, so Cheetah follows the principle of least surprise. If +you {\em do} want to call the instance, put the \code{()} on, or rename the +\code{.\_\_call\_\_()} method to \code{.\_\_str\_\_}. + +\item Autocalling can be disabled via Cheetah's 'useAutocalling' compiler +setting. You can also disable it for one placeholder by using the syntax +\code{\$getVar('varName', 'default value', False)}. (\code{.getVar()} works +only with searchList values.) +\end{itemize} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Namespace cascading and the searchList} +\label{language.searchList} + +When Cheetah maps a variable name in a template to a Python value, it searches +several namespaces in order: + +\begin{enumerate} +\item {\bf Local variables:} created by \code{\#set}, + \code{\#for}, or predefined by Cheetah. +\item The {\bf searchList}, consisting of: + \begin{enumerate} + \item \code{\#set\ global} variables. + \item The {\bf searchList} containers you passed to the \code{Template} + constructor, if any. + \item The {\bf Template instance} (``self''). This contains any attributes + you assigned, \code{\#def} methods and \code{\#block methods}, + attributes/methods inherited via \code{\#extends}, and other + attributes/methods built into \code{Template} or inherited by it + (there's a list of all these methods in section + \ref{tips.allMethods}). + \end{enumerate} +\item {\bf Python globals:} created by \code{\#import}, + \code{\#from\ ...\ import}, or otherwise predefined by Cheetah. +\item {\bf Python builtins:} \code{None}, \code{max}, etc. +\end{enumerate} + +The first matching name found is used. + +Remember, these namespaces apply only to the {\em first} identifier after the +\code{\$}. In a placeholder like \code{\$a.b}, only `a' is looked up in the +searchList and other namespaces. `b' is looked up only inside `a'. + +A searchList container can be any Python object with attributes or keys: +dictionaries, instances, classes or modules. If an instance contains both +attributes and keys, its attributes are searched first, then its keys. + +Because the \code{Template} instance is part of the searchList, you can +access its attributes/methods without `self': \code{\$myAttr}. However, use +the `self' if you want to make sure you're getting the \code{Template} +attribute and not a same-name variable defined in a higher namespace: +\code{\$self.myAttr}. This works because ``self'' itself is a local variable. + +The final resulting value, after all lookups and function calls (but before the +filter is applied) is called the {\em placeholder value}, no matter which +namespace it was found in. + +{\em {\bf Note carefully:}} if you put an object `myObject' in the searchList, +you {\em cannot} look up \code{\$myObject}! You can look up only the +attributes/keys {\em inside} `myObject'. + +Earlier versions of Cheetah did not allow you to override Python builtin +names, but this was fixed in Cheetah 0.9.15. + +If your template will be used as a Webware servlet, do not override methods +'name' and 'log' in the \code{Template} instance or it will interfere with +Webware's logging. However, it {\em is} OK to use those variables in a higher +namespace, since Webware doesn't know about Cheetah namespaces. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Missing Values} +\label{language.namemapper.missing} + +If NameMapper can not find a Python value for a Cheetah variable name, it will +raise the NameMapper.NotFound exception. You can use the \code{\#errorCatcher} +directive (section \ref{errorHandling.errorCatcher}) or {\bf errorCatcher} +Template constructor argument (section \ref{howWorks.constructing}) to specify +an alternate behaviour. BUT BE AWARE THAT errorCatcher IS ONLY INTENDED FOR +DEBUGGING! + +To provide a default value for a placeholder, write it like this: +\code{\$getVar('varName', 'default value')}. If you don't specify a default +and the variable is missing, \code{NameMapper.NotFound} will be raised. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Directive Syntax Rules} +\label{language.directives.syntax} + + +Directive tags begin with a hash character (\#) and are used for comments, +loops, conditional blocks, includes, and all other advanced features. Cheetah +uses a Python-like syntax inside directive tags and understands any valid +Python expression. {\bf However, unlike Python, Cheetah does not use colons +(:) and indentation to mark off multi-line directives.} That doesn't work in +an environment where whitespace is significant as part of the text. Instead, +multi-line directives like \code{\#for} have corresponding closing tags +(\code{\#end for}). Most directives are direct mirrors of Python statements. + +Many directives have arguments after the opening tag, which must be in the +specified syntax for the tag. All end tags have the following syntax: +\begin{verbatim} +#end TAG_NAME [EXPR] +\end{verbatim} +The expression is ignored, so it's essentially a comment. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Directive closures and whitespace handling} +\label{language.directives.closures} +Directive tags can be closed explicitly with \code{\#}, or implicitly with the +end of the line if you're feeling lazy. + +\begin{verbatim} +#block testBlock # +Text in the body of the +block directive +#end block testBlock # +\end{verbatim} +is identical to: +\begin{verbatim} +#block testBlock +Text in the body of the +block directive +#end block testBlock +\end{verbatim} + +When a directive tag is closed explicitly, it can be followed with other text on +the same line: + +\begin{verbatim} +bah, bah, #if $sheep.color == 'black'# black#end if # sheep. +\end{verbatim} + +When a directive tag is closed implicitly with the end of the line, all trailing +whitespace is gobbled, including the newline character: +\begin{verbatim} +""" +foo #set $x = 2 +bar +""" +outputs +""" +foo bar +""" + +while +""" +foo #set $x = 2 # +bar +""" +outputs +""" +foo +bar +""" +\end{verbatim} + +When a directive tag is closed implicitly AND there is no other text on the +line, the ENTIRE line is gobbled up including any preceeding whitespace: +\begin{verbatim} +""" +foo + #set $x = 2 +bar +""" +outputs +""" +foo +bar +""" + +while +""" +foo + - #set $x = 2 +bar +""" +outputs +""" +foo + - bar +""" +\end{verbatim} + +The \code{\#slurp} directive (section \ref{output.slurp}) also gobbles up +whitespace. + +Spaces outside directives are output {\em exactly} as written. In the +black sheep example, there's a space before ``black'' and another before +``sheep''. So although it's legal to put multiple directives on one line, +it can be hard to read. + +\begin{verbatim} +#if $a# #echo $a + 1# #end if + - There's a space between each directive, + or two extra spaces total. +#if $a##echo $a + 1##end if + - No spaces, but you have to look closely + to verify none of the ``##'' are comment markers. +#if $a##echo $a + 1##end if ### A comment. + - In ``###'', the first ``#'' ends the directive, + the other two begin the comment. (This also shows + how you can add extra whitespace in the directive + tag without affecting the output.) +#if $a##echo $a + 1##end if # ## A comment. + - More readable, but now there's a space before the + comment. +\end{verbatim} + +% Local Variables: +% TeX-master: "users_guide" +% End: + +% # vim: sw=4 ts=4 expandtab diff --git a/docs/users_guide_2_src/05_placeholders_and_the_namemapper.txt b/docs/users_guide_2_src/05_placeholders_and_the_namemapper.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/docs/users_guide_2_src/05_placeholders_and_the_namemapper.txt diff --git a/docs/users_guide_2_src/06_comments.txt b/docs/users_guide_2_src/06_comments.txt new file mode 100755 index 0000000..36323cf --- /dev/null +++ b/docs/users_guide_2_src/06_comments.txt @@ -0,0 +1,99 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Comments} +\label{comments} + +Comments are used to mark notes, explanations, and decorative text that should +not appear in the output. Cheetah maintains the comments in the Python module +it generates from the Cheetah source code. There are two forms of the comment +directive: single-line and multi-line. + +All text in a template definition that lies between two hash characters +(\code{\#\#}) and the end of the line is treated as a single-line comment and +will not show up in the output, unless the two hash characters are escaped with +a backslash. +\begin{verbatim} +##============================= this is a decorative comment-bar +$var ## this is an end-of-line comment +##============================= +\end{verbatim} + +Any text between \code{\#*} and \code{*\#} will be treated as a multi-line +comment. +\begin{verbatim} +#* + Here is some multiline + comment text +*# +\end{verbatim} + +If you put blank lines around method definitions or loops to separate them, +be aware that the blank lines will be output as is. To avoid this, make sure +the blank lines are enclosed in a comment. Since you normally have a +comment before the next method definition (right?), you can just extend that +comment to include the blank lines after the previous method definition, like +so: +\begin{verbatim} +#def method1 +... lines ... +#end def +#* + + + Description of method2. + $arg1, string, a phrase. +*# +#def method2($arg1) +... lines ... +#end def +\end{verbatim} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Docstring Comments} +\label{comments.docstring} + +Python modules, classes, and methods can be documented with inline +'documentation strings' (aka 'docstrings'). Docstrings, unlike comments, are +accesible at run-time. Thus, they provide a useful hook for interactive help +utilities. + +Cheetah comments can be transformed into doctrings by adding one of the +following prefixes: + +\begin{verbatim} +##doc: This text will be added to the method docstring +#*doc: If your template file is MyTemplate.tmpl, running "cheetah compile" + on it will produce MyTemplate.py, with a class MyTemplate in it, + containing a method .respond(). This text will be in the .respond() + method's docstring. *# + +##doc-method: This text will also be added to .respond()'s docstring +#*doc-method: This text will also be added to .respond()'s docstring *# + +##doc-class: This text will be added to the MyTemplate class docstring +#*doc-class: This text will be added to the MyTemplate class docstring *# + +##doc-module: This text will be added to the module docstring MyTemplate.py +#*doc-module: This text will be added to the module docstring MyTemplate.py*# +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Header Comments} +\label{comments.headers} +Cheetah comments can also be transformed into module header comments using the +following syntax: + +\begin{verbatim} +##header: This text will be added to the module header comment +#*header: This text will be added to the module header comment *# +\end{verbatim} + +Note the difference between \code{\#\#doc-module: } and \code{header: }: +``cheetah-compile'' puts \code{\#\#doc-module: } text inside the module +docstring. \code{header: } makes the text go {\em above} the docstring, as a +set of \#-prefixed comment lines. + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_2_src/07_output.txt b/docs/users_guide_2_src/07_output.txt new file mode 100755 index 0000000..742291e --- /dev/null +++ b/docs/users_guide_2_src/07_output.txt @@ -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{\$*<interval>*variable}, where \code{<interval>} 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} +<HTML> +<HEAD><TITLE>$title</TITLE></HEAD> +<BODY> + +$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. + +</BODY> +</HTML> +\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{\$*<interval>*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{\$*<interval>*}. 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{<PRE>} 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_2_src/08_inheritanceEtc.txt b/docs/users_guide_2_src/08_inheritanceEtc.txt new file mode 100755 index 0000000..3e76ce2 --- /dev/null +++ b/docs/users_guide_2_src/08_inheritanceEtc.txt @@ -0,0 +1,564 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Import, Inheritance, Declaration and Assignment} +\label{inheritanceEtc} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#import and \#from directives} +\label{inheritanceEtc.import} + +Syntax: +\begin{verbatim} +#import MODULE_OR_OBJECT [as NAME] [, ...] +#from MODULE import MODULE_OR_OBJECT [as NAME] [, ...] +\end{verbatim} + + +The \code{\#import} and \code{\#from} directives are used to make external +Python modules or objects available to placeholders. The syntax is identical +to the import syntax in Python. Imported modules are visible globally to all +methods in the generated Python class. + +\begin{verbatim} +#import math +#import math as mathModule +#from math import sin, cos +#from math import sin as _sin +#import random, re +#from mx import DateTime # ## Part of Egenix's mx package. +\end{verbatim} + +After the above imports, \code{\$math}, \code{\$mathModule}, +\code{\$sin}, \code{\$cos} and \code{\$\_sin}, \code{\$random}, \code{\$re} +and \code{\$DateTime} may be used in \code{\$placeholders} and expressions. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#extends} +\label{inheritanceEtc.extends} + +Syntax: +\begin{verbatim} +#extends CLASS +\end{verbatim} + + +All templates are subclasses of \code{Cheetah.Template.Template}. However, +it's possible for a template to subclass another template or a pure Python +class. This is where \code{\#extends} steps in: it +specifies the parent class. It's equivalent to PSP's \code{``@page extends=''} +directive. + +Cheetah imports the class mentioned in an \code{\#extends} directive +automatically if you haven't imported it yet. The implicit importing works +like this: + +\begin{verbatim} +#extends Superclass +## Implicitly does '#from Superclass import Superclass'. + +#extends Cheetah.Templates.SkeletonPage +## Implicitly does '#from Cheetah.Templates.SkeletonPage import SkeletonPage'. +\end{verbatim} + +If your superclass is in an unusual location or in a module named +differently than the class, you must import it explicitly. There is no +support for extending from a class that is not imported; e.g., from a template +dynamically created from a string. Since the most practical way to +get a parent template into a module is to precompile it, all parent templates +essentially have to be precompiled. + +There can be only one \code{\#extends} directive in a template and it +may list only one class. In other words, templates don't do multiple +inheritance. This is intentional: it's too hard to initialize multiple +base classes correctly from inside a template. However, you can do +multiple inheritance in your pure Python classes. + +If your pure Python class overrides any of the standard \code{Template} +methods such as \code{.\_\_init\_\_} or \code{.awake}, be sure to call +the superclass method in your method or things will break. Examples of calling +the superclass method are in section \ref{tips.callingSuperclassMethods}. +A list of all superclass methods is in section +\ref{tips.allMethods}. + +In all cases, the root superclass must be \code{Template}. If your +bottommost class is a template, simply omit the \code{\#extends} in it and it +will automatically inherit from \code{Template}. {\em If your bottommost class +is a pure Python class, it must inherit from \code{Template} explicitly: } +\begin{verbatim} +from Cheetah.Template import Template +class MyPurePythonClass(Template): +\end{verbatim} + +If you're not keen about having your Python classes inherit from +\code{Template}, create a tiny glue class that inherits both from your +class and from \code{Template}. + +Before giving any examples we'll stress that Cheetah does {\em not} +dictate how you should structure your inheritance tree. As long as +you follow the rules above, many structures are possible. + +Here's an example for a large web site that has not only a general site +template, but also a template for this section of the site, and then a +specific template-servlet for each URL. (This is the ``inheritance +approach'' discussed in the Webware chapter.) Each template inherits from a +pure Python class that contains methods/attributes used by the template. We'll +begin with the bottommost superclass and end with the specific +template-servlet: + +\begin{verbatim} +1. SiteLogic.py (pure Python class containing methods for the site) + from Cheetah.Template import Template + class SiteLogic(Template): + +2. Site.tmpl/py (template containing the general site framework; + this is the template that controls the output, + the one that contains "<HTML><HEAD>...", the one + that contains text outside any #def/#block.) + #from SiteLogic import SiteLogic + #extends SiteLogic + #implements respond + +3. SectionLogic.py (pure Python class with helper code for the section) + from Site import Site + class SectionLogic(Site) + +4. Section.tmpl/py (template with '#def' overrides etc. for the section) + #from SectionLogic import SectionLogic + #extends SectionLogic + +5. page1Logic.py (pure Python class with helper code for the template-servlet) + from Section import Section + class indexLogic(Section): + +6. page1.tmpl/py (template-servlet for a certain page on the site) + #from page1Logic import page1Logic + #extends page1Logic +\end{verbatim} + +A pure Python classes might also contain methods/attributes that aren't used by +their immediate child template, but are available for any descendant +template to use if it wishes. For instance, the site template might have +attributes for the name and e-mail address of the site administrator, +ready to use as \$placeholders in any template that wants it. + +{\em Whenever you use \code{\#extends}, you often need \code{\#implements} +too,} as in step 2 above. Read the next section to understand what +\code{\#implements} is and when to use it. + +% @@MO: Edmund suggests making some diagrams of inheritance chains. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#implements} +\label{inheritanceEtc.implements} + +Syntax: +\begin{verbatim} +#implements METHOD +\end{verbatim} + +You can call any \code{\#def} or \code{\#block} method directly and get its +outpt. The top-level content -- all the text/placeholders/directives outside any +\code{\#def}/\code{\#block} -- gets concatenated and wrapped in a ``main +method'', by default \code{.respond()}. So if you call \code{.respond()}, you +get the ``whole template output''. When Webware calls \code{.respond()}, +that's what it's doing. And when you do 'print t' or 'str(t)' on a template +instance, you're taking advantage of the fact that Cheetah makes +\code{.\_\_str\_\_()} an alias for the main method. + +That's all fine and dandy, but what if your application prefers to call another +method name rather than \code{.respond()}? What if it wants to call, say, +\code{.send\_output()} instead? That's where \code{\#implements} steps in. It +lets you choose the name for the main method. Just put this in your template +definition: +\begin{verbatim} +#implements send_output +\end{verbatim} + +When one template extends another, every template in the inheritance chain +has its own main method. To fill the template, you invoke exactly one of +these methods and the others are ignored. The method you call may be in any of +the templates in the inheritance chain: the base template, the leaf template, +or any in between, depending on how you structure your application. So you +have two problems: (1) calling the right method name, and (2) preventing an +undesired same-name subclass method from overriding the one you want to call. + +Cheetah assumes the method you will call is \code{.respond()} because +that's what Webware calls. It further assumes the desired main method is the +one in the lowest-level base template, because that works well with +\code{\#block} as described in the Inheritance Approach for building Webware +servlets (section \ref{webware.inheritance}), which was originally the +principal use for Cheetah. So when you use \code{\#extends}, Cheetah changes +that template's main method to \code{.writeBody()} to get it out of the way and +prevent it from overriding the base template's \code{.respond()}. + +Unfortunately this assumption breaks down if the template is used in other +ways. For instance, you may want to use the main method in the highest-level +leaf template, and treat the base template(s) as merely a library of +methods/attributes. In that case, the leaf template needs \code{\#implements +respond} to change its main method name back to \code{.respond()} (or whatever +your application desires to call). Likewise, if your main method is in one of the +intermediate templates in an inheritance chain, that template needs +\code{\#implements respond}. + +The other way the assumption breaks down is if the main method {\em is} in +the base template but that template extends a pure Python class. Cheetah sees +the \code{\#extends} and dutifully but incorrectly renames the method to +\code{.writeBody()}, so you have to use \code{\#implements respond} to change +it back. Otherwise the dummy \code{.respond()} in \code{Cheetah.Template} +is found, which outputs... nothing. {\bf So if you're using \code{\#extends} +and get no output, the {\em first} thing you should think is, ``Do I need to +add \code{\#implements respond} somewhere?'' } + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#set} +\label{inheritanceEtc.set} + +Syntax: +\begin{verbatim} +#set [global] $var = EXPR +\end{verbatim} + +\code{\#set} is used to create and update local variables at run time. +The expression may be any Python expression. +Remember to preface variable names with \$ unless they're part of an +intermediate result in a list comprehension. + +Here are some examples: +\begin{verbatim} +#set $size = $length * 1096 +#set $buffer = $size + 1096 +#set $area = $length * $width +#set $namesList = ['Moe','Larry','Curly'] +#set $prettyCountry = $country.replace(' ', ' ') +\end{verbatim} + +\code{\#set} variables are useful to assign a short name to a +\code{\$deeply.nested.value}, to a calculation, or to a printable version of +a value. The last example above converts any spaces in the 'country' value +into HTML non-breakable-space entities, to ensure the entire value appears on +one line in the browser. + +\code{\#set} variables are also useful in \code{\#if} expressions, but +remember that complex logical routines should be coded in Python, not in +Cheetah! +\begin{verbatim} +#if $size > 1500 + #set $adj = 'large' +#else + #set $adj = 'small' +#end if +\end{verbatim} +Or Python's one-line equivalent, "A and B or C". Remember that in this case, +B must be a true value (not None, '', 0, [] or {}). +\begin{verbatim} +#set $adj = $size > 1500 and 'large' or 'small' +\end{verbatim} +(Note: Cheetah's one-line \code{\#if} will not work for this, since it +produces output rather than setting a variable. + +You can also use the augmented assignment operators: +\begin{verbatim} +## Increment $a by 5. +#set $a += 5 +\end{verbatim} + +By default, \code{\#set} variables are not visible in method calls or include +files unless you use the \code{global} attribute: \code{\#set global \$var = +EXPRESSION}. Global variables are visible in all methods, nested templates and +included files. Use this feature with care to prevent surprises. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#del} +\label{inheritanceEtc.del} + +Syntax: +\begin{verbatim} +#del $var +\end{verbatim} + +\code{\#del} is the opposite of \code{\#set}. It deletes a {\em local} +variable. Its usage is just like Python's \code{del} statement: +\begin{verbatim} +#del $myVar +#del $myVar, $myArray[5] +\end{verbatim} + +Only local variables can be deleted. There is no directive to delete a +\code{\#set global} variable, a searchList variable, or any other type of +variable. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#attr} +\label{inheritanceEtc.attr} + +Syntax: +\begin{verbatim} +#attr $var = EXPR +\end{verbatim} + +The \code{\#attr} directive creates class attributes in the generated Python +class. It should be used to assign simple Python literals such as numbers or +strings. In particular, the expression must {\em not} depend on searchList +values or \code{\#set} variables since those are not known at compile time. + +\begin{verbatim} +#attr $title = "Rob Roy" +#attr $author = "Sir Walter Scott" +#attr $version = 123.4 +\end{verbatim} + +This template or any child template can output the value thus: +\begin{verbatim} +$title, by $author, version $version +\end{verbatim} + +If you have a library of templates derived from etexts +(\url{http://www.gutenberg.org/}), you can extract the titles and authors +and put them in a database (assuming the templates have been compiled into +.py template modules): + +%\begin{verbatim} +%import glob +% +%\end{verbatim} +% +% @@MO: Finish this example. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#def} +\label{inheritanceEtc.def} + +Syntax: +\begin{verbatim} +#def METHOD[(ARGUMENTS)] +#end def +\end{verbatim} + +Or the one-line variation: +\begin{verbatim} +#def METHOD[(ARGUMENTS)] : TEXT_AND_PLACEHOLDERS +\end{verbatim} + + +The \code{\#def} directive is used to define new methods in the generated +Python class, or to override superclass methods. It is analogous to Python's +\code{def} statement. The directive is silent, meaning it does not itself +produce any output. However, the content of the method will be inserted into +the output (and the directives executed) whenever the method is later called by +a \$placeholder. + +\begin{verbatim} +#def myMeth() +This is the text in my method +$a $b $c(123) ## these placeholder names have been defined elsewhere +#end def + +## and now use it... +$myMeth() +\end{verbatim} + +The arglist and parentheses can be omitted: +\begin{verbatim} +#def myMeth +This is the text in my method +$a $b $c(123) +#end def + +## and now use it... +$myMeth +\end{verbatim} + +Methods can have arguments and have defaults for those arguments, just like +in Python. Remember the \code{\$} before variable names: +\begin{verbatim} +#def myMeth($a, $b=1234) +This is the text in my method +$a - $b +#end def + +## and now use it... +$myMeth(1) +\end{verbatim} + +The output from this last example will be: + +\begin{verbatim} +This is the text in my method +1 - 1234 +\end{verbatim} + +There is also a single line version of the \code{\#def} directive. +{\bf Unlike the multi-line directives, it uses a colon (:) to delimit the method +signature and body}: +\begin{verbatim} +#attr $adj = 'trivial' +#def myMeth: This is the $adj method +$myMeth +\end{verbatim} +Leading and trailing whitespace is stripped from the method. This is in +contrast to: +\begin{verbatim} +#def myMeth2 +This is the $adj method +#end def +\end{verbatim} +where the method includes a newline after "method". If you don't want the +newline, add \code{\#slurp}: +\begin{verbatim} +#def myMeth3 +This is the $adj method#slurp +#end def +\end{verbatim} + +Because \code{\#def} is handled at compile time, it can appear above or +below the placeholders that call it. And if a superclass placeholder +calls a method that's overridden in a subclass, it's the subclass method +that will be called. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#block ... \#end block} +\label{inheritanceEtc.block} + + +The \code{\#block} directive allows you to mark a section of your template that +can be selectively reimplemented in a subclass. It is very useful for +changing part of a template without having to copy-paste-and-edit +the entire thing. The output from a template definition that uses blocks will +be identical to the output from the same template with the \code{\#block \ldots +\#end block} tags removed. + +({\em Note:} don't be confused by the generic word `block'' in this Guide, +which means a section of code inside {\em any} \code{\#TAG \ldots \#end TAG} +pair. Thus, an if-block, for-block, def-block, block-block etc. In this +section we are talking only of block-blocks.) + +To reimplement the block, use the \code{\#def} directive. The magical effect +is that it appears to go back and change the output text {\em at the point the +original block was defined} rather than at the location of the +reimplementation. + +\begin{verbatim} +#block testBlock +Text in the contents +area of the block directive +#if $testIt +$getFoo() +#end if +#end block testBlock +\end{verbatim} + +You can repeat the block name in the \code{\#end block} directive or not, as +you wish. + +\code{\#block} directives can be nested to any depth. + +\begin{verbatim} +#block outerBlock +Outer block contents + +#block innerBlock1 +inner block1 contents +#end block innerBlock1 + +#block innerBlock2 +inner block2 contents +#end block innerBlock2 + +#end block outerBlock +\end{verbatim} + +Note that the name of the block is optional for the \code{\#end block} tag. + +Technically, \code{\#block} directive is equivalent to a \code{\#def} directive +followed immediately by a \code{\#placeholder} for the same name. In fact, +that's what Cheetah does. Which means you can use \code{\$theBlockName} +elsewhere in the template to output the block content again. + +There is a one-line \code{\#block} syntax analagous to the one-line +\code{\#def}. + +The block must not require arguments because the implicit placeholder that's +generated will call the block without arguments. + + +% Local Variables: +% TeX-master: "users_guide" +% End: + + +Object-Oriented Documents +------------------------- + +.. + :label: howWorks.objoriented + +Because Cheetah documents are actually class definitions, templates may inherit +from one another in a natural way, using regular Python semantics. For +instance, consider this template, FrogBase.tmpl:: + + #def title + This document has not defined its title + #end def + #def htTitle + $title + #end def + <HTML><HEAD> + <TITLE>$title</TITLE> + </HEAD><BODY> + <H1>$htTitle</H1> + $body + </BODY></HTML> + +And its subclassed document, Frog1.tmpl:: + + #from FrogBase import FrogBase + #extends FrogBase + #def title + The Frog Page + #end def + #def htTitle + The <IMG SRC="Frog.png"> page + #end def + #def body + ... lots of info about frogs ... + #end def + + +This is a classic use of inheritance. The parent "template" is simply an +abstract superclass. Each document specializes the output of its parent. +For instance, here the parent defines +``\$htTitle`` so that by default it's identical to whatever the +``\$title`` is, but it can also be customized. + +In many other templating systems, you'd have to use case statements or +if-elseif blocks of some sort, repeated in many different sections of code. + +While we show another Cheetah document inheriting from this parent, a Python +class can inherit from it just as easily. This Python class could define its +programmatically-driven value for ``\$body`` and ``\$title``, simply by +defining body() and title() methods that return a string. (Actually they +can return anything, but we'll get into that later.) :: + + from FrogBase import FrogBase + class Frog2(FrogBase): + def title(self): + return "Frog 2 Page" + # We don't override .htTitle, so it defaults to "Frog 2 Page" too. + def body(self): + return " ... more info about frogs ..." + +Similarly, the Cheetah document can inherit from an arbitrary class. That's +how Cheetah makes templates usable as Webware servlets, by subclassing +``Servlet``. This technique should be possible for non-Webware systems +too. + +(*Note:*\ ``FrogBase.tmpl`` could be improved by using the +``\#block`` directive, section \ref{inheritanceEtc.block}.) + + diff --git a/docs/users_guide_2_src/09_flowControl.txt b/docs/users_guide_2_src/09_flowControl.txt new file mode 100755 index 0000000..75a5845 --- /dev/null +++ b/docs/users_guide_2_src/09_flowControl.txt @@ -0,0 +1,414 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Flow Control} +\label{flowControl} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#for ... \#end for} +\label{flowControl.for} + +Syntax: +\begin{verbatim} +#for $var in EXPR +#end for +\end{verbatim} + + +The \code{\#for} directive iterates through a sequence. The syntax is the same +as Python, but remember the \code{\$} before variables. + +Here's a simple client listing: +\begin{verbatim} +<TABLE> +#for $client in $service.clients +<TR> +<TD>$client.surname, $client.firstname</TD> +<TD><A HREF="mailto:$client.email" >$client.email</A></TD> +</TR> +#end for +</TABLE> +\end{verbatim} + +Here's how to loop through the keys and values of a dictionary: +\begin{verbatim} +<PRE> +#for $key, $value in $dict.items() +$key: $value +#end for +</PRE> +\end{verbatim} + +Here's how to create list of numbers separated by hyphens. This ``\#end for'' +tag shares the last line to avoid introducing a newline character after each +hyphen. +\begin{verbatim} +#for $i in range(15) +$i - #end for +\end{verbatim} + +If the location of the \code{\#end for} offends your sense of indentational +propriety, you can do this instead: +\begin{verbatim} +#for $i in $range(15) +$i - #slurp +#end for +\end{verbatim} + +The previous two examples will put an extra hyphen after last number. Here's +how to get around that problem, using the \code{\#set} directive, which will be +dealt with in more detail below. +\begin{verbatim} +#set $sep = '' +#for $name in $names +$sep$name +#set $sep = ', ' +#end for +\end{verbatim} + +Although to just put a separator between strings, you don't need a for loop: +\begin{verbatim} +#echo ', '.join($names) +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#repeat ... \#end repeat} +\label{flowControl.repeat} + +Syntax: +\begin{verbatim} +#repeat EXPR +#end repeat +\end{verbatim} + + +Do something a certain number of times. +The argument may be any numeric expression. +If it's zero or negative, the loop will execute zero times. +\begin{verbatim} +#repeat $times + 3 +She loves me, she loves me not. +#repeat +She loves me. +\end{verbatim} + + +Inside the loop, there's no way to tell which iteration you're on. If you +need a counter variable, use \code{\#for} instead with Python's \code{range} +function. Since Python's ranges are base 0 by default, there are two ways +to start counting at 1. Say we want to count from 1 to 5, and that +\code{\$count} is 5. +\begin{verbatim} +#for $i in $range($count) +#set $step = $i + 1 +$step. Counting from 1 to $count. +#end for + + +#for $i in $range(1, $count + 1) +$i. Counting from 1 to $count. +#end for +\end{verbatim} + + +A previous implementation used a local variable \code{\$i} as the repeat +counter. However, this prevented instances of \code{\#repeat} from +being nested. The current implementation does not have this problem as it +uses a new local variable for every instance of \code{\#repeat}. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#while ... \#end while} +\label{flowControl.while} + +Syntax: +\begin{verbatim} +#while EXPR +#end while +\end{verbatim} + + +\code{\#while} is the same as Python's \code{while} statement. It may be +followed by any boolean expression: +\begin{verbatim} +#while $someCondition('arg1', $arg2) +The condition is true. +#end while +\end{verbatim} + +Be careful not to create an infinite loop. \code{\#while 1} will loop until +the computer runs out of memory. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#if ... \#else if ... \#else ... \#end if} +\label{flowControl.if} + +Syntax: +\begin{verbatim} +#if EXPR +#else if EXPR +#elif EXPR +#else +#end if +\end{verbatim} + + +The \code{\#if} directive and its kin are used to display a portion of text +conditionally. \code{\#if} and \code{\#else if} should be followed by a +true/false expression, while \code{\#else} should not. Any valid Python +expression is allowed. As in Python, the expression is true unless it evaluates +to 0, '', None, an empty list, or an empty dictionary. In deference to Python, +\code{\#elif} is accepted as a synonym for \code{\#else if}. + +Here are some examples: +\begin{verbatim} +#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} + +\begin{verbatim} +#if $testItem($item) +The item $item.name is OK. +#end if +\end{verbatim} + +Here's an example that combines an \code{\#if} tag with a \code{\#for} tag. +\begin{verbatim} +#if $people +<table> +<tr> +<th>Name</th> +<th>Address</th> +<th>Phone</th> +</tr> +#for $p in $people +<tr> +<td>$p.name</td> +<td>$p.address</td> +<td>$p.phone</td> +</tr> +#end for +</table> +#else +<p> Sorry, the search did not find any people. </p> +#end if +\end{verbatim} + +See section \ref{output.oneLineIf} for the one-line \code{\#if} directive, +which is equivalent to Perl's and C's \code{?:} operator. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#unless ... \#end unless} +\label{flowControl.unless} + +Syntax: +\begin{verbatim} +#unless EXPR +#end unless +\end{verbatim} + + +\code{\#unless} is the opposite of \code{\#if}: the text is executed if the +condition is {\bf false}. Sometimes this is more convenient. +\code{\#unless EXPR} is equivalent to \code{\#if not (EXPR)}. + +\begin{verbatim} +#unless $alive +This parrot is no more! He has ceased to be! +'E's expired and gone to meet 'is maker! ... +THIS IS AN EX-PARROT!! +#end unless +\end{verbatim} + +You cannot use \code{\#else if} or \code{\#else} inside an \code{\#unless} +construct. If you need those, use \code{\#if} instead. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#break and \#continue} +\label{flowControl.break} + +Syntax: +\begin{verbatim} +#break +#continue +\end{verbatim} + + +These directives are used as in Python. \code{\#break} will +exit a \code{\#for} loop prematurely, while \code{\#continue} will immediately +jump to the next iteration in the \code{\#for} loop. + +In this example the output list will not contain ``10 - ''. +\begin{verbatim} +#for $i in range(15) +#if $i == 10 + #continue +#end if +$i - #slurp +#end for +\end{verbatim} + +In this example the loop will exit if it finds a name that equals 'Joe': +\begin{verbatim} +#for $name in $names +#if $name == 'Joe' + #break +#end if +$name - #slurp +#end for +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#pass} +\label{flowControl.pass} + +Syntax: +\begin{verbatim} +#pass +\end{verbatim} + + +The \code{\#pass} directive is identical to Python \code{pass} statement: it +does nothing. It can be used when a statement is required syntactically but the +program requires no action. + +The following example does nothing if only \$A is true +\begin{verbatim} +#if $A and $B + do something +#elif $A + #pass +#elif $B + do something +#else + do something +#end if +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#stop} +\label{flowControl.stop} + +Syntax: +\begin{verbatim} +#stop +\end{verbatim} + + +The \code{\#stop} directive is used to stop processing of a template at a +certain point. The output will show {\em only} what has been processed up to +that point. + +When \code{\#stop} is called inside an \code{\#include} it skips the rest of +the included code and continues on from after the \code{\#include} directive. +stop the processing of the included code. Likewise, when \code{\#stop} is +called inside a \code{\#def} or \code{\#block}, it stops only the \code{\#def} +or \code{\#block}. + +\begin{verbatim} +A cat +#if 1 + sat on a mat + #stop + watching a rat +#end if +in a flat. +\end{verbatim} + +will print +\begin{verbatim} +A cat + sat on a mat +\end{verbatim} + +And +\begin{verbatim} +A cat +#block action + sat on a mat + #stop + watching a rat +#end block +in a flat. +\end{verbatim} + +will print + +\begin{verbatim} +A cat + sat on a mat +in a flat. +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#return} +\label{flowControl.return} + +Syntax: +\begin{verbatim} +#return +\end{verbatim} + + +This is used as in Python. \code{\#return} will exit the current method with a +default return value of \code{None} or the value specified. It may be used +only inside a \code{\#def} or a \code{\#block}. + +Note that \code{\#return} is different from the \code{\#stop} directive, +which returns the sum of all text output from the method in which it is called. +The following examples illustrate this point: + +\begin{verbatim} +1 +$test[1] +3 +#def test +1.5 +#if 1 +#return '123' +#else +99999 +#end if +#end def +\end{verbatim} + +will produce +\begin{verbatim} +1 +2 +3 +\end{verbatim} + +while +\begin{verbatim} +1 +$test +3 +#def test +1.5 +#if 1 +#stop +#else +99999 +#end if +#end def +\end{verbatim} + +will produce +\begin{verbatim} +1 +1.5 +3 +\end{verbatim} + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_2_src/10_errorHandling.txt b/docs/users_guide_2_src/10_errorHandling.txt new file mode 100755 index 0000000..28eee3a --- /dev/null +++ b/docs/users_guide_2_src/10_errorHandling.txt @@ -0,0 +1,145 @@ +\section{Error Handling} +\label{errorHandling} + +There are two ways to handle runtime errors (exceptions) in Cheetah. The first +is with the Cheetah directives that mirror Python's structured exception +handling statements. The second is with Cheetah's \code{ErrorCatcher} +framework. These are described below. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#try ... \#except ... \#end try, \#finally, and \#assert} +\label{errorHandling.directives} + +Cheetah's exception-handling directives are exact mirrors Python's +exception-handling statements. See Python's documentation for details. The +following Cheetah code demonstrates their use: + + +\begin{verbatim} +#try + $mightFail() +#except + It failed +#end try + +#try + #assert $x == $y +#except AssertionError + They're not the same! +#end try + +#try + #raise ValueError +#except ValueError + #pass +#end try + + +#try + $mightFail() +#except ValueError + Hey, it raised a ValueError! +#except NameMapper.NotFound + Hey, it raised a NameMapper.NotFound! +#else + It didn't raise anything! +#end try + +#try + $mightFail() +#finally + $cleanup() +#end try +\end{verbatim} + +Like Python, \code{\#except} and \code{\#finally} cannot appear in the same +try-block, but can appear in nested try-blocks. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#errorCatcher and ErrorCatcher objects} +\label{errorHandling.errorCatcher} + +Syntax: +\begin{verbatim} +#errorCatcher CLASS +#errorCatcher $PLACEHOLDER_TO_AN_ERROR_CATCHER_INSTANCE +\end{verbatim} + + +\code{ErrorCatcher} is a debugging tool that catches exceptions that occur +inside \code{\$placeholder} tags and provides a customizable warning to the +developer. Normally, the first missing namespace value raises a +\code{NameMapper.NotFound} error and halts the filling of the template. This +requires the developer to resolve the exceptions in order without seeing the +subsequent output. When an \code{ErrorCatcher} is enabled, the developer can +see all the exceptions at once as well as the template output around them. + +The \code{Cheetah.ErrorCatchers} module defines the base class for +ErrorCatchers: + +\begin{verbatim} +class ErrorCatcher: + _exceptionsToCatch = (NameMapper.NotFound,) + + def __init__(self, templateObj): + pass + + def exceptions(self): + return self._exceptionsToCatch + + def warn(self, exc_val, code, rawCode, lineCol): + return rawCode +\end{verbatim} + +This ErrorCatcher catches \code{NameMapper.NotFound} exceptions and leaves the +offending placeholder visible in its raw form in the template output. If the +following template is executed: +\begin{verbatim} +#errorCatcher Echo +#set $iExist = 'Here I am!' +Here's a good placeholder: $iExist +Here's bad placeholder: $iDontExist +\end{verbatim} + +the output will be: +\begin{verbatim} +Here's a good placeholder: Here I am! +Here's bad placeholder: $iDontExist +\end{verbatim} + +The base class shown above is also accessible under the alias +\code{Cheetah.ErrorCatchers.Echo}. \code{Cheetah.ErrorCatchers} also provides a +number of specialized subclasses that warn about exceptions in different ways. +\code{Cheetah.ErrorCatchers.BigEcho} will output + +\begin{verbatim} +Here's a good placeholder: Here I am! +Here's bad placeholder: ===============<$iDontExist could not be found>=============== +\end{verbatim} + +ErrorCatcher has a significant performance impact and is turned off by default. +It can also be turned on with the \code{Template} class' \code{'errorCatcher'} +keyword argument. The value of this argument should either be a string +specifying which of the classes in \code{Cheetah.ErrorCatchers} to use, or a +class that subclasses \code{Cheetah.ErrorCatchers.ErrorCatcher}. The +\code{\#errorCatcher} directive can also be used to change the errorCatcher part +way through a template. + +\code{Cheetah.ErrorCatchers.ListErrors} will produce the same ouput as +\code{Echo} while maintaining a list of the errors that can be retrieved later. +To retrieve the list, use the \code{Template} class' \code{'errorCatcher'} +method to retrieve the errorCatcher and then call its \code{listErrors} method. + +ErrorCatcher doesn't catch exceptions raised inside directives. + +% @@MO: How do you turn ErrorCatcher off after turn it on. +% '#ErrorCatcher None'? + +% Local Variables: +% TeX-master: "users_guide" +% End: + + + + diff --git a/docs/users_guide_2_src/11_parserInstructions.txt b/docs/users_guide_2_src/11_parserInstructions.txt new file mode 100755 index 0000000..bfd6bc2 --- /dev/null +++ b/docs/users_guide_2_src/11_parserInstructions.txt @@ -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_2_src/12_moduleFormatting.txt b/docs/users_guide_2_src/12_moduleFormatting.txt new file mode 100644 index 0000000..9c558e3 --- /dev/null +++ b/docs/users_guide_2_src/12_moduleFormatting.txt @@ -0,0 +1 @@ +. diff --git a/docs/users_guide_2_src/13_tipsAndTroubleshooting.txt b/docs/users_guide_2_src/13_tipsAndTroubleshooting.txt new file mode 100755 index 0000000..a7b58e5 --- /dev/null +++ b/docs/users_guide_2_src/13_tipsAndTroubleshooting.txt @@ -0,0 +1,549 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Tips, Tricks and Troubleshooting} +\label{tips} + +Troubleshooting: make a precomiled template with "cheetah compile" and inspect +the Python code. Put $_CHEETAH__searchList in the template. (Caveat about +"<value>" results.) Make a tiny template containing only the suspicious code +and precompile it. + +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_2_src/13a_precompiledTemplateModules.txt b/docs/users_guide_2_src/13a_precompiledTemplateModules.txt new file mode 100644 index 0000000..5b0f978 --- /dev/null +++ b/docs/users_guide_2_src/13a_precompiledTemplateModules.txt @@ -0,0 +1,109 @@ +A look inside precompiled template modules +========================================== + +.. + :label: howWorks.pyTrivia + +When debugging a template, it's useful to compile it with "cheetah compile" +and then inspect the resulting Python module. This will often clear up whether +Cheetah misinterpreted your intent. You can do this even if you don't intend to +use the precompiled templates in production. It's also a good way to learn how +Cheetah works. Simply make a throwaway template definition containing only one +placeholder or directive, compile it with "cheetah compile", and see what +Python code Cheetah generated. + +However, precompiled template modules can be a bit cryptic to read unless you +have a bit of background information. Let's look at an example. Put the +following into /tmp/x.tmpl (or any other file) and run "cheetah compile" on +it:: + + The number is $Test.unittest.main. + #set mood = "lucky" + I'm feeling $lucky. + +Open the resulting /tmp/x.py in your favorite text editor. You'll see a class +with the same name as the module:: + + class x(Template): + +This template class contains a method ``.respond()``:: + + def respond(self, trans=None): + ## CHEETAH: main method generated for this template + if (not trans and not self._CHEETAH__isBuffering and + not callable(self.transaction)): + trans = self.transaction # is None unless self.awake() was called + if not trans: + trans = DummyTransaction() + _dummyTrans = True + else: _dummyTrans = False + write = trans.response().write + SL = self._CHEETAH__searchList + _filter = self._CHEETAH__currentFilter + + ######################################## + ## START - generated method body + + + write('The number is ') + _v = VFFSL(SL,"Test.unittest.main",True) + # '$Test.unittest.main' on line 1, col 15 + if _v is not None: write(_filter(_v, rawExpr='$Test.unittest.main')) + # from line 1, col 15. + write('.\n') + mood = "lucky" + write("I'm feeling ") + _v = VFFSL(SL,"lucky",True) # '$lucky' on line 3, col 13 + if _v is not None: write(_filter(_v, rawExpr='$lucky')) + # from line 3, col 13. + write('.\n') + + ######################################## + ## END - generated method body + + return _dummyTrans and trans.response().getvalue() or "" + +This becomes clearer when we scroll up to see some important imports and +global variables:: + + from Cheetah.Template import Template + from Cheetah.DummyTransaction import DummyTransaction + from Cheetah.NameMapper import NotFound, valueFromFrameOrSearchList + VFFSL=valueFromFrameOrSearchList + __CHEETAH_version__ = '2.0rc6' + __CHEETAH_src__ = 'x.tmpl' + +The actual code will differ slightly depending on your Cheetah version. Also, +we've split some long lines to make this page printer-friendly. + +Placeholder lookup is handled by ``VFFSL``, which is really the +``Cheetah.NameMapper.valueFromFrameOrSearchList`` function or its equivalent +in Cheetah/_namemapper.c. + +``trans`` and ``write()`` are Webware compatibility features. Normally +``trans`` is not specified and Cheetah creates a ``DummyTransaction`` +instance. ``write()`` is a shortcut for ``trans.response().write()``, +which concatenates the output to an internal buffer. The method returns +the result: ``trans.response().getvalue()``. You might assume from +``.getvalue()`` that Cheetah uses ``StringIO`` internally, but you'd be wrong. +Cheetah *used* to use ``StringIO`` but now it uses a list and ``str.join()``. +The ``.getvalue()`` name is retained for backward compatibility. + +If this template is part of a Webware site and the user enters its URL, Webware +calls ``.respond()`` with a live Webware transaction. In this case, +``write()`` writes the output directly to Webware's output stream. (Or to +a Webware buffer, but that's not our concern.) There's nothing to return +because the output has already been written, so the method returns the empty +string. That way if it accidentally gets concatenated to the output, no harm +will be done. + +You can write your own transaction class to support non-Webware output +streaming, but Cheetah currently comes with no examples of this. Ask on +the mailing list if you need help with it. + +Global variables and class attributes defined by Cheetah have a +``_CHEETAH_`` prefix. Instance attributes defined by Cheetah have a +``__CHEETAH__`` prefix (two trailing underscores). You should normally +never write to these but you can read them if desired; many are +self-explanatory. One such attribute is ``._CHEETAH__searchList``. This +is the actual search List ``VFFSL()`` will consult for placeholder lookups. diff --git a/docs/users_guide_2_src/14_webware.txt b/docs/users_guide_2_src/14_webware.txt new file mode 100755 index 0000000..8c47e90 --- /dev/null +++ b/docs/users_guide_2_src/14_webware.txt @@ -0,0 +1,582 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\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 <PRE> 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 + + + +``Template`` subclasses Webware's ``Servlet`` class when available, +so the generated class can be used as a Webware servlet. This is practical +only with precompiled templates. + diff --git a/docs/users_guide_2_src/15_otherHtml.txt b/docs/users_guide_2_src/15_otherHtml.txt new file mode 100755 index 0000000..89fd58a --- /dev/null +++ b/docs/users_guide_2_src/15_otherHtml.txt @@ -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_2_src/16_nonHtml.txt b/docs/users_guide_2_src/16_nonHtml.txt new file mode 100755 index 0000000..b618ab0 --- /dev/null +++ b/docs/users_guide_2_src/16_nonHtml.txt @@ -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_2_src/17_libraries.txt b/docs/users_guide_2_src/17_libraries.txt new file mode 100755 index 0000000..dc9231a --- /dev/null +++ b/docs/users_guide_2_src/17_libraries.txt @@ -0,0 +1,306 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Batteries included: templates and other libraries} +\label{libraries} + +Cheetah comes ``batteries included'' with libraries of templates, functions, +classes and other objects you can use in your own programs. The different +types are listed alphabetically below, followed by a longer description of +the SkeletonPage framework. Some of the objects are classes for specific +purposes (e.g., filters or error catchers), while others are standalone and +can be used without Cheetah. + +If you develop any objects which are generally useful for Cheetah sites, +please consider posting them on the wiki with an announcement on the mailing +list so we can incorporate them into the standard library. That way, all +Cheetah users will benefit, and it will encourage others to contribute their +objects, which might include something you want. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{ErrorCatchers} +\label{libraries.ErrorCatchers} + +Module \code{Cheetah.ErrorCatchers} contains error-handling classes suitable for +the \code{\#errorCatcher} directive. These are debugging tools that are not +intended for use in production systems. See section +\ref{errorHandling.errorCatcher} for a description of the error catchers bundled +with Cheetah. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{FileUtils} +\label{libraries.FileUtils} + +Module \code{Cheetah.FileUtils} contains generic functions and classes for +doing bulk search-and-replace on several files, and for finding all the files +in a directory hierarchy whose names match a glob pattern. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Filters} +\label{libraries.Filters} + +Module \code{Filters} contains filters suitable for the \code{\#Filter} +directive. See section \ref{output.filter} for a description of the +filters bundled with Cheetah. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{SettingsManager} +\label{libraries.SettingsManager} + +The \code{SettingsManager} class in the \code{Cheetah.SettingsManager} module is +a baseclass that provides facilities for managing application settings. It +facilitates the use of user-supplied configuration files to fine tune an +application. A setting is a key/value pair that an application or component +(e.g., a filter, or your own servlets) looks up and treats as a configuration +value to modify its (the component's) behaviour. + +SettingsManager is designed to: +\begin{itemize} +\item work well with nested settings dictionaries of any depth +\item read/write \code{.ini style config files} (or strings) +\item read settings from Python source files (or strings) so that + complex Python objects can be stored in the application's settings + dictionary. For example, you might want to store references to various + classes that are used by the application, and plugins to the application + might want to substitute one class for another. +\item allow sections in \code{.ini config files} to be extended by settings in + Python src files. If a section contains a setting like + ``\code{importSettings=mySettings.py}'', \code{SettingsManager} will merge + all the settings defined in ``\code{mySettings.py}'' with the settings for + that section that are defined in the \code{.ini config file}. +\item maintain the case of setting names, unlike the ConfigParser module +\end{itemize} + +Cheetah uses \code{SettingsManager} to manage its configuration settings. +\code{SettingsManager} might also be useful in your own applications. See the +source code and docstrings in the file \code{src/SettingsManager.py} for more +information. + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Templates} +\label{libraries.templates} + +Package \code{Cheetah.Templates} contains stock templates that you can +either use as is, or extend by using the \code{\#def} directive to redefine +specific {\bf blocks}. Currently, the only template in here is SkeletonPage, +which is described in detail below in section +\ref{libraries.templates.skeletonPage}. (Contributed by Tavis Rudd.) + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Tools} +\label{libraries.Tools} + +Package \code{Cheetah.Tools} contains functions and classes contributed by third +parties. Some are Cheetah-specific but others are generic and can be used +standalone. None of them are imported by any other Cheetah component; you can +delete the Tools/ directory and Cheetah will function fine. + +Some of the items in Tools/ are experimental and have been placed there just to +see how useful they will be, and whether they attract enough users to make +refining them worthwhile (the tools, not the users :). + +Nothing in Tools/ is guaranteed to be: (A) tested, (B) reliable, (C) immune +from being deleted in a future Cheetah version, or (D) immune from +backwards-incompatable changes. If you depend on something in Tools/ on a +production system, consider making a copy of it outside the Cheetah/ directory +so that this version won't be lost when you upgrade Cheetah. Also, learn +enough about Python and about the Tool so that you can maintain it and bugfix +it if necessary. + +If anything in Tools/ is found to be necessary to Cheetah's operation (i.e., if +another Cheetah component starts importing it), it will be moved to the +\code{Cheetah.Utils} package. + +Current Tools include: +\begin{description} +\item{Cheetah.Tools.MondoReport} an ambitious class useful when + iterating over records of data (\code{\#for} loops), displaying one + pageful of records at a time (with previous/next links), and printing + summary statistics about the records or the current page. See + \code{MondoReportDoc.txt} in the same directory as the module. Some + features are not implemented yet. \code{MondoReportTest.py} is a test + suite (and it shows there are currently some errors in MondoReport, hmm). + Contributed by Mike Orr. + +\item{Cheetah.Tools.RecursiveNull} Nothing, but in a friendly way. Good + for filling in for objects you want to hide. If \code{\$form.f1} is a + RecursiveNull object, then \code{\$form.f1.anything["you"].might("use")} + will resolve to the empty string. You can also put a \code{RecursiveNull} + instance at the end of the searchList to convert missing values to '' + rather than raising a \code{NotFound} error or having a (less efficient) + errorCatcher handle it. Of course, maybe you prefer to get a + \code{NotFound} error... Contributed by Ian Bicking. + +\item{Cheetah.Tools.SiteHierarchy} Provides navigational links to this + page's parents and children. The constructor takes a recursive list of + (url,description) pairs representing a tree of hyperlinks to every page in + the site (or section, or application...), and also a string containing the + current URL. Two methods 'menuList' and 'crumbs' return output-ready HTML + showing an indented menu (hierarchy tree) or crumbs list (Yahoo-style bar: + home > grandparent > parent > currentURL). Contributed by Ian Bicking. + +\item +\end{description} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Utils} +\label{libraries.Utils} + +Package \code{Cheetah.Utils} contains non-Cheetah-specific functions and +classes that are imported by other Cheetah components. Many of these utils can +be used standalone in other applications too. + +Current Utils include: +\begin{description} +\item{Cheetah.Utils.CGIImportMixin} This is inherited by \code{Template} + objects, and provides the method, \code{.cgiImport} method + (section \ref{webware.cgiImport}). + +\item{Cheetah.Utils.Misc} A catch-all module for small functions. + \begin{description} + \item{\code{UseOrRaise(thing, errmsg='')}} Raise 'thing' if it's a + subclass of Exception, otherwise return it. Useful when one + argument does double duty as a default value or an exception to + throw. Contribyted by Mike Orr. + + \item{\code{checkKeywords(dic, legalKeywords, what='argument'}} + Verifies the dictionary does not contain any keys not listed in + 'legalKeywords'. If it does, raise TypeError. Useful for + checking the keyword arguments to a function. Contributed by + Mike Orr. + \end{description} + +\item{Cheetah.Utils.UploadFileMixin} Not implemented yet, but will contain + the \code{.uploadFile} method (or three methods) to ``safely'' copy a + form-uploaded file to a local file, to a searchList variable, or return + it. When finished, this will be inherited by \code{Template}, allowing + all templates to do this. If you want this feature, read the docstring + in the source and let us know on the mailing list what you'd like this + method to do. Contributed by Mike Orr. + +\item{Cheetah.Utils.VerifyType} Functions to verify the type of a + user-supplied function argument. Contributed by Mike Orr. +\end{description} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Cheetah.Templates.SkeletonPage} +\label{libraries.templates.skeletonPage} + +A stock template class that may be useful for web developers is defined in +the \code{Cheetah.Templates.SkeletonPage} module. The \code{SkeletonPage} +template class is generated from the following Cheetah source code: + +\begin{verbatim} +##doc-module: A Skeleton HTML page template, that provides basic structure and utility methods. +################################################################################ +#extends Cheetah.Templates._SkeletonPage +#implements respond +################################################################################ +#cache id='header' +$docType +$htmlTag +<!-- This document was autogenerated by Cheetah(http://CheetahTemplate.org). +Do not edit it directly! + +Copyright $currentYr - $siteCopyrightName - All Rights Reserved. +Feel free to copy any javascript or html you like on this site, +provided you remove all links and/or references to $siteDomainName +However, please do not copy any content or images without permission. + +$siteCredits + +--> + + +#block writeHeadTag +<head> +<title>$title</title> +$metaTags +$stylesheetTags +$javascriptTags +</head> +#end block writeHeadTag + +#end cache header +################# + +$bodyTag + +#block writeBody +This skeleton page has no flesh. Its body needs to be implemented. +#end block writeBody + +</body> +</html> +\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} +<ul> +<dtml-in frogQuery> + <li><dtml-var animal_name></li> +</dtml-in> +</ul> +\end{verbatim} + +\begin{verbatim} +<ul> +#for $animal_name in $frogQuery + <li>$animal_name</li> +#end for +</ul> +\end{verbatim} + +\begin{verbatim} +<dtml-if expr="monkeys > monkey_limit"> + <p>There are too many monkeys!</p> +<dtml-elif expr="monkeys < minimum_monkeys"> + <p>There aren't enough monkeys!</p> +<dtml-else> + <p>There are just enough monkeys.</p> +</dtml-if> +\end{verbatim} + +\begin{verbatim} +#if $monkeys > $monkey_limit + <p>There are too many monkeys!</p> +#else if $monkeys < $minimum_monkeys + <p>There aren't enough monkeys!</p> +#else + <p>There are just enough monkeys.</p> +#end if +\end{verbatim} + +\begin{verbatim} +<table> +<dtml-in expr="objectValues('File')"> + <dtml-if sequence-even> + <tr bgcolor="grey"> + <dtml-else> + <tr> + </dtml-if> + <td> + <a href="&dtml-absolute_url;"><dtml-var title_or_id></a> + </td></tr> +</dtml-in> +</table> +\end{verbatim} + +\begin{verbatim} +<table> +#set $evenRow = 0 +#for $file in $files('File') + #if $evenRow + <tr bgcolor="grey"> + #set $evenRow = 0 + #else + <tr> + #set $evenRow = 1 + #end if + <td> + <a href="$file.absolute_url">$file.title_or_id</a> + </td></tr> +#end for +</table> +\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{<dtml-in>} tag. We are also planning an output filter as flexible as +the \code{<dtml-var>} 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{<!-- BEGIN blockName --> \ldots + <!-- END blockName>}. The \code{set\_block} method extracts this text + into a namespace variable and puts a placeholder referring to it in the + template. This has a few parallels with Cheetah's \code{\#block} + directive but is overall quite different. +\item To do the equivalent of \code{\#if}, extract the block. Then if true, do + nothing. If false, assign the empty string to the namespace variable. +\item To do the equivalent of \code{\#for}, extract the block. Set any + namespace variables needed inside the loop. To parse one iteration, use + the \code{parse} method to fill the block variable (a mini-template) into + another namespace variable, appending to it. Refresh the namespace + variables needed inside the loop and parse again; repeat for each + iteration. You'll end up with a mini-result that will be plugged into the + main template's placeholder. +\item To read a template definition from a file, use the \code{set\_file} + method. This places the file's content in a namespace variable. + To read a template definition from a string, assign it to a namespace + variable. +\item Thus, for complicated templates, you are doing a lot of recursive block + filling and file reading and parsing mini-templates all into one flat + namespace as you finally build up values for the main template. In + Cheetah, all this display logic can be embedded into the template using + directives, calling out to Python methods for the more complicated tasks. +\item Although you can nest blocks in the template, it becomes tedious and + arguably hard to read, because all blocks have identical syntax. Unless + you choose your block names carefully and put comments around them, it's + hard to tell which blocks are if-blocks and which are for-blocks, or what + their nesting order is. +\item PHPLib templates do not have caching, output filters, etc. +\end{itemize} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. PSP, PHP, ASP, JSP, Embperl, etc.} +\label{comparisons.pspEtc} + +\begin{description} +\item[Webware's PSP Component] -- \url{http://webware.sourceforge.net/Webware/PSP/Docs/} +\item[Tomcat JSP Information] -- \url{http://jakarta.apache.org/tomcat/index.html} +\item[ASP Information at ASP101] -- \url{http://www.asp101.com/} +\item[Embperl] -- \url{http://perl.apache.org/embperl/} +\end{description} + + +Here's a basic Cheetah example: +\begin{verbatim} +<TABLE> +#for $client in $service.clients +<TR> +<TD>$client.surname, $client.firstname</TD> +<TD><A HREF="mailto:$client.email" >$client.email</A></TD> +</TR> +#end for +</TABLE> +\end{verbatim} + +Compare this with PSP: + +\begin{verbatim} +<TABLE> +<% for client in service.clients(): %> +<TR> +<TD><%=client.surname()%>, <%=client.firstname()%></TD> +<TD><A HREF="mailto:<%=client.email()%>"><%=client.email()%></A></TD> +</TR> +<%end%> +</TABLE> +\end{verbatim} + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_2_src/E_license.txt b/docs/users_guide_2_src/E_license.txt new file mode 100644 index 0000000..8a5a73f --- /dev/null +++ b/docs/users_guide_2_src/E_license.txt @@ -0,0 +1,32 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{License} +\label{intro.license} + +\paragraph*{The gist} +Cheetah is open source, but products developed with Cheetah or derived +from Cheetah may be open source or closed source. + +(@@MO If this licence is identical to the MIT license, let's say so. That will +make it easier for distributors/aggregators to classify the product.) + +\paragraph*{Legal terms} +Copyright \copyright 2001-2006, The Cheetah Development Team: Tavis Rudd, Mike +Orr, Ian Bicking, Chuck Esterbrook, JJ Behrens. + +(@@MO Who is the current development team? Chuck and Ian have not been major +contributors for years. However, some of their code may remain in Cheetah.) + +Permission to use, copy, modify, and distribute this software for any purpose +and without fee is hereby granted, provided that the above copyright notice +appear in all copies and that both that copyright notice and this permission +notice appear in supporting documentation, and that the names of the authors not +be used in advertising or publicity pertaining to distribution of the software +without specific, written prior permission. + +THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS +BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + diff --git a/docs/users_guide_2_src/Makefile b/docs/users_guide_2_src/Makefile new file mode 100644 index 0000000..ad0b786 --- /dev/null +++ b/docs/users_guide_2_src/Makefile @@ -0,0 +1,16 @@ +RST = rst2html.py --stylesheet=default.css --link-stylesheet --initial-header-level=2 + +#%.html: %.txt +# ${RST} $< $@ + +all: + #${RST} --warnings=/dev/null index.txt index.html + ${RST} 01_introduction.txt 01_introduction.html + ${RST} 02_glossary.txt 02_glossary.html + ${RST} 03_gettingStarted.txt 03_gettingStarted.html + ${RST} 04_howItWorks.txt 04_howItWorks.html + ${RST} 04_howItWorks.txt 04_howItWorks.html + ${RST} 13a_precompiledTemplateModules.txt 13a_precompiledTemplateModules.html + + +# vim: sw=8 ts=8 noexpandtab ai diff --git a/docs/users_guide_2_src/default.css b/docs/users_guide_2_src/default.css new file mode 100644 index 0000000..fa715d6 --- /dev/null +++ b/docs/users_guide_2_src/default.css @@ -0,0 +1,293 @@ +/* BEGIN Cheetah additions. *********************************** */ + +body { + /* font-size: 10pt; */ +} + +blockquote { + font-family: sans-serif; +} + +li { + margin-bottom: 1em; +} + +/* END Cheetah additions. ************************************ */ + +/* +:Author: David Goodger +:Contact: goodger@users.sourceforge.net +:Date: $Date: 2006/02/20 07:38:08 $ +:Revision: $Revision: 1.1 $ +:Copyright: This stylesheet has been placed in the public domain. + +Default cascading style sheet for the HTML output of Docutils. + +See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to +customize this style sheet. +*/ + +/* "! important" is used here to override other ``margin-top`` and + ``margin-bottom`` styles that are later in the stylesheet or + more specific. See http://www.w3.org/TR/CSS1#the-cascade */ +.first { + margin-top: 0 ! important } + +.last, .with-subtitle { + margin-bottom: 0 ! important } + +.hidden { + display: none } + +a.toc-backref { + text-decoration: none ; + color: black } + +blockquote.epigraph { + margin: 2em 5em ; } + +dl.docutils dd { + margin-bottom: 0.5em } + +dl.docutils dt { + font-weight: bold } + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.admonition, div.attention, div.caution, div.danger, div.error, +div.hint, div.important, div.note, div.tip, div.warning { + margin: 2em ; + border: medium outset ; + padding: 1em } + +div.admonition p.admonition-title, div.hint p.admonition-title, +div.important p.admonition-title, div.note p.admonition-title, +div.tip p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +/* Uncomment (and remove this text!) to get reduced vertical space in + compound paragraphs. +div.compound .compound-first, div.compound .compound-middle { + margin-bottom: 0.5em } + +div.compound .compound-last, div.compound .compound-middle { + margin-top: 0.5em } +*/ + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + margin-left: 2em } + +div.footer, div.header { + clear: both; + font-size: smaller } + +div.line-block { + display: block ; + margin-top: 1em ; + margin-bottom: 1em } + +div.line-block div.line-block { + margin-top: 0 ; + margin-bottom: 0 ; + margin-left: 1.5em } + +div.sidebar { + margin-left: 1em ; + border: medium outset ; + padding: 1em ; + background-color: #ffffee ; + width: 40% ; + float: right ; + clear: right } + +div.sidebar p.rubric { + font-family: sans-serif ; + font-size: medium } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + border: medium outset ; + padding: 1em } + +div.system-message p.system-message-title { + color: red ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, +h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { + margin-top: 0.4em } + +h1.title { + text-align: center } + +h2.subtitle { + text-align: center } + +hr.docutils { + width: 75% } + +img.align-left { + clear: left } + +img.align-right { + clear: right } + +img.borderless { + border: 0 } + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.attribution { + text-align: right ; + margin-left: 50% } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.label { + white-space: nowrap } + +p.rubric { + font-weight: bold ; + font-size: larger ; + color: maroon ; + text-align: center } + +p.sidebar-title { + font-family: sans-serif ; + font-weight: bold ; + font-size: larger } + +p.sidebar-subtitle { + font-family: sans-serif ; + font-weight: bold } + +p.topic-title { + font-weight: bold } + +pre.address { + margin-bottom: 0 ; + margin-top: 0 ; + font-family: serif ; + font-size: 100% } + +pre.line-block { + font-family: serif ; + font-size: 100% } + +pre.literal-block, pre.doctest-block { + margin-left: 2em ; + margin-right: 2em ; + background-color: #eeeeee } + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.interpreted { + font-family: sans-serif } + +span.option { + white-space: nowrap } + +span.pre { + white-space: pre } + +span.problematic { + color: red } + +span.section-subtitle { + /* font-size relative to parent (h1..h6 element) */ + font-size: 80% } + +table.citation { + border-left: solid thin gray } + +table.docinfo { + margin: 2em 4em } + +table.docutils { + margin-top: 0.5em ; + margin-bottom: 0.5em } + +table.footnote { + border-left: solid thin black } + +table.docutils td, table.docutils th, +table.docinfo td, table.docinfo th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: top } + +table.docutils th.field-name, table.docinfo th.docinfo-name { + font-weight: bold ; + text-align: left ; + white-space: nowrap ; + padding-left: 0 } + +h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, +h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { + font-size: 100% } + +tt.docutils { + background-color: #eeeeee } + +ul.auto-toc { + list-style-type: none } + + +/* vim: sw=4 ts=4 expandtab ai */ diff --git a/docs/users_guide_2_src/eg_1.py b/docs/users_guide_2_src/eg_1.py new file mode 100644 index 0000000..8098e6b --- /dev/null +++ b/docs/users_guide_2_src/eg_1.py @@ -0,0 +1,11 @@ +#eg_1 +# +#Looking up values held in dictionaries. +#No need to use all values in searchlist. + +from Cheetah.Template import Template +tmpl = "$value1 $value2 $value3" +NS = [{'value1':1, 'value2':2}, {'value3':3},{'value4':4}] +T = Template.compile(source=tmpl) +t = T(namespaces=NS) +print t.respond() #1,2,3 diff --git a/docs/users_guide_2_src/eg_2.py b/docs/users_guide_2_src/eg_2.py new file mode 100644 index 0000000..ee0f7a7 --- /dev/null +++ b/docs/users_guide_2_src/eg_2.py @@ -0,0 +1,10 @@ +from Cheetah.Template import Template + +#A retrieved value can be any Python object and can be used _exactly_ +#as it would be in Python code + +tmpl = "$value1, $value2, $value3[0], $value3[1], $value4[0]['this'][0]" +NS = [{'value1':1, 'value2':2, 'value3':[3,4], 'value4': [ {'this':[5]}]} ] +#Compile and fill template in one step +t = Template.compile(source=tmpl)(namespaces=NS) +print t.respond() #1, 2, 3, 4, 5 diff --git a/docs/users_guide_2_src/eg_3.py b/docs/users_guide_2_src/eg_3.py new file mode 100644 index 0000000..5c89a65 --- /dev/null +++ b/docs/users_guide_2_src/eg_3.py @@ -0,0 +1,18 @@ +from Cheetah.Template import Template + +#The namespaces list is a list of dictionaries and/or +#class instances. Search is for dictionary key or object +#attributes in this list +class X: + pass + + +x = X() +x.value3 = 3 +x.value4 = 4 + +tmpl = "$value1, $value2, $value3, $value4" +NS = [{'value1':1},{'value2':2}, x] + +t = Template.compile(source=tmpl)(namespaces=NS) +print t.respond() #1,2,3,4 diff --git a/docs/users_guide_2_src/eg_4.py b/docs/users_guide_2_src/eg_4.py new file mode 100644 index 0000000..8fab657 --- /dev/null +++ b/docs/users_guide_2_src/eg_4.py @@ -0,0 +1,22 @@ +from Cheetah.Template import Template +from Cheetah import NameMapper + +#Error. Cheetah cannot find 'x' because +#it is not dictionary key or instance member: + + +class X: + pass + +x = X() +x.value3 = 3 + +tmpl = "$x.value3" +NS = [x] +t = Template.compile(source=tmpl)(namespaces=NS) +try: + t.respond() #Here substitution is attempted +except NameMapper.NotFound, e: + print 'NameMapper.NotFound: %s' % e + #NameMapper.NotFound: cannot find 'x' + diff --git a/docs/users_guide_2_src/eg_5.py b/docs/users_guide_2_src/eg_5.py new file mode 100644 index 0000000..551f9c0 --- /dev/null +++ b/docs/users_guide_2_src/eg_5.py @@ -0,0 +1,25 @@ +from Cheetah.Template import Template + +# ways of using Python to process values after +#retrieval. 1. Sets a new variable then uses it, +#2. Uses pure Python function to set new variable +#3. Cheetah calls function directly +#4. Extended ${} syntax without function call + +tmpl = """ + +#set $value1 = $value.replace(' ','-') +1. $value1 +<% def change(x): + return x.replace(' ','-') +%> +#set $value1 = change($value) +2. $value1 +3. $change($value) +4. ${value.replace(' ','-')} +""" +NS = [ {'value':'this and that'}] + +#compile and fill the template +t = Template(source=tmpl, namespaces=NS) +print t.respond() diff --git a/docs/users_guide_2_src/latex2rst.py b/docs/users_guide_2_src/latex2rst.py new file mode 100755 index 0000000..80f9a1d --- /dev/null +++ b/docs/users_guide_2_src/latex2rst.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +"""Convert files from LaTeX format to ReStructured Text. + + This converter is meant only for saving keystrokes. It won't catch + everything and it may misformat stuff, so proofread the file after + processing. + + "Verbatim" blocks are not converted due to the difficulty in placing the + preceding colon(s) and indenting every line. +""" +import os, re, shutil, sys + +def convert(filename): + print "Processing file", filename + backup = filename + ".bak" + shutil.copy2(filename, backup) + f = open(filename, 'r+') + text = f.read() + text = re.sub( R"%%%+", R"", text) + text = re.sub( R"\\section\{(.*?)\}", R"\1\n" + ("=" * 40), text) + text = re.sub( R"\\subsection\{(.*?)\}", R"\1\n" + ("-" * 40), text) + text = re.sub( R"\\label\{(.*?)\}", R"\n..\n :label: \1", text) + text = re.sub( R"``|''", R'"', text) + text = re.sub( R"(?s)\{\\em (.*?)\}", R"*\1*", text) + text = re.sub( R"(?s)\{\\bf (.*?)\}", R"**\1**", text) + text = re.sub( R"(?s)\\code\{(.*?)\}", R"``\1``", text) + text = re.sub( R"\\(begin|end)\{(itemize|enumerate)\}\n", R"", text) + text = re.sub( R"\\item ", R"* ", text) + #text = re.sub( + # R"(?sm)(\w):\n\s*^\\begin\{verbatim\}\s*(.*?)\\end\{verbatim\}", + # R"\1::\n\n\2", text) + f.seek(0) + f.write(text) + f.truncate() + f.close() + + +def main(): + if len(sys.argv) < 2: + prog = os.path.basename(sys.argv[0]) + raise SystemExit("usage: %s FILENAMES ..." % prog) + for filename in sys.argv[1:]: + convert(filename) + +if __name__ == "__main__": main() diff --git a/docs/users_guide_2_src/unused.txt b/docs/users_guide_2_src/unused.txt new file mode 100644 index 0000000..3b78fc9 --- /dev/null +++ b/docs/users_guide_2_src/unused.txt @@ -0,0 +1,67 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Give me an example of a Webware servlet!} +\label{intro.example.servlet} + +This example uses an HTML form to ask the user's name, then invokes itself +again to display a {\em personalized} friendly greeting. + +\begin{verbatim} +<HTML><HEAD><TITLE>My Template-Servlet</TITLE></HEAD><BODY> +#set $name = $request.field('name', None) +#if $name +Hello $name +#else +<FORM ACTION="" METHOD="GET"> +Name: <INPUT TYPE="text" NAME="name"><BR> +<INPUT TYPE="submit"> +</FORM> +#end if +</BODY></HTML> +\end{verbatim} + +To try it out for yourself on a Webware system: +\begin{enumerate} +\item copy the template definition to a file {\bf test.tmpl} in your + Webware servlet directory. +\item Run ``\code{cheetah compile test.tmpl}''. This produces + {\bf test.py} (a .py template module) in the same directory. +\item In your web browser, go to {\bf test.py}, using whatever site and + directory is appropriate. Depending on your Webware configuration, you may + also be able to go to {\bf test}. +\end{enumerate} + +At the first request, field `name' will be blank (false) so the ``\#else'' +portion will execute and present a form. You type your name and press submit. +The form invokes the same page. Now `name' is true so the ``\#if'' portion +executes, which displays the greeting. The ``\#set'' directive creates a +local variable that lasts while the template is being filled. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +To install Cheetah in your system-wide Python library: +* Login as a user with privileges to install system-wide Python packages. + On POSIX systems (AIX, Solaris, Linux, IRIX, etc.), the command is + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Certain test failures are insignificant: +\begin{description} +\item{**AssertionError: Template output mismatch: Expected Output = 0(end) +Actual Output = False(end)**} Python 2.3 changed the string representation of +booleans, and the tests haven't yet been updated to reflect this. +\item{**AssertionError: subcommand exit status 127**} Certain tests run +"cheetah" as a subcommand. The failure may mean the command wasn't found +in your system path. (What happens if you run "cheetah" on the command line?) +The failure also happens on some Windows systems for unknown reasons. This +failure has never been observed outside the test suite. Long term, we plan to +rewrite the tests to do a function call rather than a subcommand, which will +also make the tests run significantly faster. +\item{**ImportError: No module named SampleBaseClass**} The test tried to +write a temporary module in the current directory and ``import`` it. Reread +the first paragraph in this section about the current directory. +\item{**ImportError: No module named tmp**} May be the same problem as +SampleBaseClass; let us know if changing the current directory doesn't work. +\end{description} + + normally 'su root'. On non-POSIX systems such as Windows NT, login as an + administrator. diff --git a/docs/users_guide_src/Makefile b/docs/users_guide_src/Makefile new file mode 100755 index 0000000..8b8e977 --- /dev/null +++ b/docs/users_guide_src/Makefile @@ -0,0 +1,39 @@ +# You must change PYTHONSRC to the path of your Python source distributon. +# OR just create a symlink that matches this path. +PYTHONSRC=/usr/local/src/Python-source +DOCNAME=users_guide +MKHOWTO=$(PYTHONSRC)/Doc/tools/mkhowto +MAIN_TEX_FILE= users_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/users_guide_src/README b/docs/users_guide_src/README new file mode 100755 index 0000000..3b45564 --- /dev/null +++ b/docs/users_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/users_guide_src/comments.tex b/docs/users_guide_src/comments.tex new file mode 100755 index 0000000..36323cf --- /dev/null +++ b/docs/users_guide_src/comments.tex @@ -0,0 +1,99 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Comments} +\label{comments} + +Comments are used to mark notes, explanations, and decorative text that should +not appear in the output. Cheetah maintains the comments in the Python module +it generates from the Cheetah source code. There are two forms of the comment +directive: single-line and multi-line. + +All text in a template definition that lies between two hash characters +(\code{\#\#}) and the end of the line is treated as a single-line comment and +will not show up in the output, unless the two hash characters are escaped with +a backslash. +\begin{verbatim} +##============================= this is a decorative comment-bar +$var ## this is an end-of-line comment +##============================= +\end{verbatim} + +Any text between \code{\#*} and \code{*\#} will be treated as a multi-line +comment. +\begin{verbatim} +#* + Here is some multiline + comment text +*# +\end{verbatim} + +If you put blank lines around method definitions or loops to separate them, +be aware that the blank lines will be output as is. To avoid this, make sure +the blank lines are enclosed in a comment. Since you normally have a +comment before the next method definition (right?), you can just extend that +comment to include the blank lines after the previous method definition, like +so: +\begin{verbatim} +#def method1 +... lines ... +#end def +#* + + + Description of method2. + $arg1, string, a phrase. +*# +#def method2($arg1) +... lines ... +#end def +\end{verbatim} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Docstring Comments} +\label{comments.docstring} + +Python modules, classes, and methods can be documented with inline +'documentation strings' (aka 'docstrings'). Docstrings, unlike comments, are +accesible at run-time. Thus, they provide a useful hook for interactive help +utilities. + +Cheetah comments can be transformed into doctrings by adding one of the +following prefixes: + +\begin{verbatim} +##doc: This text will be added to the method docstring +#*doc: If your template file is MyTemplate.tmpl, running "cheetah compile" + on it will produce MyTemplate.py, with a class MyTemplate in it, + containing a method .respond(). This text will be in the .respond() + method's docstring. *# + +##doc-method: This text will also be added to .respond()'s docstring +#*doc-method: This text will also be added to .respond()'s docstring *# + +##doc-class: This text will be added to the MyTemplate class docstring +#*doc-class: This text will be added to the MyTemplate class docstring *# + +##doc-module: This text will be added to the module docstring MyTemplate.py +#*doc-module: This text will be added to the module docstring MyTemplate.py*# +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Header Comments} +\label{comments.headers} +Cheetah comments can also be transformed into module header comments using the +following syntax: + +\begin{verbatim} +##header: This text will be added to the module header comment +#*header: This text will be added to the module header comment *# +\end{verbatim} + +Note the difference between \code{\#\#doc-module: } and \code{header: }: +``cheetah-compile'' puts \code{\#\#doc-module: } text inside the module +docstring. \code{header: } makes the text go {\em above} the docstring, as a +set of \#-prefixed comment lines. + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_src/comparisons.tex b/docs/users_guide_src/comparisons.tex new file mode 100755 index 0000000..56a0fb3 --- /dev/null +++ b/docs/users_guide_src/comparisons.tex @@ -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} +<ul> +<dtml-in frogQuery> + <li><dtml-var animal_name></li> +</dtml-in> +</ul> +\end{verbatim} + +\begin{verbatim} +<ul> +#for $animal_name in $frogQuery + <li>$animal_name</li> +#end for +</ul> +\end{verbatim} + +\begin{verbatim} +<dtml-if expr="monkeys > monkey_limit"> + <p>There are too many monkeys!</p> +<dtml-elif expr="monkeys < minimum_monkeys"> + <p>There aren't enough monkeys!</p> +<dtml-else> + <p>There are just enough monkeys.</p> +</dtml-if> +\end{verbatim} + +\begin{verbatim} +#if $monkeys > $monkey_limit + <p>There are too many monkeys!</p> +#else if $monkeys < $minimum_monkeys + <p>There aren't enough monkeys!</p> +#else + <p>There are just enough monkeys.</p> +#end if +\end{verbatim} + +\begin{verbatim} +<table> +<dtml-in expr="objectValues('File')"> + <dtml-if sequence-even> + <tr bgcolor="grey"> + <dtml-else> + <tr> + </dtml-if> + <td> + <a href="&dtml-absolute_url;"><dtml-var title_or_id></a> + </td></tr> +</dtml-in> +</table> +\end{verbatim} + +\begin{verbatim} +<table> +#set $evenRow = 0 +#for $file in $files('File') + #if $evenRow + <tr bgcolor="grey"> + #set $evenRow = 0 + #else + <tr> + #set $evenRow = 1 + #end if + <td> + <a href="$file.absolute_url">$file.title_or_id</a> + </td></tr> +#end for +</table> +\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{<dtml-in>} tag. We are also planning an output filter as flexible as +the \code{<dtml-var>} 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{<!-- BEGIN blockName --> \ldots + <!-- END blockName>}. The \code{set\_block} method extracts this text + into a namespace variable and puts a placeholder referring to it in the + template. This has a few parallels with Cheetah's \code{\#block} + directive but is overall quite different. +\item To do the equivalent of \code{\#if}, extract the block. Then if true, do + nothing. If false, assign the empty string to the namespace variable. +\item To do the equivalent of \code{\#for}, extract the block. Set any + namespace variables needed inside the loop. To parse one iteration, use + the \code{parse} method to fill the block variable (a mini-template) into + another namespace variable, appending to it. Refresh the namespace + variables needed inside the loop and parse again; repeat for each + iteration. You'll end up with a mini-result that will be plugged into the + main template's placeholder. +\item To read a template definition from a file, use the \code{set\_file} + method. This places the file's content in a namespace variable. + To read a template definition from a string, assign it to a namespace + variable. +\item Thus, for complicated templates, you are doing a lot of recursive block + filling and file reading and parsing mini-templates all into one flat + namespace as you finally build up values for the main template. In + Cheetah, all this display logic can be embedded into the template using + directives, calling out to Python methods for the more complicated tasks. +\item Although you can nest blocks in the template, it becomes tedious and + arguably hard to read, because all blocks have identical syntax. Unless + you choose your block names carefully and put comments around them, it's + hard to tell which blocks are if-blocks and which are for-blocks, or what + their nesting order is. +\item PHPLib templates do not have caching, output filters, etc. +\end{itemize} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Cheetah vs. PSP, PHP, ASP, JSP, Embperl, etc.} +\label{comparisons.pspEtc} + +\begin{description} +\item[Webware's PSP Component] -- \url{http://webware.sourceforge.net/Webware/PSP/Docs/} +\item[Tomcat JSP Information] -- \url{http://jakarta.apache.org/tomcat/index.html} +\item[ASP Information at ASP101] -- \url{http://www.asp101.com/} +\item[Embperl] -- \url{http://perl.apache.org/embperl/} +\end{description} + + +Here's a basic Cheetah example: +\begin{verbatim} +<TABLE> +#for $client in $service.clients +<TR> +<TD>$client.surname, $client.firstname</TD> +<TD><A HREF="mailto:$client.email" >$client.email</A></TD> +</TR> +#end for +</TABLE> +\end{verbatim} + +Compare this with PSP: + +\begin{verbatim} +<TABLE> +<% for client in service.clients(): %> +<TR> +<TD><%=client.surname()%>, <%=client.firstname()%></TD> +<TD><A HREF="mailto:<%=client.email()%>"><%=client.email()%></A></TD> +</TR> +<%end%> +</TABLE> +\end{verbatim} + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_src/editors.tex b/docs/users_guide_src/editors.tex new file mode 100755 index 0000000..84c8f03 --- /dev/null +++ b/docs/users_guide_src/editors.tex @@ -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_src/errorHandling.tex b/docs/users_guide_src/errorHandling.tex new file mode 100755 index 0000000..28eee3a --- /dev/null +++ b/docs/users_guide_src/errorHandling.tex @@ -0,0 +1,145 @@ +\section{Error Handling} +\label{errorHandling} + +There are two ways to handle runtime errors (exceptions) in Cheetah. The first +is with the Cheetah directives that mirror Python's structured exception +handling statements. The second is with Cheetah's \code{ErrorCatcher} +framework. These are described below. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#try ... \#except ... \#end try, \#finally, and \#assert} +\label{errorHandling.directives} + +Cheetah's exception-handling directives are exact mirrors Python's +exception-handling statements. See Python's documentation for details. The +following Cheetah code demonstrates their use: + + +\begin{verbatim} +#try + $mightFail() +#except + It failed +#end try + +#try + #assert $x == $y +#except AssertionError + They're not the same! +#end try + +#try + #raise ValueError +#except ValueError + #pass +#end try + + +#try + $mightFail() +#except ValueError + Hey, it raised a ValueError! +#except NameMapper.NotFound + Hey, it raised a NameMapper.NotFound! +#else + It didn't raise anything! +#end try + +#try + $mightFail() +#finally + $cleanup() +#end try +\end{verbatim} + +Like Python, \code{\#except} and \code{\#finally} cannot appear in the same +try-block, but can appear in nested try-blocks. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#errorCatcher and ErrorCatcher objects} +\label{errorHandling.errorCatcher} + +Syntax: +\begin{verbatim} +#errorCatcher CLASS +#errorCatcher $PLACEHOLDER_TO_AN_ERROR_CATCHER_INSTANCE +\end{verbatim} + + +\code{ErrorCatcher} is a debugging tool that catches exceptions that occur +inside \code{\$placeholder} tags and provides a customizable warning to the +developer. Normally, the first missing namespace value raises a +\code{NameMapper.NotFound} error and halts the filling of the template. This +requires the developer to resolve the exceptions in order without seeing the +subsequent output. When an \code{ErrorCatcher} is enabled, the developer can +see all the exceptions at once as well as the template output around them. + +The \code{Cheetah.ErrorCatchers} module defines the base class for +ErrorCatchers: + +\begin{verbatim} +class ErrorCatcher: + _exceptionsToCatch = (NameMapper.NotFound,) + + def __init__(self, templateObj): + pass + + def exceptions(self): + return self._exceptionsToCatch + + def warn(self, exc_val, code, rawCode, lineCol): + return rawCode +\end{verbatim} + +This ErrorCatcher catches \code{NameMapper.NotFound} exceptions and leaves the +offending placeholder visible in its raw form in the template output. If the +following template is executed: +\begin{verbatim} +#errorCatcher Echo +#set $iExist = 'Here I am!' +Here's a good placeholder: $iExist +Here's bad placeholder: $iDontExist +\end{verbatim} + +the output will be: +\begin{verbatim} +Here's a good placeholder: Here I am! +Here's bad placeholder: $iDontExist +\end{verbatim} + +The base class shown above is also accessible under the alias +\code{Cheetah.ErrorCatchers.Echo}. \code{Cheetah.ErrorCatchers} also provides a +number of specialized subclasses that warn about exceptions in different ways. +\code{Cheetah.ErrorCatchers.BigEcho} will output + +\begin{verbatim} +Here's a good placeholder: Here I am! +Here's bad placeholder: ===============<$iDontExist could not be found>=============== +\end{verbatim} + +ErrorCatcher has a significant performance impact and is turned off by default. +It can also be turned on with the \code{Template} class' \code{'errorCatcher'} +keyword argument. The value of this argument should either be a string +specifying which of the classes in \code{Cheetah.ErrorCatchers} to use, or a +class that subclasses \code{Cheetah.ErrorCatchers.ErrorCatcher}. The +\code{\#errorCatcher} directive can also be used to change the errorCatcher part +way through a template. + +\code{Cheetah.ErrorCatchers.ListErrors} will produce the same ouput as +\code{Echo} while maintaining a list of the errors that can be retrieved later. +To retrieve the list, use the \code{Template} class' \code{'errorCatcher'} +method to retrieve the errorCatcher and then call its \code{listErrors} method. + +ErrorCatcher doesn't catch exceptions raised inside directives. + +% @@MO: How do you turn ErrorCatcher off after turn it on. +% '#ErrorCatcher None'? + +% Local Variables: +% TeX-master: "users_guide" +% End: + + + + diff --git a/docs/users_guide_src/examples.tex b/docs/users_guide_src/examples.tex new file mode 100755 index 0000000..6c394fb --- /dev/null +++ b/docs/users_guide_src/examples.tex @@ -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_src/flowControl.tex b/docs/users_guide_src/flowControl.tex new file mode 100755 index 0000000..75a5845 --- /dev/null +++ b/docs/users_guide_src/flowControl.tex @@ -0,0 +1,414 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Flow Control} +\label{flowControl} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#for ... \#end for} +\label{flowControl.for} + +Syntax: +\begin{verbatim} +#for $var in EXPR +#end for +\end{verbatim} + + +The \code{\#for} directive iterates through a sequence. The syntax is the same +as Python, but remember the \code{\$} before variables. + +Here's a simple client listing: +\begin{verbatim} +<TABLE> +#for $client in $service.clients +<TR> +<TD>$client.surname, $client.firstname</TD> +<TD><A HREF="mailto:$client.email" >$client.email</A></TD> +</TR> +#end for +</TABLE> +\end{verbatim} + +Here's how to loop through the keys and values of a dictionary: +\begin{verbatim} +<PRE> +#for $key, $value in $dict.items() +$key: $value +#end for +</PRE> +\end{verbatim} + +Here's how to create list of numbers separated by hyphens. This ``\#end for'' +tag shares the last line to avoid introducing a newline character after each +hyphen. +\begin{verbatim} +#for $i in range(15) +$i - #end for +\end{verbatim} + +If the location of the \code{\#end for} offends your sense of indentational +propriety, you can do this instead: +\begin{verbatim} +#for $i in $range(15) +$i - #slurp +#end for +\end{verbatim} + +The previous two examples will put an extra hyphen after last number. Here's +how to get around that problem, using the \code{\#set} directive, which will be +dealt with in more detail below. +\begin{verbatim} +#set $sep = '' +#for $name in $names +$sep$name +#set $sep = ', ' +#end for +\end{verbatim} + +Although to just put a separator between strings, you don't need a for loop: +\begin{verbatim} +#echo ', '.join($names) +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#repeat ... \#end repeat} +\label{flowControl.repeat} + +Syntax: +\begin{verbatim} +#repeat EXPR +#end repeat +\end{verbatim} + + +Do something a certain number of times. +The argument may be any numeric expression. +If it's zero or negative, the loop will execute zero times. +\begin{verbatim} +#repeat $times + 3 +She loves me, she loves me not. +#repeat +She loves me. +\end{verbatim} + + +Inside the loop, there's no way to tell which iteration you're on. If you +need a counter variable, use \code{\#for} instead with Python's \code{range} +function. Since Python's ranges are base 0 by default, there are two ways +to start counting at 1. Say we want to count from 1 to 5, and that +\code{\$count} is 5. +\begin{verbatim} +#for $i in $range($count) +#set $step = $i + 1 +$step. Counting from 1 to $count. +#end for + + +#for $i in $range(1, $count + 1) +$i. Counting from 1 to $count. +#end for +\end{verbatim} + + +A previous implementation used a local variable \code{\$i} as the repeat +counter. However, this prevented instances of \code{\#repeat} from +being nested. The current implementation does not have this problem as it +uses a new local variable for every instance of \code{\#repeat}. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#while ... \#end while} +\label{flowControl.while} + +Syntax: +\begin{verbatim} +#while EXPR +#end while +\end{verbatim} + + +\code{\#while} is the same as Python's \code{while} statement. It may be +followed by any boolean expression: +\begin{verbatim} +#while $someCondition('arg1', $arg2) +The condition is true. +#end while +\end{verbatim} + +Be careful not to create an infinite loop. \code{\#while 1} will loop until +the computer runs out of memory. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#if ... \#else if ... \#else ... \#end if} +\label{flowControl.if} + +Syntax: +\begin{verbatim} +#if EXPR +#else if EXPR +#elif EXPR +#else +#end if +\end{verbatim} + + +The \code{\#if} directive and its kin are used to display a portion of text +conditionally. \code{\#if} and \code{\#else if} should be followed by a +true/false expression, while \code{\#else} should not. Any valid Python +expression is allowed. As in Python, the expression is true unless it evaluates +to 0, '', None, an empty list, or an empty dictionary. In deference to Python, +\code{\#elif} is accepted as a synonym for \code{\#else if}. + +Here are some examples: +\begin{verbatim} +#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} + +\begin{verbatim} +#if $testItem($item) +The item $item.name is OK. +#end if +\end{verbatim} + +Here's an example that combines an \code{\#if} tag with a \code{\#for} tag. +\begin{verbatim} +#if $people +<table> +<tr> +<th>Name</th> +<th>Address</th> +<th>Phone</th> +</tr> +#for $p in $people +<tr> +<td>$p.name</td> +<td>$p.address</td> +<td>$p.phone</td> +</tr> +#end for +</table> +#else +<p> Sorry, the search did not find any people. </p> +#end if +\end{verbatim} + +See section \ref{output.oneLineIf} for the one-line \code{\#if} directive, +which is equivalent to Perl's and C's \code{?:} operator. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#unless ... \#end unless} +\label{flowControl.unless} + +Syntax: +\begin{verbatim} +#unless EXPR +#end unless +\end{verbatim} + + +\code{\#unless} is the opposite of \code{\#if}: the text is executed if the +condition is {\bf false}. Sometimes this is more convenient. +\code{\#unless EXPR} is equivalent to \code{\#if not (EXPR)}. + +\begin{verbatim} +#unless $alive +This parrot is no more! He has ceased to be! +'E's expired and gone to meet 'is maker! ... +THIS IS AN EX-PARROT!! +#end unless +\end{verbatim} + +You cannot use \code{\#else if} or \code{\#else} inside an \code{\#unless} +construct. If you need those, use \code{\#if} instead. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#break and \#continue} +\label{flowControl.break} + +Syntax: +\begin{verbatim} +#break +#continue +\end{verbatim} + + +These directives are used as in Python. \code{\#break} will +exit a \code{\#for} loop prematurely, while \code{\#continue} will immediately +jump to the next iteration in the \code{\#for} loop. + +In this example the output list will not contain ``10 - ''. +\begin{verbatim} +#for $i in range(15) +#if $i == 10 + #continue +#end if +$i - #slurp +#end for +\end{verbatim} + +In this example the loop will exit if it finds a name that equals 'Joe': +\begin{verbatim} +#for $name in $names +#if $name == 'Joe' + #break +#end if +$name - #slurp +#end for +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#pass} +\label{flowControl.pass} + +Syntax: +\begin{verbatim} +#pass +\end{verbatim} + + +The \code{\#pass} directive is identical to Python \code{pass} statement: it +does nothing. It can be used when a statement is required syntactically but the +program requires no action. + +The following example does nothing if only \$A is true +\begin{verbatim} +#if $A and $B + do something +#elif $A + #pass +#elif $B + do something +#else + do something +#end if +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#stop} +\label{flowControl.stop} + +Syntax: +\begin{verbatim} +#stop +\end{verbatim} + + +The \code{\#stop} directive is used to stop processing of a template at a +certain point. The output will show {\em only} what has been processed up to +that point. + +When \code{\#stop} is called inside an \code{\#include} it skips the rest of +the included code and continues on from after the \code{\#include} directive. +stop the processing of the included code. Likewise, when \code{\#stop} is +called inside a \code{\#def} or \code{\#block}, it stops only the \code{\#def} +or \code{\#block}. + +\begin{verbatim} +A cat +#if 1 + sat on a mat + #stop + watching a rat +#end if +in a flat. +\end{verbatim} + +will print +\begin{verbatim} +A cat + sat on a mat +\end{verbatim} + +And +\begin{verbatim} +A cat +#block action + sat on a mat + #stop + watching a rat +#end block +in a flat. +\end{verbatim} + +will print + +\begin{verbatim} +A cat + sat on a mat +in a flat. +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#return} +\label{flowControl.return} + +Syntax: +\begin{verbatim} +#return +\end{verbatim} + + +This is used as in Python. \code{\#return} will exit the current method with a +default return value of \code{None} or the value specified. It may be used +only inside a \code{\#def} or a \code{\#block}. + +Note that \code{\#return} is different from the \code{\#stop} directive, +which returns the sum of all text output from the method in which it is called. +The following examples illustrate this point: + +\begin{verbatim} +1 +$test[1] +3 +#def test +1.5 +#if 1 +#return '123' +#else +99999 +#end if +#end def +\end{verbatim} + +will produce +\begin{verbatim} +1 +2 +3 +\end{verbatim} + +while +\begin{verbatim} +1 +$test +3 +#def test +1.5 +#if 1 +#stop +#else +99999 +#end if +#end def +\end{verbatim} + +will produce +\begin{verbatim} +1 +1.5 +3 +\end{verbatim} + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_src/gettingStarted.tex b/docs/users_guide_src/gettingStarted.tex new file mode 100755 index 0000000..69a3136 --- /dev/null +++ b/docs/users_guide_src/gettingStarted.tex @@ -0,0 +1,266 @@ +\section{Getting Started} +\label{gettingStarted} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Requirements} +\label{gettingStarted.requirements} + +Cheetah requires Python release 2.0 or greater, and has been tested with Python +2.0, 2.1 and 2.2. It is known to run on Linux, Windows NT/98/XP, FreeBSD and +Solaris, and should run anywhere Python runs. + +99\% of Cheetah is written in Python. There is one small C module +(\code{\_namemapper.so}) for speed, but Cheetah automatically falls back to a +Python equivalent (\code{NameMapper.py}) if the C module is not available. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Installation} +\label{gettingStarted.install} + +To install Cheetah in your system-wide Python library: +\begin{enumerate} +\item Login as a user with privileges to install system-wide Python packages. + On POSIX systems (AIX, Solaris, Linux, IRIX, etc.), the command is normally + 'su root'. On non-POSIX systems such as Windows NT, login as an + administrator. + +\item Run \code{python setup.py install} at the command prompt. + +\item The setup program will install the wrapper script {\bf cheetah} to + wherever it usually puts Python binaries ("/usr/bin/", "bin/" in the + Python install directory, etc.) +\end{enumerate} + +Cheetah's installation is managed by Python's Distribution Utilities +('distutils'). There are many options for customization. Type \code{``python + setup.py help''} for more information. + +To install Cheetah in an alternate location -- someplace outside Python's +\code{site-packages/} directory, use one of these options: +\begin{verbatim} + python setup.py install --home /home/tavis + python setup.py install --install-lib /home/tavis/lib/python +\end{verbatim} +Either way installs to /home/tavis/lib/python/Cheetah/ . Of course, +/home/tavis/lib/python must be in your Python path in order for Python to +find Cheetah. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Files} +\label{gettingstarted.files} + +If you do the systemwide install, all Cheetah modules are installed in the +{\bf site-packages/Cheetah/} subdirectory of your standard library +directory; e.g., /opt/Python2.2/lib/python2.2/site-packages/Cheetah. + +Two commands are installed in Python's \code{bin/} directory or a system +bin directory: \code{cheetah} (section \ref{gettingStarted.cheetah}) and +\code{cheetah-compile} (section \ref{howWorks.cheetah-compile}). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Uninstalling} +\label{gettingstarted.uninstalling} + +% @@MO: When 'python setup.py uninstall' is implemented, mention it here. + +To uninstall Cheetah, merely delete the site-packages/Cheetah/ directory. +Then delete the ``cheetah'' and ``cheetah-compile'' commands from whichever +bin/ directory they were put in. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{The 'cheetah' command} +\label{gettingStarted.cheetah} + +Cheetah comes with a utility \code{cheetah} that provides a command-line +interface to various housekeeping tasks. The command's first argument is +the name of the task. The following commands are currently supported: + +\begin{verbatim} +cheetah compile [options] [FILES ...] : Compile template definitions +cheetah fill [options] [FILES ...] : Fill template definitions +cheetah help : Print this help message +cheetah options : Print options help message +cheetah test : Run Cheetah's regression tests +cheetah version : Print Cheetah version number +\end{verbatim} + +You only have to type the first letter of the command: +\code{cheetah c} is the same as \code{cheetah compile}. + +The test suite is described in the next section. The \code{compile} +command will be described in section \ref{howWorks.cheetah-compile}, +and the \code{fill} command in section \ref{howWorks.cheetah-fill}. + +The depreciated \code{cheetah-compile} program does the same thing as +\code{cheetah compile}. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Testing your installation} +\label{gettingStarted.test} + +After installing Cheetah, you can run its self-test routine to verify it's +working properly on your system. Change directory to any directory you have +write permission in (the tests write temporary files). Do not run the tests +in the directory you installed Cheetah from, or you'll get unnecessary errors. +Type the following at the command prompt: +\begin{verbatim} +cheetah test +\end{verbatim} + +The tests will run for about three minutes and print a success/failure +message. If the tests pass, start Python in interactive mode and try the +example in the next section. + +Certain test failures are insignificant: +\begin{description} +\item{{\bf AssertionError: Template output mismatch: Expected Output = 0(end) +Actual Output = False(end)}} Python 2.3 changed the string representation of +booleans, and the tests haven't yet been updated to reflect this. +\item{{\bf AssertionError: subcommand exit status 127}} Certain tests run +``cheetah'' as a subcommand. The failure may mean the command wasn't found +in your system path. (What happens if you run ``cheetah'' on the command line?) +The failure also happens on some Windows systems for unknown reasons. This +failure has never been observed outside the test suite. Long term, we plan to +rewrite the tests to do a function call rather than a subcommand, which will +also make the tests run significantly faster. +\item{{\bf ImportError: No module named SampleBaseClass}} The test tried to +write a temporary module in the current directory and \code{import} it. Reread +the first paragraph in this section about the current directory. +\item{{\bf ImportError: No module named tmp}} May be the same problem as +SampleBaseClass; let us know if changing the current directory doesn't work. +\end{description} + +If any other tests fail, please send a message to the e-mail list with a copy +of the test output and the following details about your installation: + +\begin{enumerate} +\item your version of Cheetah +\item your version of Python +\item your operating system +\item whether you have changed anything in the Cheetah installation +\end{enumerate} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Quickstart tutorial} +\label{gettingStarted.tutorial} + +This tutorial briefly introduces how to use Cheetah from the Python prompt. +The following chapters will discuss other ways to use templates and more of +Cheetah's features. + +The core of Cheetah is the \code{Template} class in the \code{Cheetah.Template} +module. The following example shows how to use the \code{Template} class in an +interactive Python session. \code{t} is the Template instance. Lines prefixed +with \code{>>>} and \code{...} are user input. The remaining lines are Python +output. + +\begin{verbatim} +>>> from Cheetah.Template import Template +>>> templateDef = """ +... <HTML> +... <HEAD><TITLE>$title</TITLE></HEAD> +... <BODY> +... $contents +... ## this is a single-line Cheetah comment and won't appear in the output +... #* This is a multi-line comment and won't appear in the output +... blah, blah, blah +... *# +... </BODY> +... </HTML>""" +>>> nameSpace = {'title': 'Hello World Example', 'contents': 'Hello World!'} +>>> t = Template(templateDef, searchList=[nameSpace]) +>>> print t + +<HTML> +<HEAD><TITLE>Hello World Example</TITLE></HEAD> +<BODY> +Hello World! +</BODY> +</HTML> +>>> print t # print it as many times as you want + [ ... same output as above ... ] +>>> nameSpace['title'] = 'Example #2' +>>> nameSpace['contents'] = 'Hiya Planet Earth!' +>>> print t # Now with different plug-in values. +<HTML> +<HEAD><TITLE>Example #2</TITLE></HEAD> +<BODY> +Hiya Planet Earth! +</BODY> +</HTML> + +\end{verbatim} + +Since Cheetah is extremely flexible, you can achieve the same result this +way: + +\begin{verbatim} +>>> t2 = Template(templateDef) +>>> t2.title = 'Hello World Example!' +>>> t2.contents = 'Hello World' +>>> print t2 + [ ... same output as the first example above ... ] +>>> t2.title = 'Example #2' +>>> t2.contents = 'Hello World!' +>>> print t2 + [ ... same as Example #2 above ... ] +\end{verbatim} + +Or this way: + +\begin{verbatim} +>>> class Template3(Template): +>>> title = 'Hello World Example!' +>>> contents = 'Hello World!' +>>> t3 = Template3(templateDef) +>>> print t3 + [ ... you get the picture ... ] +\end{verbatim} + +The template definition can also come from a file instead of a string, +as we will see in section \ref{howWorks.constructing}. + +The above is all fine for short templates, but for long templates or +for an application that depends on many templates in a hierarchy, it's +easier to store the templates in separate *.tmpl files and use the +{\bf cheetah compile} program to convert them into Python classes in +their own modules. This will be covered in section +\ref{howWorks.cheetah-compile}. + +As an appetizer, we'll just briefly mention that you can store constant values +{\em inside} the template definition, and they will be converted to attributes +in the generated class. You can also create methods the same way. +You can even use inheritance to arrange your templates in a hierarchy, +with more specific templates overriding certain parts of more general +templates (e.g., a "page" template overriding a sidebar in a "section" +template). + +For the minimalists out there, here's a template definition, +instantiation and filling all in one Python statement: + +\begin{verbatim} +>>> print Template("Templates are pretty useless without placeholders.") +Templates are pretty useless without placeholders. +\end{verbatim} + +You use a precompiled template the same way, except you don't provide +a template definition since it was already established: + +\begin{verbatim} +from MyPrecompiledTemplate import MyPrecompiledTemplate +t = MyPrecompiledTemplate() +t.name = "Fred Flintstone" +t.city = "Bedrock City" +print t +\end{verbatim} + + +% Local Variables: +% TeX-master: "users_guide" +% End: + diff --git a/docs/users_guide_src/glossary.tex b/docs/users_guide_src/glossary.tex new file mode 100644 index 0000000..4ee2d9b --- /dev/null +++ b/docs/users_guide_src/glossary.tex @@ -0,0 +1,96 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Vocabulary} +\label{glossary} +\label{vocabulary} + +{\bf Template} is an informal term meaning a template definition, a +template instance or a template class. A {\bf template definition} is what +the human {\bf template maintainer} writes: a string consisting of text, +placeholders and directives. {\bf Placeholders} are variables that will be +looked up when the template is filled. {\bf Directives} are commands to be +executed when the template is filled, or instructions to the Cheetah compiler. +The conventional suffix for a file containing a template definition is +{\bf .tmpl}. + +There are two things you can do with a template: compile it or fill it. +{\bf Filling} is the reason you have a template in the first place: +to get a finished string out of it. Compiling is a necessary prerequisite: the +{\bf Cheetah compiler} takes a template definition and produces Python code +to create the finished string. Cheetah provides several ways to compile +and fill templates, either as one step or two. + +Cheetah's compiler produces a subclass of \code{Cheetah.Template} +specific to that template definition; this is called the {\bf generated +class}. A {\bf template instance} is an instance of a generated class. + +If the user calls the \code{Template} constructor directly (rather than a +subclass constructor), s/he will get what appears to be an instance of +\code{Template} but is actually a subclass created on-the-fly. + +The user can make the subclass explicit by using the ``cheetah compile'' +command to write the template class to a Python module. Such a module is +called a {\bf .py template module}. + +The {\bf Template Definition Language} -- or the ``Cheetah language'' for short +-- is the syntax rules governing placeholders and directives. These are +discussed in sections \ref{language} and following in this Guide. + +To fill a template, you call its {\bf main method}. This is normally +\code{.respond()}, but it may be something else, and you can use the +\code{\#implements} directive to choose the method name. (Section +\ref{inheritanceEtc.implements}. + +A {\bf template-servlet} is a .py template module in a Webware servlet +directory. Such templates can be filled directly through the web by requesting +the URL. ``Template-servlet'' can also refer to the instance being filled by +a particular web request. If a Webware servlet that is not a +template-servlet invokes a template, that template is not a template-servlet +either. + +A {\bf placeholder tag} is the substring in the template +definition that is the placeholder, including the start and end delimeters (if +there is an end delimeter). The {\bf placeholder name} is the same but without +the delimeters. + +Placeholders consist of one or more {\bf identifiers} separated by periods +(e.g., \code{a.b}). Each identifier must follow the same rules as Python +identifiers; that is, a letter or underscore followed by one or more letters, +digits or underscores. (This is the regular expression +\verb+[A-Za-z_][A-Za-z0-9_]*+.) + +The first (or only) identifier of a placeholder name represents a {\bf +variable} to be looked up. Cheetah looks up variables in various {\bf +namespaces}: the searchList, local variables, and certain other places. The +searchList is a list of objects ({\bf containers}) with attributes +and/or keys: each container is a namespace. Every template instance has +exactly one searchList. Identifiers after the first are looked up only in +the parent object. The final value after all lookups have been performed is +the {\bf placeholder value}. + +Placeholders may occur in three positions: top-level, expression and LVALUE. +{\bf Top-level} placeholders are those in ordinary text (``top-level text''). +{\bf Expression} placeholders are those in Python expressions. +{\bf LVALUE} placeholders are those naming a variable to receive a value. +(LVALUE is computerese for ``the left side of the equal sign''.) Section +\ref{language.placeholders.positions} explains the differences between these +three positions. + +The routine that does the placeholder lookups is called the {\bf NameMapper}. +Cheetah's NameMapper supports universal dotted notation and autocalling. +{\bf Universal dotted notation} means that keys may be written as if they were +attributes: \code{a.b} instead of \code{a['b']}. {\bf Autocalling} means that +if any identifier's value is found to be a function or method, Cheetah will +call it without arguments if there is no \verb+()+ following. More about the +NameMapper is in section \ref{language.namemapper}. + +Some directives are multi-line, meaning they have a matching {\bf \#end} tag. +The lines of text between the start and end tags is the {\bf body} of the +directive. Arguments on the same line as the start tag, in contrast, are +considered part of the directive tag. More details are in section +\ref{language.directives.syntax} (Directive Syntax Rules). + +% Local Variables: +% TeX-master: "users_guide" +% End: + +% # vim: sw=4 ts=4 expandtab diff --git a/docs/users_guide_src/howItWorks.tex b/docs/users_guide_src/howItWorks.tex new file mode 100755 index 0000000..4efa22f --- /dev/null +++ b/docs/users_guide_src/howItWorks.tex @@ -0,0 +1,420 @@ +\section{How Cheetah Works} +\label{howWorks} + +As mentioned before, you can do two things with templates: compile them and +fill them. (Actually you can query them too, to see their attributes and +method values.) Using templates in a Python program was shown in section +\ref{gettingStarted.tutorial} (Quickstart tutorial). Here we'll focus on +compiling and filling templates from the shell command line, and how to make +.py template modules. The compiling information here is also important for +template-servlets, which will be otherwise covered in chapter \ref{webware} +(Webware). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Constructing Template Objects} +\label{howWorks.templateClass} +\label{howWorks.constructing} + +The heart of Cheetah is the \code{Template} class in the +\code{Cheetah.Template} module. You can use it directly if you have a +template definition in hand, or indirectly through a precompiled template, +which is a subclass. The constructor accepts the following keyword +arguments. (If you're a beginner, learn the first three arguments now; +the others are much less frequent.) + +\begin{description} +\item{{\bf source}} + The template definition as a string. You may omit the \code{source=} + prefix {\em if it's the first argument}, as in all the examples below. + The source can be a string literal in your module, or perhaps a string + you read from a database or other data structure. +\item{{\bf file}} + A filename or file object containing the template definition. + A filename must be a string, and a file object must be open for reading. + By convention, template definition files have the extension + {\bf .tmpl}. +\item{{\bf searchList}} + A list of objects to add to the searchList. The attributes/keys of these + objects will be consulted for \code{\$placeholder} lookup. +\item{{\bf filter}} + A class that will format every \code{\$placeholder} value. You may + specify a class object or string. If a class object, + it must be a subclass of \code{Cheetah.Filters.Filter}. If a string, it + must be the name of one of the filters in filtersLib module (see next + item). + (You may also use the \code{\#filter} directive (section + \ref{output.filter}) to switch filters at runtime.) +\item{{\bf filtersLib}} + A module containing the filters Cheetah should look up by name. The + default is \code{Cheetah.Filters}. All classes in this module that are + subclasses of \code{Cheetah.Filters.Filter} are considered filters. +\item{{\bf errorCatcher}} + A class to handle \code{\$placeholder} errors. You may + specify a class object or string. If a class object, + it must be a subclass of \code{Cheetah.ErrorCatchers.ErrorCatcher}. + If a string, it must be the name of one of the error catchers in + \code{Cheetah.ErrorCatchers}. This is similar to the + \code{\#errorCatcher} directive + (section \ref{errorHandling.errorCatcher}). +\item{{\bf compilerSettings}} + A dictionary (or dictionary hierarchy) of settings that change Cheetah's + behavior. Not yet documented. +\end{description} + +To use \code{Template} directly, you {\em must} specify either \code{source} +or \code{file}, but not both. To use a precompiled template, you +{\em must not} specify either one, because the template definition is already +built into the class. The other arguments, however, may be used in either case. +Here are typical ways to create a template instance: +\begin{description} +\item{\code{t = Template("The king is a \$placeholder1.")}} + \\ Pass the template definition as a string. +\item{\code{t = Template(file="fink.tmpl")}} + \\ Read the template definition from a file named "fink.tmpl". +\item{\code{t = Template(file=f)}} + \\ Read the template definition from file-like object 'f'. +\item{\code{t = Template("The king is a \$placeholder1.", searchList=[dict, obj])}} + \\ Pass the template definition as a string. Also pass two namespaces for + the searchList: a dictionary 'dict' and an instance 'obj'. +\item{\code{t = Template(file="fink.txt", searchList=[dict, obj])}} + \\ Same, but pass a filename instead of a string. +\item{\code{t = Template(file=f, searchList=[dict, obj])}} + \\ Same with a file object. +\end{description} + +If you use \code{Template} directly, the template definition will be compiled +the first time it's filled. Compilation creates a template-specific class +called the {\bf generated class}, which is a subclass of \code{Template}. It +then dynamically switches the instance so it's now an instance of this class. +Don't worry if you don't understand this; it works. + +% By convention, you give a file containing a template definition the extension +% {\bf .tmpl}. + +When you precompile a template using the ``cheetah compile'' command, it +writes the generated class to a file. Actually, what it writes is the source +code for a Python module that contains the generated class. Again, the +generated class is a subclass of \code{Template}. We call the generated +module a {\bf .py template module}. Thus, if you always use +precompiled templates (as many people do), you can view Cheetah as a +convenient front-end for writing certain kinds of Python modules, the way +you might use a graphical dialog builder to make a dialog module. + +Precompiled templates provide a slight performance boost because the +compilation happens only once rather than every time it's instantiated. +Also, once you import the .py template module and allow Python to create a +.pyc or .pyo file, you skip the Python compiler too. The speed advantage +of all this is negligable, but it may make a difference in programs that +use templates many times a second. + +\code{Template} subclasses Webware's \code{Servlet} class when available, +so the generated class can be used as a Webware servlet. This is practical +only with precompiled templates. + +To fill a template, you call its {\bf main method}. This is normally +\code{.respond()}, but under certain circumstances it's \code{.writeBody()} or +a user-defined name. (Section \ref{inheritanceEtc.implements} explains why +the method name is not always the same.) However, \code{.\/\_\_str\_\_()} is +always an alias for the main method, so you can always use +\code{print\ myTemplateInstance} or \code{str(myTempateInstance)} to fill it. +You can also call any \code{\#def} or \code{\#block} method and it will fill +just that portion of the template, although this feature is not often used. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{``cheetah compile'' and .py template modules} +\label{howWorks.cheetah-compile} + +To create a .py template module, do either of these: + +\begin{verbatim} +cheetah compile [options] [FILES ...] +cheetah c [options] [FILES ...] +\end{verbatim} + +The following options are supported: +\begin{verbatim} + --idir DIR, --odir DIR : input/output directories (default: current dir) + --iext EXT, --oext EXT : input/output filename extensions + (default input: tmpl, default output: py) + -R : recurse subdirectories looking for input files + --debug : print lots of diagnostic output to standard error + --flat : no destination subdirectories + --nobackup : don't make backups + --stdout, -p : output to standard output (pipe) +\end{verbatim} + +{\em Note:} If Cheetah can't find your input files, or if it puts output files +in the wrong place, use the \code{--debug} option to see what Cheetah thinks +of your command line. + +The most basic usage is: +\begin{verbatim} +cheetah compile a.tmpl : writes a.py +cheetah compile a.tmpl b.tmpl : writes a.py and b.py +\end{verbatim} + +Cheetah will automatically add the default input extension (.tmpl) if the +file is not found. So the following two examples are the same as above +(provided files ``a'' and ``b'' don't exist): +\begin{verbatim} +cheetah compile a : writes a.py (from a.tmpl) +cheetah compile a b : writes a.py and b.py +\end{verbatim} + +You can override the default input extension and output extension +(\code{py}) using \code{--iext} and \code{--oext}, although there's +little reason to do so. Cheetah assumes the extension has a leading dot +(.) even if you don't specify it. + +Use the \code{-R} option to recurse subdirectories: +\begin{verbatim} +cheetah compile dir1 : error, file is a directory +cheetah compile -R dir1 : look in `dir1' for files to compile +cheetah compile : error, no file specified +cheetah compile -R : look in current directory for files + to compile +cheetah compile -R a b dir1 : compile files and recurse +\end{verbatim} +When recursing, only regular files that end in the input extension (.tmpl) are +considered source files. All other filenames are ignored. + +The options \code{--idir} and \code{--odir} allow you to specify that +the source (and/or destination) paths are relative to a certain directory +rather than to the current directory. This is useful if you keep your +*.tmpl and *.py files in separate directory hierarchies. After editing a +source file, just run one of these (or put the command in a script or +Makefile): +\begin{verbatim} +cheetah compile --odir /var/webware a.tmpl +cheetah compile -R --odir /var/webware +cheetah c --odir /var/webware sub/a.tmpl + : writes /var/webware/sub/a.py +\end{verbatim} + +``cheetah compile'' overwrites any existing \code{.py} file it finds, after +backing it up to FILENAME.py\_bak (unless you specify \code{--nobackup}). For +this reason, you should make changes to the \code{.tmpl} version of the +template rather than to the \code{.py} version. + +For the same reason, if your template requires custom Python methods or +other Python code, don't put it in the \code{FILENAME.py} file. Instead, put +it in a separate base class and use the \code{\#extends} directive to +inherit from it. + +Because FILENAME will be used as a class and module name, it must be a valid +Python identifier. For instance, \code{cheetah compile spam-eggs.tmpl} is +illegal because of the hyphen ("-"). This is sometimes inconvenient when +converting a site of HTML files into Webware servlets. Fortunately, the +{\em directory} it's in does not have to be an identifier. ({\em Hint:} for +date-specific files, try converting 2002/04/12.html to 2002/04/12/index.tmpl. +This also gives you a directory to store images or supplemental files.) + +Occasionally you may want output files put directly into the output directory +(or current directory), rather than into a subdirectory parallel to the input +file. The \code{--flat} option does this. Note that this introduces the +possibility that several input files might map to one output file. Cheetah +checks for output file collisions before writing any files, and aborts if there +are any collisions. +\begin{verbatim} +cheetah c sub/a.py : writes sub/a.py +cheetah c --flat sub/a.py : writes a.py +cheetah c --odir DEST sub/a.tmpl + : writes DEST/sub/a.py +cheetah c --flat --odir DEST sub/a.tmpl + : writes DEST/a.py +cheetah c --idir /home/henry sub/rollins.tmpl + : writes sub/rollins.py +cheetah c --flat --idir /home/henry sub/rollins.tmpl + : writes rollins.py +cheetah c --idir /home/henry --odir /home/henry sub/rollins.tmpl + : writes /home/henry/sub/rollins.py +cheetah c --flat --idir /home/henry --odir /home/henry sub/rollins.tmpl + : writes /home/henry/rollins.py +\end{verbatim} + +Whenever ``cheetah compile'' has to create an output directory or subdirectory, it +also creates an \_\_init\_\_.py file in it. This file is necessary +in order to make Python treat the directory as a Python package. + +One of the advantages of .py template modules is that you don't lose any +flexibility. The generated class contains all \code{\#attr} values and +\code{\#def}/\code{\#block} values as ordinary attributes and methods, so you +can read the values individually from other Python tools for any kind of custom +processing you want. For instance, you can extract the titles of all +your templates into a database, or find all the servlets with a certain +\code{\$author} value. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{``cheetah fill''} +\label{howWorks.cheetah-fill} + +You can compile and fill a large number of template definitions from the +command line in one step using \code{cheetah fill}. This compiles the template +in memory; it does {\em not} save the .py template module to disk. Instead it +writes a finished output file, which has the extension \code{.html} by default. +All the options to \code{cheetah compile} work the same way here, and there are +also a couple additional options: +\begin{verbatim} + --env : put the environment in the searchList + --pickle FILE : unpickle FILE and put that object in the searchList +\end{verbatim} + +Because you can't provide a searchList on the command line, the +templates must either contain or inherit all the variables it needs, +or use the \code{--env} and \code{--pickle} options to +provide additional variables. + +Examples: +\begin{verbatim} +cheetah fill a.tmpl : writes a.html +cheetah fill a.tmpl b.tmpl : writes a.html and b.html +cheetah f --oext txt a : writes a.txt (from a.tmpl) +\end{verbatim} + +Using \code{--env} may have security or reliability implications because the +environment normally contains lots of variables you inherited rather than +defining yourself. If any of these variables override any of yours (say a +\code{\#def}), you will get incorrect output, may reveal private information, +and may get an exception due to the variable being an unexpected type +(environmental variables are always strings). Your calling program may wish +to clear out the environment before setting environmental variables for the +template. + +There are two other differences between ``cheetah compile'' and ``cheetah fill''. +Cheetah doesn't create \_\_init\_\_.py files when creating directories in +fill mode. Also, the source filenames don't have to be identifiers. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Some trivia about .py template modules} +\label{howWorks.pyTrivia} + +We won't look inside .py template modules in this Guide except to note that +they are very different from template definitions. The following template +definition fragment: + +\begin{verbatim} +The number is $Test.unittest.main. +\end{verbatim} + +compiles to this: + +\begin{verbatim} +write("The number is ") +write(filter(VFN(VFS(SL,"Test.unittest",1),"main",0) +write(".") +\end{verbatim} + +The Cheetah Developers' Guide looks at .py template +modules in depth, and shows what the various directives compile to. +But you are welcome to take a peek at some .py template modules yourself +if you're curious about what Cheetah does under the hood. It's all +regular Python code: writing strings and function calls to a file-like +object. + +Looking at a .py template module may also help you see why something +doesn't work, by seeing what Cheetah thought you meant. It also helps +discourage you from modifying the .py file yourself, because who wants to +keep all those function calls and arguments straight? Let the computer +do the drudgery work. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Running a .py template module as a standalone program} +\label{howWorks.standalone} + +In addition to importing your .py template module file into a Python +script or using it as a Webware servlet, you can also run it from the +command line as a standalone program. The program will print the filled +template on standard output. This is useful while debugging the template, +and for producing formatted output in shell scripts. + +When running the template as a program, you cannot provide a searchList or +set \code{self.} attributes in the normal way, so you must take +alternative measures to ensure that every placeholder has a value. +Otherwise, you will get the usual \code{NameMapper.NotFound} exception at +the first missing value. You can either set default values in the template +itself (via the \code{\#attr} or \code{\#def} directives) or in a Python +superclass, or use the \code{--env} or \code{--pickle} command-line options, +which work just like their ``cheetah fill'' counterparts. + +Run \code{python FILENAME.py --help} to see all the command-line +options your .py template module accepts. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Object-Oriented Documents} +\label{howWorks.objoriented} + +Because Cheetah documents are actually class definitions, templates may inherit +from one another in a natural way, using regular Python semantics. For +instance, consider this template, FrogBase.tmpl: + +\begin{verbatim} +#def title +This document has not defined its title +#end def +#def htTitle +$title +#end def +<HTML><HEAD> +<TITLE>$title</TITLE> +</HEAD><BODY> +<H1>$htTitle</H1> +$body +</BODY></HTML> +\end{verbatim} + +And its subclassed document, Frog1.tmpl: +\begin{verbatim} +#from FrogBase import FrogBase +#extends FrogBase +#def title +The Frog Page +#end def +#def htTitle +The <IMG SRC="Frog.png"> page +#end def +#def body +... lots of info about frogs ... +#end def +\end{verbatim} + +This is a classic use of inheritance. The parent ``template'' is simply an +abstract superclass. Each document specializes the output of its parent. + For instance, here the parent defines +\code{\$htTitle} so that by default it's identical to whatever the +\code{\$title} is, but it can also be customized. + +In many other templating systems, you'd have to use case statements or +if-elseif blocks of some sort, repeated in many different sections of code. + +While we show another Cheetah document inheriting from this parent, a Python +class can inherit from it just as easily. This Python class could define its +programmatically-driven value for \code{\$body} and \code{\$title}, simply by +defining body() and title() methods that return a string. (Actually they +can return anything, but we'll get into that later.) + +\begin{verbatim} +from FrogBase import FrogBase +class Frog2(FrogBase): + def title(self): + return "Frog 2 Page" + # We don't override .htTitle, so it defaults to "Frog 2 Page" too. + def body(self): + return " ... more info about frogs ..." +\end{verbatim} + +Similarly, the Cheetah document can inherit from an arbitrary class. That's +how Cheetah makes templates usable as Webware servlets, by subclassing +\code{Servlet}. This technique should be possible for non-Webware systems +too. + +({\em Note:}\ \code{FrogBase.tmpl} could be improved by using the +\code{\#block} directive, section \ref{inheritanceEtc.block}.) + +% Local Variables: +% TeX-master: "users_guide" +% End: + diff --git a/docs/users_guide_src/inheritanceEtc.tex b/docs/users_guide_src/inheritanceEtc.tex new file mode 100755 index 0000000..019b042 --- /dev/null +++ b/docs/users_guide_src/inheritanceEtc.tex @@ -0,0 +1,492 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Import, Inheritance, Declaration and Assignment} +\label{inheritanceEtc} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#import and \#from directives} +\label{inheritanceEtc.import} + +Syntax: +\begin{verbatim} +#import MODULE_OR_OBJECT [as NAME] [, ...] +#from MODULE import MODULE_OR_OBJECT [as NAME] [, ...] +\end{verbatim} + + +The \code{\#import} and \code{\#from} directives are used to make external +Python modules or objects available to placeholders. The syntax is identical +to the import syntax in Python. Imported modules are visible globally to all +methods in the generated Python class. + +\begin{verbatim} +#import math +#import math as mathModule +#from math import sin, cos +#from math import sin as _sin +#import random, re +#from mx import DateTime # ## Part of Egenix's mx package. +\end{verbatim} + +After the above imports, \code{\$math}, \code{\$mathModule}, +\code{\$sin}, \code{\$cos} and \code{\$\_sin}, \code{\$random}, \code{\$re} +and \code{\$DateTime} may be used in \code{\$placeholders} and expressions. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#extends} +\label{inheritanceEtc.extends} + +Syntax: +\begin{verbatim} +#extends CLASS +\end{verbatim} + + +All templates are subclasses of \code{Cheetah.Template.Template}. However, +it's possible for a template to subclass another template or a pure Python +class. This is where \code{\#extends} steps in: it +specifies the parent class. It's equivalent to PSP's \code{``@page extends=''} +directive. + +Cheetah imports the class mentioned in an \code{\#extends} directive +automatically if you haven't imported it yet. The implicit importing works +like this: + +\begin{verbatim} +#extends Superclass +## Implicitly does '#from Superclass import Superclass'. + +#extends Cheetah.Templates.SkeletonPage +## Implicitly does '#from Cheetah.Templates.SkeletonPage import SkeletonPage'. +\end{verbatim} + +If your superclass is in an unusual location or in a module named +differently than the class, you must import it explicitly. There is no +support for extending from a class that is not imported; e.g., from a template +dynamically created from a string. Since the most practical way to +get a parent template into a module is to precompile it, all parent templates +essentially have to be precompiled. + +There can be only one \code{\#extends} directive in a template and it +may list only one class. In other words, templates don't do multiple +inheritance. This is intentional: it's too hard to initialize multiple +base classes correctly from inside a template. However, you can do +multiple inheritance in your pure Python classes. + +If your pure Python class overrides any of the standard \code{Template} +methods such as \code{.\_\_init\_\_} or \code{.awake}, be sure to call +the superclass method in your method or things will break. Examples of calling +the superclass method are in section \ref{tips.callingSuperclassMethods}. +A list of all superclass methods is in section +\ref{tips.allMethods}. + +In all cases, the root superclass must be \code{Template}. If your +bottommost class is a template, simply omit the \code{\#extends} in it and it +will automatically inherit from \code{Template}. {\em If your bottommost class +is a pure Python class, it must inherit from \code{Template} explicitly: } +\begin{verbatim} +from Cheetah.Template import Template +class MyPurePythonClass(Template): +\end{verbatim} + +If you're not keen about having your Python classes inherit from +\code{Template}, create a tiny glue class that inherits both from your +class and from \code{Template}. + +Before giving any examples we'll stress that Cheetah does {\em not} +dictate how you should structure your inheritance tree. As long as +you follow the rules above, many structures are possible. + +Here's an example for a large web site that has not only a general site +template, but also a template for this section of the site, and then a +specific template-servlet for each URL. (This is the ``inheritance +approach'' discussed in the Webware chapter.) Each template inherits from a +pure Python class that contains methods/attributes used by the template. We'll +begin with the bottommost superclass and end with the specific +template-servlet: + +\begin{verbatim} +1. SiteLogic.py (pure Python class containing methods for the site) + from Cheetah.Template import Template + class SiteLogic(Template): + +2. Site.tmpl/py (template containing the general site framework; + this is the template that controls the output, + the one that contains "<HTML><HEAD>...", the one + that contains text outside any #def/#block.) + #from SiteLogic import SiteLogic + #extends SiteLogic + #implements respond + +3. SectionLogic.py (pure Python class with helper code for the section) + from Site import Site + class SectionLogic(Site) + +4. Section.tmpl/py (template with '#def' overrides etc. for the section) + #from SectionLogic import SectionLogic + #extends SectionLogic + +5. page1Logic.py (pure Python class with helper code for the template-servlet) + from Section import Section + class indexLogic(Section): + +6. page1.tmpl/py (template-servlet for a certain page on the site) + #from page1Logic import page1Logic + #extends page1Logic +\end{verbatim} + +A pure Python classes might also contain methods/attributes that aren't used by +their immediate child template, but are available for any descendant +template to use if it wishes. For instance, the site template might have +attributes for the name and e-mail address of the site administrator, +ready to use as \$placeholders in any template that wants it. + +{\em Whenever you use \code{\#extends}, you often need \code{\#implements} +too,} as in step 2 above. Read the next section to understand what +\code{\#implements} is and when to use it. + +% @@MO: Edmund suggests making some diagrams of inheritance chains. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#implements} +\label{inheritanceEtc.implements} + +Syntax: +\begin{verbatim} +#implements METHOD +\end{verbatim} + +You can call any \code{\#def} or \code{\#block} method directly and get its +outpt. The top-level content -- all the text/placeholders/directives outside any +\code{\#def}/\code{\#block} -- gets concatenated and wrapped in a ``main +method'', by default \code{.respond()}. So if you call \code{.respond()}, you +get the ``whole template output''. When Webware calls \code{.respond()}, +that's what it's doing. And when you do 'print t' or 'str(t)' on a template +instance, you're taking advantage of the fact that Cheetah makes +\code{.\_\_str\_\_()} an alias for the main method. + +That's all fine and dandy, but what if your application prefers to call another +method name rather than \code{.respond()}? What if it wants to call, say, +\code{.send\_output()} instead? That's where \code{\#implements} steps in. It +lets you choose the name for the main method. Just put this in your template +definition: +\begin{verbatim} +#implements send_output +\end{verbatim} + +When one template extends another, every template in the inheritance chain +has its own main method. To fill the template, you invoke exactly one of +these methods and the others are ignored. The method you call may be in any of +the templates in the inheritance chain: the base template, the leaf template, +or any in between, depending on how you structure your application. So you +have two problems: (1) calling the right method name, and (2) preventing an +undesired same-name subclass method from overriding the one you want to call. + +Cheetah assumes the method you will call is \code{.respond()} because +that's what Webware calls. It further assumes the desired main method is the +one in the lowest-level base template, because that works well with +\code{\#block} as described in the Inheritance Approach for building Webware +servlets (section \ref{webware.inheritance}), which was originally the +principal use for Cheetah. So when you use \code{\#extends}, Cheetah changes +that template's main method to \code{.writeBody()} to get it out of the way and +prevent it from overriding the base template's \code{.respond()}. + +Unfortunately this assumption breaks down if the template is used in other +ways. For instance, you may want to use the main method in the highest-level +leaf template, and treat the base template(s) as merely a library of +methods/attributes. In that case, the leaf template needs \code{\#implements +respond} to change its main method name back to \code{.respond()} (or whatever +your application desires to call). Likewise, if your main method is in one of the +intermediate templates in an inheritance chain, that template needs +\code{\#implements respond}. + +The other way the assumption breaks down is if the main method {\em is} in +the base template but that template extends a pure Python class. Cheetah sees +the \code{\#extends} and dutifully but incorrectly renames the method to +\code{.writeBody()}, so you have to use \code{\#implements respond} to change +it back. Otherwise the dummy \code{.respond()} in \code{Cheetah.Template} +is found, which outputs... nothing. {\bf So if you're using \code{\#extends} +and get no output, the {\em first} thing you should think is, ``Do I need to +add \code{\#implements respond} somewhere?'' } + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#set} +\label{inheritanceEtc.set} + +Syntax: +\begin{verbatim} +#set [global] $var = EXPR +\end{verbatim} + +\code{\#set} is used to create and update local variables at run time. +The expression may be any Python expression. +Remember to preface variable names with \$ unless they're part of an +intermediate result in a list comprehension. + +Here are some examples: +\begin{verbatim} +#set $size = $length * 1096 +#set $buffer = $size + 1096 +#set $area = $length * $width +#set $namesList = ['Moe','Larry','Curly'] +#set $prettyCountry = $country.replace(' ', ' ') +\end{verbatim} + +\code{\#set} variables are useful to assign a short name to a +\code{\$deeply.nested.value}, to a calculation, or to a printable version of +a value. The last example above converts any spaces in the 'country' value +into HTML non-breakable-space entities, to ensure the entire value appears on +one line in the browser. + +\code{\#set} variables are also useful in \code{\#if} expressions, but +remember that complex logical routines should be coded in Python, not in +Cheetah! +\begin{verbatim} +#if $size > 1500 + #set $adj = 'large' +#else + #set $adj = 'small' +#end if +\end{verbatim} +Or Python's one-line equivalent, "A and B or C". Remember that in this case, +B must be a true value (not None, '', 0, [] or {}). +\begin{verbatim} +#set $adj = $size > 1500 and 'large' or 'small' +\end{verbatim} +(Note: Cheetah's one-line \code{\#if} will not work for this, since it +produces output rather than setting a variable. + +You can also use the augmented assignment operators: +\begin{verbatim} +## Increment $a by 5. +#set $a += 5 +\end{verbatim} + +By default, \code{\#set} variables are not visible in method calls or include +files unless you use the \code{global} attribute: \code{\#set global \$var = +EXPRESSION}. Global variables are visible in all methods, nested templates and +included files. Use this feature with care to prevent surprises. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#del} +\label{inheritanceEtc.del} + +Syntax: +\begin{verbatim} +#del $var +\end{verbatim} + +\code{\#del} is the opposite of \code{\#set}. It deletes a {\em local} +variable. Its usage is just like Python's \code{del} statement: +\begin{verbatim} +#del $myVar +#del $myVar, $myArray[5] +\end{verbatim} + +Only local variables can be deleted. There is no directive to delete a +\code{\#set global} variable, a searchList variable, or any other type of +variable. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#attr} +\label{inheritanceEtc.attr} + +Syntax: +\begin{verbatim} +#attr $var = EXPR +\end{verbatim} + +The \code{\#attr} directive creates class attributes in the generated Python +class. It should be used to assign simple Python literals such as numbers or +strings. In particular, the expression must {\em not} depend on searchList +values or \code{\#set} variables since those are not known at compile time. + +\begin{verbatim} +#attr $title = "Rob Roy" +#attr $author = "Sir Walter Scott" +#attr $version = 123.4 +\end{verbatim} + +This template or any child template can output the value thus: +\begin{verbatim} +$title, by $author, version $version +\end{verbatim} + +If you have a library of templates derived from etexts +(\url{http://www.gutenberg.org/}), you can extract the titles and authors +and put them in a database (assuming the templates have been compiled into +.py template modules): + +%\begin{verbatim} +%import glob +% +%\end{verbatim} +% +% @@MO: Finish this example. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#def} +\label{inheritanceEtc.def} + +Syntax: +\begin{verbatim} +#def METHOD[(ARGUMENTS)] +#end def +\end{verbatim} + +Or the one-line variation: +\begin{verbatim} +#def METHOD[(ARGUMENTS)] : TEXT_AND_PLACEHOLDERS +\end{verbatim} + + +The \code{\#def} directive is used to define new methods in the generated +Python class, or to override superclass methods. It is analogous to Python's +\code{def} statement. The directive is silent, meaning it does not itself +produce any output. However, the content of the method will be inserted into +the output (and the directives executed) whenever the method is later called by +a \$placeholder. + +\begin{verbatim} +#def myMeth() +This is the text in my method +$a $b $c(123) ## these placeholder names have been defined elsewhere +#end def + +## and now use it... +$myMeth() +\end{verbatim} + +The arglist and parentheses can be omitted: +\begin{verbatim} +#def myMeth +This is the text in my method +$a $b $c(123) +#end def + +## and now use it... +$myMeth +\end{verbatim} + +Methods can have arguments and have defaults for those arguments, just like +in Python. Remember the \code{\$} before variable names: +\begin{verbatim} +#def myMeth($a, $b=1234) +This is the text in my method +$a - $b +#end def + +## and now use it... +$myMeth(1) +\end{verbatim} + +The output from this last example will be: + +\begin{verbatim} +This is the text in my method +1 - 1234 +\end{verbatim} + +There is also a single line version of the \code{\#def} directive. +{\bf Unlike the multi-line directives, it uses a colon (:) to delimit the method +signature and body}: +\begin{verbatim} +#attr $adj = 'trivial' +#def myMeth: This is the $adj method +$myMeth +\end{verbatim} +Leading and trailing whitespace is stripped from the method. This is in +contrast to: +\begin{verbatim} +#def myMeth2 +This is the $adj method +#end def +\end{verbatim} +where the method includes a newline after "method". If you don't want the +newline, add \code{\#slurp}: +\begin{verbatim} +#def myMeth3 +This is the $adj method#slurp +#end def +\end{verbatim} + +Because \code{\#def} is handled at compile time, it can appear above or +below the placeholders that call it. And if a superclass placeholder +calls a method that's overridden in a subclass, it's the subclass method +that will be called. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{\#block ... \#end block} +\label{inheritanceEtc.block} + + +The \code{\#block} directive allows you to mark a section of your template that +can be selectively reimplemented in a subclass. It is very useful for +changing part of a template without having to copy-paste-and-edit +the entire thing. The output from a template definition that uses blocks will +be identical to the output from the same template with the \code{\#block \ldots +\#end block} tags removed. + +({\em Note:} don't be confused by the generic word `block'' in this Guide, +which means a section of code inside {\em any} \code{\#TAG \ldots \#end TAG} +pair. Thus, an if-block, for-block, def-block, block-block etc. In this +section we are talking only of block-blocks.) + +To reimplement the block, use the \code{\#def} directive. The magical effect +is that it appears to go back and change the output text {\em at the point the +original block was defined} rather than at the location of the +reimplementation. + +\begin{verbatim} +#block testBlock +Text in the contents +area of the block directive +#if $testIt +$getFoo() +#end if +#end block testBlock +\end{verbatim} + +You can repeat the block name in the \code{\#end block} directive or not, as +you wish. + +\code{\#block} directives can be nested to any depth. + +\begin{verbatim} +#block outerBlock +Outer block contents + +#block innerBlock1 +inner block1 contents +#end block innerBlock1 + +#block innerBlock2 +inner block2 contents +#end block innerBlock2 + +#end block outerBlock +\end{verbatim} + +Note that the name of the block is optional for the \code{\#end block} tag. + +Technically, \code{\#block} directive is equivalent to a \code{\#def} directive +followed immediately by a \code{\#placeholder} for the same name. In fact, +that's what Cheetah does. Which means you can use \code{\$theBlockName} +elsewhere in the template to output the block content again. + +There is a one-line \code{\#block} syntax analagous to the one-line +\code{\#def}. + +The block must not require arguments because the implicit placeholder that's +generated will call the block without arguments. + + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_src/introduction.tex b/docs/users_guide_src/introduction.tex new file mode 100755 index 0000000..be34fc6 --- /dev/null +++ b/docs/users_guide_src/introduction.tex @@ -0,0 +1,392 @@ +\section{Introduction} +\label{intro} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Who should read this Guide?} +\label{intro.whoShouldRead} + +This Users' Guide provides a technical overview and reference for the +Cheetah template system. Knowledge of Python and object-oriented programming +is assumed. The emphasis in this Guide is on features useful in a wide variety +of situations. Information on less common situations and troubleshooting tips +are gradually being moved to the Cheetah FAQ. There is also a Cheetah +Developer's Guide for those who want to know what goes on under the hood. + +%% A gentler introduction for template maintainers who don't know +%% Python will be written later. + +This Guide also contains examples of integrating Cheetah with Webware for +Python. You will have to learn Webware from its own documentation in order to +build a Webware + Cheetah site. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{What is Cheetah?} +\label{intro.whatIs} + +Cheetah is a Python-powered template engine and code generator. It may be used +as a standalone utility or combined with other tools. Cheetah has +many potential uses, but web developers looking for a viable alternative to ASP, +JSP, PHP and PSP are expected to be its principle user group. + +Cheetah: +\begin{itemize} +\item generates HTML, SGML, XML, SQL, Postscript, form email, LaTeX, or any + other text-based format. It has also been used to produce Python, Java + and PHP source code. + +\item cleanly separates content, graphic design, and program code. This leads + to highly modular, flexible, and reusable site architectures; faster + development time; and HTML and program code that is easier to understand + and maintain. It is particularly well suited for team efforts. + +\item blends the power and flexibility of Python with a simple template language + that non-programmers can understand. + +\item gives template writers full access in their templates to any Python data + structure, module, function, object, or method. + +\item makes code reuse easy by providing an object-oriented interface to + templates that is accessible from Python code or other Cheetah templates. + One template can subclass another and selectively reimplement sections of + it. A compiled template {\em is} a Python class, so it can subclass a + pure Python class and vice-versa. + +\item provides a simple yet powerful caching mechanism + +%% that can dramatically improve the performance of a dynamic website. +\end{itemize} + +Cheetah integrates tightly with {\bf Webware for Python} +(\url{http://webware.sourceforge.net/}): a Python-powered application server and +persistent servlet framework. Webware provides automatic session, cookie, and +user management and can be used with almost any operating-system, web server, or +database. Through Python, it works with XML, SOAP, XML-RPC, CORBA, COM, DCOM, +LDAP, IMAP, POP3, FTP, SSL, etc.. Python supports structured exception handling, +threading, object serialization, unicode, string internationalization, advanced +cryptography and more. It can also be extended with code and libraries written +in C, C++, Java and other languages. + +Like Python, Cheetah and Webware are Open Source software and are supported by +active user communities. Together, they are a powerful and elegant framework +for building dynamic web sites. + +Like its namesake, Cheetah is fast, flexible and powerful. + +% @@MO: Repeat picture of cheetah. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{What is the philosophy behind Cheetah?} +\label{intro.philosophy} + +Cheetah's design was guided by these principles: +\begin{itemize} +\item Python for the back end, Cheetah for the front end. Cheetah was + designed to complement Python, not replace it. + +\item Cheetah's core syntax should be easy for non-programmers to learn. + +\item Cheetah should make code reuse easy by providing an object-oriented + interface to templates that is accessible from Python code or other + Cheetah templates. + +\item Python objects, functions, and other data structures should be fully + accessible in Cheetah. + +\item Cheetah should provide flow control and error handling. Logic + that belongs in the front end shouldn't be relegated to the + back end simply because it's complex. + +\item It should be easy to {\bf separate} content, graphic design, and program + code, but also easy to {\bf integrate} them. + + A clean separation makes it easier for a team of content writers, + HTML/graphic designers, and programmers to work together without stepping + on each other's toes and polluting each other's work. The HTML framework + and the content it contains are two separate things, and analytical + calculations (program code) is a third thing. Each team member should be + able to concentrate on their specialty and to implement their changes + without having to go through one of the others (i.e., the dreaded + ``webmaster bottleneck''). + + While it should be easy to develop content, graphics and program + code separately, it should be easy to integrate them together into a + website. In particular, it should be easy: + + \begin{itemize} + \item for {\bf programmers} to create reusable components and functions + that are accessible and understandable to designers. + \item for {\bf designers} to mark out placeholders for content and + dynamic components in their templates. + \item for {\bf designers} to soft-code aspects of their design that are + either repeated in several places or are subject to change. + \item for {\bf designers} to reuse and extend existing templates and thus + minimize duplication of effort and code. + \item and, of course, for {\bf content writers} to use the templates that + designers have created. + \end{itemize} + +\end{itemize} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Why Cheetah doesn't use HTML-style tags} +\label{intro.htmlStyleTags} + +Cheetah does not use HTML/XML-style tags like some other template languages for +the following reasons: + Cheetah is not limited to HTML, + HTML-style tags are hard to distinguish from real HTML tags, + HTML-style tags are not visible in rendered HTML when something goes wrong, + HTML-style tags often lead to invalid HTML (e.g., +\code{<img src="<template-directive>">}), +Cheetah tags are less verbose and easier to understand than HTML-style tags, +and HTML-style tags aren't compatible with most WYSIWYG editors + +Besides being much more compact, Cheetah also has some advantages over +languages that put information inside the HTML tags, such as Zope Page +Templates or PHP: + HTML or XML-bound languages do not work well with other languages, + While ZPT-like syntaxes work well in many ways with WYSIWYG HTML editors, + they also give up a significant advantage of those editors -- concrete + editing of the document. When logic is hidden away in (largely + inaccessible) tags it is hard to understand a page simply by viewing it, + and it is hard to confirm or modify that logic. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Give me an example!} +\label{intro.example} + +Here's a very simple example that illustrates some of Cheetah's basic syntax: + +\begin{verbatim} + +<HTML> +<HEAD><TITLE>$title</TITLE></HEAD> +<BODY> + +<TABLE> +#for $client in $clients +<TR> +<TD>$client.surname, $client.firstname</TD> +<TD><A HREF="mailto:$client.email">$client.email</A></TD> +</TR> +#end for +</TABLE> + +</BODY> +</HTML> +\end{verbatim} + +Compare this with PSP: + +\begin{verbatim} +<HTML> +<HEAD><TITLE><%=title%></TITLE></HEAD> +<BODY> + +<TABLE> +<% for client in clients: %> +<TR> +<TD><%=client['surname']%>, <%=client['firstname']%></TD> +<TD><A HREF="mailto:<%=client['email']%>"><%=client['email']%></A></TD> +</TR> +<%end%> +</TABLE> + +</BODY> +</HTML> +\end{verbatim} + +Section \ref{gettingStarted.tutorial} has a more typical example that shows +how to get the plug-in values {\em into} Cheetah, and section +\ref{howWorks.cheetah-compile} explains how to turn your template definition +into an object-oriented Python module. + +%% @@TR: I'm going to extend this and briefly introduce: +%% - Template objects vs. .tmpl files. +%% - how to get data into it +%% @@MO: If you do this, reconcile this example and the one in gettingStarted. +%% Keep two examples or collapse into one? + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Give me an example of a Webware servlet!} +\label{intro.example.servlet} + +This example uses an HTML form to ask the user's name, then invokes itself +again to display a {\em personalized} friendly greeting. + +\begin{verbatim} +<HTML><HEAD><TITLE>My Template-Servlet</TITLE></HEAD><BODY> +#set $name = $request.field('name', None) +#if $name +Hello $name +#else +<FORM ACTION="" METHOD="GET"> +Name: <INPUT TYPE="text" NAME="name"><BR> +<INPUT TYPE="submit"> +</FORM> +#end if +</BODY></HTML> +\end{verbatim} + +To try it out for yourself on a Webware system: +\begin{enumerate} +\item copy the template definition to a file {\bf test.tmpl} in your + Webware servlet directory. +\item Run ``\code{cheetah compile test.tmpl}''. This produces + {\bf test.py} (a .py template module) in the same directory. +\item In your web browser, go to {\bf test.py}, using whatever site and + directory is appropriate. Depending on your Webware configuration, you may + also be able to go to {\bf test}. +\end{enumerate} + +At the first request, field `name' will be blank (false) so the ``\#else'' +portion will execute and present a form. You type your name and press submit. +The form invokes the same page. Now `name' is true so the ``\#if'' portion +executes, which displays the greeting. The ``\#set'' directive creates a +local variable that lasts while the template is being filled. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{How mature is Cheetah?} +\label{intro.mature} + +Cheetah is stable, production quality, post-beta code. Cheetah's syntax, +semantics and performance have been generally stable since a performance +overhaul in mid 2001. Most of the changes since October 2001 have +been in response to specific requests by production sites, things they need that +we hadn't considered. + +As of summer 2003, we are putting in the final touches before the 1.0 release. + +The {\bf TODO} and {\bf BUGS} files in the Cheetah distribution show what we're +working on now or planning to work on. There's also a {\bf ToDo} page on the +wiki (see below), which is updated less often. The {\bf WishList} page on the +wiki shows requested features we're considering but haven't commited to. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Where can I get news?} +\label{intro.news} + +Cheetah releases and other stuff can be obtained from the the Cheetah +{\bf Web site}: +\url{http://CheetahTemplate.sourceforge.net} + +Cheetah discussions take place on the {\bf mailing list} +\email{cheetahtemplate-discuss@lists.sourceforge.net}. This is where to hear +the latest news first. + +The Cheetah {\bf wiki} is becoming an increasingly popular place to list +examples of Cheetah in use, provide cookbook tips for solving various problems, +and brainstorm ideas for future versions of Cheetah. +\url{http://www.cheetahtemplate.org/wiki} +(The wiki is actually hosted at +\url{http://cheetah.colorstudy.net/twiki/bin/view/Cheetah/WebHome}, but the +other URL is easier to remember.) +For those unfamiliar with a wiki, it's a type of Web site that readers can edit +themselves to make additions or corrections to. Try it. Examples and tips +from the wiki will also be considered for inclusion in future versions of this +Users' Guide. + +If you encounter difficulties, or are unsure about how to do something, +please post a detailed message to the list. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{How can I contribute?} +\label{intro.contribute} + +Cheetah is the work of many volunteers. If you use Cheetah please share your +experiences, tricks, customizations, and frustrations. + +\subsubsection{Bug reports and patches} + +If you think there is a bug in Cheetah, send a message to the e-mail list +with the following information: + +\begin{enumerate} +\item a description of what you were trying to do and what happened +\item all tracebacks and error output +\item your version of Cheetah +\item your version of Python +\item your operating system +\item whether you have changed anything in the Cheetah installation +\end{enumerate} + +\subsubsection{Example sites and tutorials} +If you're developing a website with Cheetah, please put a link on the wiki on +the {\bf WhoIsUsingCheetah} page, and mention it on the list. Also, if you +discover new and interesting ways to use Cheetah, please put a quick tutorial +(HOWTO) about your technique on the {\bf CheetahRecipies} page on the wiki. + +\subsubsection{Template libraries and function libraries} +We hope to build up a framework of Template libraries (see section +\ref{libraries.templates}) to distribute with Cheetah and would appreciate any +contributions. + +\subsubsection{Test cases} +Cheetah is packaged with a regression testing suite that is run with each +new release to ensure that everything is working as expected and that recent +changes haven't broken anything. The test cases are in the Cheetah.Tests +module. If you find a reproduceable bug please consider writing a test case +that will pass only when the bug is fixed. Send any new test cases to the email +list with the subject-line ``new test case for Cheetah.'' + +\subsubsection{Publicity} +Help spread the word ... recommend it to others, write articles about it, etc. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Acknowledgements} +\label{intro.acknowledgments} + +Cheetah is one of several templating frameworks that grew out of a `templates' +thread on the Webware For Python email list. Tavis Rudd, Mike Orr, Chuck +Esterbrook and Ian Bicking are the core developers. + +We'd like to thank the following people for contributing valuable advice, code +and encouragement: Geoff Talvola, Jeff Johnson, Graham Dumpleton, Clark C. +Evans, Craig Kattner, Franz Geiger, Geir Magnusson, Tom Schwaller, Rober Kuzelj, +Jay Love, Terrel Shumway, Sasa Zivkov, Arkaitz Bitorika, Jeremiah Bellomy, +Baruch Even, Paul Boddie, Stephan Diehl, Chui Tey, Michael Halle, Edmund Lian +and Aaron Held. + +The Velocity, WebMacro and Smarty projects provided inspiration and design +ideas. Cheetah has benefitted from the creativity and energy of their +developers. Thank you. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{License} +\label{intro.license} + +\paragraph*{The gist} +Cheetah is open source, but products developed with Cheetah or derived +from Cheetah may be open source or closed source. + +{\bf Cheetah.Utils.optik} is based on a third-party package Optik by Gregory +P Ward. Optik's license is in appendix \ref{optikLicense}. + + +\paragraph*{Legal terms} +Copyright \copyright 2001, The Cheetah Development Team: Tavis Rudd, Mike Orr, +Ian Bicking, Chuck Esterbrook. + +Permission to use, copy, modify, and distribute this software for any purpose +and without fee is hereby granted, provided that the above copyright notice +appear in all copies and that both that copyright notice and this permission +notice appear in supporting documentation, and that the names of the authors not +be used in advertising or publicity pertaining to distribution of the software +without specific, written prior permission. + +THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS +BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +These terms do not apply to the {\bf Cheetah.Utils.optik} package. Optik's +license is in appendix \ref{optikLicense}. + +% Local Variables: +% TeX-master: "users_guide" +% End: diff --git a/docs/users_guide_src/language.tex b/docs/users_guide_src/language.tex new file mode 100755 index 0000000..673abca --- /dev/null +++ b/docs/users_guide_src/language.tex @@ -0,0 +1,651 @@ +\section{Language Overview} +\label{language} + +Cheetah's basic syntax was inspired by the Java-based template engines Velocity +and WebMacro. It has two types of tags: {\bf \$placeholders} and {\bf +\#directives}. Both types are case-sensitive. + +Placeholder tags begin with a dollar sign (\code{\$varName}) and are similar to +data fields in a form letter or to the \code{\%(key)s} fields on the left side +of Python's \code{\%} operator. When the template is filled, the placeholders +are replaced with the values they refer to. + +Directive tags begin with a hash character (\#) and are used for comments, +loops, conditional blocks, includes, and all other advanced features. +({\em Note:} you can customize the start and end delimeters for placeholder +and directive tags, but in this Guide we'll assume you're using the default.) + +Placeholders and directives can be escaped by putting a backslash before them. +\verb+\$var+ and \verb+\#if+ will be output as literal text. + +A placeholder or directive can span multiple physical lines, following the same +rules as Python source code: put a backslash (\verb+\+) at the end of all +lines except the last line. However, if there's an unclosed parenthesis, +bracket or brace pending, you don't need the backslash. + +\begin{verbatim} +#if $this_is_a_very_long_line and $has_lots_of_conditions \ + and $more_conditions: +<H1>bla</H1> +#end if + +#if $country in ('Argentina', 'Uruguay', 'Peru', 'Colombia', + 'Costa Rica', 'Venezuela', 'Mexico') +<H1>Hola, senorita!</H1> +#else +<H1>Hey, baby!</H1> +#end if +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Language Constructs -- Summary} +\label{language.constructs} + +\begin{enumerate} +\item Comments and documentation strings + \begin{enumerate} + \item \code{\#\# single line} + \item \code{\#* multi line *\#} + \end{enumerate} + +\item Generation, caching and filtering of output + \begin{enumerate} + \item plain text + \item look up a value: \code{\$placeholder} + \item evaluate an expression: \code{\#echo} \ldots + \item same but discard the output: \code{\#silent} \ldots + \item one-line if: \code{\#if EXPR then EXPR else EXPR} + \item gobble the EOL: \code{\#slurp} + \item parsed file includes: \code{\#include} \ldots + \item raw file includes: \code{\#include raw} \ldots + \item verbatim output of Cheetah code: \code{\#raw} \ldots \code{\#end raw} + \item cached placeholders: \code{\$*var}, \code{\$*<interval>*var} + \item cached regions: \code{\#cache} \ldots \code{\#end cache} + \item set the output filter: \code{\#filter} \ldots + \item control output indentation: \code{\#indent} \ldots ({\em not +implemented yet}) + \end{enumerate} + +\item Importing Python modules and objects: \code{\#import} \ldots, + \code{\#from} \ldots + +\item Inheritance + \begin{enumerate} + \item set the base class to inherit from: \code{\#extends} + \item set the name of the main method to implement: \code{\#implements} +\ldots + \end{enumerate} + +\item Compile-time declaration + \begin{enumerate} + \item define class attributes: \code{\#attr} \ldots + \item define class methods: \code{\#def} \ldots \code{\#end def} + \item \code{\#block} \ldots \code{\#end block} provides a simplified + interface to \code{\#def} \ldots \code{\#end def} + \end{enumerate} + +\item Run-time assignment + \begin{enumerate} + \item local vars: \code{\#set} \ldots + \item global vars: \code{\#set global} \ldots + \item deleting local vars: \code{\#del} \ldots + \end{enumerate} + +\item Flow control + \begin{enumerate} + \item \code{\#if} \ldots \code{\#else} \ldots \code{\#else if} (aka + \code{\#elif}) \ldots \code{\#end if} + \item \code{\#unless} \ldots \code{\#end unless} + \item \code{\#for} \ldots \code{\#end for} + \item \code{\#repeat} \ldots \code{\#end repeat} + \item \code{\#while} \ldots \code{\#end while} + \item \code{\#break} + \item \code{\#continue} + \item \code{\#pass} + \item \code{\#stop} + \end{enumerate} + +\item error/exception handling + \begin{enumerate} + \item \code{\#assert} + \item \code{\#raise} + \item \code{\#try} \ldots \code{\#except} \ldots \code{\#else} \ldots + \code{\#end try} + \item \code{\#try} \ldots \code{\#finally} \ldots \code{\#end try} + \item \code{\#errorCatcher} \ldots set a handler for exceptions raised by +\$placeholder calls. + \end{enumerate} + +\item Instructions to the parser/compiler + \begin{enumerate} + \item \code{\#breakpoint} + \item \code{\#compiler-settings} \ldots \code{\#end compiler-settings} + \end{enumerate} + +\item Escape to pure Python code + \begin{enumerate} + \item evalute expression and print the output: \code{<\%=} \ldots + \code{\%>} + \item execute code and discard output: \code{<\%} \ldots \code{\%>} + \end{enumerate} + +\item Fine control over Cheetah-generated Python modules + \begin{enumerate} + \item set the source code encoding of compiled template modules: \code{\#encoding} + \item set the sh-bang line of compiled template modules: \code{\#shBang} + \end{enumerate} + +\end{enumerate} + +The use of all these constructs will be covered in the next several chapters. + +%% @@MO: TODO: reconcile the order of this summary with the order in the +%% detail sections. + +% @@MO: PSP chapter with examples. What does write() do? Print? + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Placeholder Syntax Rules} +\label{language.placeholders.syntax} + +\begin{itemize} + +\item Placeholders follow the same syntax rules as Python variables except + that they are preceded by \code{\$} (the short form) or enclosed in + \code{\$\{\}} (the long form). + Examples: +\begin{verbatim} +$var +${var} +$var2.abc['def']('gh', $subplaceholder, 2) +${var2.abc['def']('gh', $subplaceholder, 2)} +\end{verbatim} + We recommend \code{\$} in simple cases, and \code{\$\{\}} when followed + directly by a letter or when Cheetah or a human template maintainer might + get confused about where the placeholder ends. You may alternately use + \verb+$()+ or \verb+$[]+, although this may confuse the (human) template + maintainer: +\begin{verbatim} +$(var) +$[var] +$(var2.abc['def']('gh', $subplaceholder, 2)) +$[var2.abc['def']('gh', $subplaceholder, 2)] +\end{verbatim} + {\em Note:} Advanced users can change the delimiters to anything they + want via the \code{\#compiler} directive. + + {\em Note 2:} The long form can be used only with top-level placeholders, + not in expressions. See section \ref{language.placeholders.positions} + for an elaboration on this. + +\item To reiterate Python's rules, placeholders consist of one or more + identifiers separated by periods. Each identifier must start with a letter + or an underscore, and the subsequent characters must be letters, digits or + underscores. Any identifier may be followed by arguments enclosed in + \verb+()+ and/or keys/subscripts in \verb+[]+. + +\item Identifiers are case sensitive. \code{\$var} does not equal \code{\$Var} + or \code{\$vAr} or \code{\$VAR}. + +\item Arguments inside \verb+()+ or \verb+[]+ are just like in Python. + Strings may be quoted using any Python quoting style. Each argument is an + expression and may use any of Python's expression operators. Variables + used in argument expressions are placeholders and should be prefixed with + \code{\$}. This also applies to the *arg and **kw forms. However, you do + {\em not} need the \code{\$} with the special Python constants \code{None}, + \code{True} and \code{False}. + Examples: +\begin{verbatim} +$hex($myVar) +$func($arg=1234) +$func2($*args, $**kw) +$func3(3.14159, $arg2, None, True) +$myList[$mySubscript] +\end{verbatim} + +\item Trailing periods are ignored. Cheetah will recognize that the placeholder + name in \code{\$varName.} is \code{varName}, and the period will be left + alone in the template output. + +\item The syntax \code{\$\{placeholderName, arg1="val1"\}} passes arguments to + the output filter (see \code{\#filter}, section \ref{output.filter}. + The braces and comma are required in this case. It's conventional to + omit the \code{\$} before the keyword arguments (i.e. \code{arg1}) in this + case. + +\item Cheetah ignores all dollar signs (\code{\$}) that are not followed by a + letter or an underscore. + +\end{itemize} + +The following are valid \$placeholders: +\begin{verbatim} +$a $_ $var $_var $var1 $_1var $var2_ $dict.key $list[3] +$object.method $object.method() $object.method +$nest($nest($var)) +\end{verbatim} + +These are not \$placeholders but are treated as literal text: +\begin{verbatim} +$@var $^var $15.50 $$ +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Where can you use placeholders?} +\label{language.placeholders.positions} + +There are three places you can use placeholders: top-level position, +expression position and LVALUE position. Each has slightly different +syntax rules. + +Top-level position means interspersed in text. This is the only place +you can use the placeholder long form: \code{\$\{var\}}. + +{\em Expression position} means inside a Cheetah expression, which is the same +as a Python expression. The placeholder names a searchList or other variable +to be read. Expression position occurs inside () and $[]$ arguments within +placeholder tags (i.e., a placeholder inside a placeholder), and in several +directive tags. + +{\em LVALUE position} means naming a variable that will be written to. LVALUE +is a computer science term meaning ``the left side of an assignment +statement''. The first argument of directives \code{\#set}, \code{\#for}, +\code{\#def}, \code{\#block} and \code{\#attr} is an LVALUE. + +This stupid example shows the three positions. Top-level position is shown +in \code{courier}, expression position is {\em italic}, and LVALUE position is +{\bf bold}. + +\begin{quote} +\#for {\bf \$count} in {\em \$range}({\em \$ninetyNine}, 0, -1)\\ +\#set {\bf \$after} = {\em \$count} - 1\\ +\code{\$count} bottles of beer on the wall. \code{\$count} bottles of beer!\\ +~~~~Take one down, pass it around. \code{\$after} bottles of beer on the wall.\\ +\#end for\\ +\code{\$hex}({\em \$myVar}, {\bf \$default}={\em None}) +\end{quote} + +The output of course is: +\begin{verbatim} +99 bottles of beer on the wall. 99 bottles of beer! + Take one down, pass it around. 98 bottles of beer on the wall. +98 bottles of beer on the wall. 98 bottles of beer! + Take one down, pass it around. 97 bottles of beer on the wall. +... +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Are all those dollar signs really necessary?} +\label{language.placeholders.dollar-signs} + +\code{\$} is a ``smart variable prefix''. When Cheetah sees \code{\$}, it +determines both the variable's position and whether it's a searchList value or +a non-searchList value, and generates the appropriate Python code. + +In top-level position, the \code{\$} is {\em required}. Otherwise there's +nothing to distinguish the variable from ordinary text, and the variable name +is output verbatim. + +In expression position, the \code{\$} is {\em required} if the value comes from +the searchList or a ``\#set global'' variable, {\em recommended} for +local/global/builtin variables, and {\em not necessary} for the special +constants \code{None}, \code{True} and \code{False}. This works because +Cheetah generates a function call for a searchList placeholder, but a bare +variable name for a local/global/builtin variable. + +In LVALUE position, the \code{\$} is {\em recommended}. Cheetah knows where +an LVALUE is expected, so it can handle your variable name whether it has +\code{\$} or not. + +EXCEPTION: Do {\em not} use the \code{\$} prefix for intermediate variables in +a Python list comprehensions. This is a limitation of Cheetah's parser; it +can't tell which variables in a list comprehension are the intermediate +variables, so you have to help it. For example: +\begin{verbatim} +#set $theRange = [x ** 2 for x in $range(10)] +\end{verbatim} +\code{\$theRange} is a regular \code{\#set} variable. \code{\$range} is a +Python built-in function. But \code{x} is a scratch variable internal to +the list comprehension: if you type \code{\$x}, Cheetah will miscompile +it. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{NameMapper Syntax} +\label{language.namemapper} + +One of our core aims for Cheetah was to make it easy for non-programmers to +use. Therefore, Cheetah uses a simplified syntax for mapping placeholders +in Cheetah to values in Python. It's known as the {\bf NameMapper syntax} +and allows for non-programmers to use Cheetah without knowing (a) the +difference between an instance and a dictionary, (b) what functions and methods +are, and (c) what 'self' is. A side benefit is that you can change the +underlying data structure (e.g., instance to dictionary or vice-versa) without +having to modify the templates. + +NameMapper syntax is used for all variables in Cheetah placeholders and +directives. If desired, it can be turned off via the \code{Template} class' +\code{'useNameMapper'} compiler setting. But it's doubtful you'd ever want to +turn it off. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Example} +\label{language.namemapper.example} + +Consider this scenario: + +You are building a customer information system. The designers with you want to +use information from your system on the client's website --AND-- they want to +understand the display code and so they can maintian it themselves. + +You write a UI class with a 'customers' method that returns a dictionary of all +the customer objects. Each customer object has an 'address' method that returns +the a dictionary with information about the customer's address. The designers +want to be able to access that information. + +Using PSP, the display code for the website would look something like the +following, assuming your servlet subclasses the class you created for managing +customer information: + +\begin{verbatim} + <%= self.customer()[ID].address()['city'] %> (42 chars) +\end{verbatim} + +With Cheetah's NameMapper syntax, you can use any of the following: + +\begin{verbatim} + $self.customers()[$ID].address()['city'] (39 chars) + --OR-- + $customers()[$ID].address()['city'] + --OR-- + $customers()[$ID].address().city + --OR-- + $customers()[$ID].address.city + --OR-- + $customers[$ID].address.city (27 chars) +\end{verbatim} + +Which of these would you prefer to explain to the designers, who have no +programming experience? The last form is 15 characters shorter than the PSP +version and -- conceptually -- far more accessible. With PHP or ASP, the +code would be even messier than with PSP. + +This is a rather extreme example and, of course, you could also just implement +\code{\$getCustomer(\$ID).city} and obey the Law of Demeter (search Google for more +on that). But good object orientated design isn't the point of this example. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Dictionary Access} +\label{language.namemapper.dict} + +NameMapper syntax allows access to dictionary items with the same dotted +notation used to access object attributes in Python. This aspect of NameMapper +syntax is known as 'Unified Dotted Notation'. +For example, with Cheetah it is possible to write: +\begin{verbatim} + $customers()['kerr'].address() --OR-- $customers().kerr.address() +\end{verbatim} +where the second form is in NameMapper syntax. + +This works only with dictionary keys that also happen to be valid Python +identifiers. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Autocalling} +\label{language.namemapper.autocalling} + +Cheetah automatically detects functions and methods in Cheetah \$variables and +calls them if the parentheses have been left off. Our previous example can be +further simplified to: +\begin{verbatim} + $customers.kerr.address +\end{verbatim} + +As another example, if 'a' is an object, 'b' is a method +\begin{verbatim} + $a.b +\end{verbatim} + +is equivalent to + +\begin{verbatim} + $a.b() +\end{verbatim} + +If b returns a dictionary, then following variations are possible +\begin{verbatim} + $a.b.c --OR-- $a.b().c --OR-- $a.b()['c'] +\end{verbatim} +where 'c' is a key in the dictionary that a.b() returns. + +Further notes: +\begin{itemize} +\item When Cheetah autocalls a function/method, it calls it without any +arguments. Thus, the function/method must have been declared without arguments +(except \code{self} for methods) or to provide default values for all arguments. +If the function requires arguments, you must use the \code{()}. + +\item Cheetah autocalls only functions and methods. Classes and other callable +objects are not autocalled. The reason is that the primary purpose of a +function/method is to call it, whereas the primary purpose of an instance is to +look up its attributes or call its methods, not to call the instance itself. +And calling a class may allocate large sums of memory uselessly or have other +side effects, depending on the class. For instance, consider +\code{\$myInstance.fname}. Do we want to look up \code{fname} in the namespace +of \code{myInstance} or in the namespace of whatever \code{myinstance} returns? +It could go either way, so Cheetah follows the principle of least surprise. If +you {\em do} want to call the instance, put the \code{()} on, or rename the +\code{.\_\_call\_\_()} method to \code{.\_\_str\_\_}. + +\item Autocalling can be disabled via Cheetah's 'useAutocalling' compiler +setting. You can also disable it for one placeholder by using the syntax +\code{\$getVar('varName', 'default value', False)}. (\code{.getVar()} works +only with searchList values.) +\end{itemize} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Namespace cascading and the searchList} +\label{language.searchList} + +When Cheetah maps a variable name in a template to a Python value, it searches +several namespaces in order: + +\begin{enumerate} +\item {\bf Local variables:} created by \code{\#set}, + \code{\#for}, or predefined by Cheetah. +\item The {\bf searchList}, consisting of: + \begin{enumerate} + \item \code{\#set\ global} variables. + \item The {\bf searchList} containers you passed to the \code{Template} + constructor, if any. + \item The {\bf Template instance} (``self''). This contains any attributes + you assigned, \code{\#def} methods and \code{\#block methods}, + attributes/methods inherited via \code{\#extends}, and other + attributes/methods built into \code{Template} or inherited by it + (there's a list of all these methods in section + \ref{tips.allMethods}). + \end{enumerate} +\item {\bf Python globals:} created by \code{\#import}, + \code{\#from\ ...\ import}, or otherwise predefined by Cheetah. +\item {\bf Python builtins:} \code{None}, \code{max}, etc. +\end{enumerate} + +The first matching name found is used. + +Remember, these namespaces apply only to the {\em first} identifier after the +\code{\$}. In a placeholder like \code{\$a.b}, only `a' is looked up in the +searchList and other namespaces. `b' is looked up only inside `a'. + +A searchList container can be any Python object with attributes or keys: +dictionaries, instances, classes or modules. If an instance contains both +attributes and keys, its attributes are searched first, then its keys. + +Because the \code{Template} instance is part of the searchList, you can +access its attributes/methods without `self': \code{\$myAttr}. However, use +the `self' if you want to make sure you're getting the \code{Template} +attribute and not a same-name variable defined in a higher namespace: +\code{\$self.myAttr}. This works because ``self'' itself is a local variable. + +The final resulting value, after all lookups and function calls (but before the +filter is applied) is called the {\em placeholder value}, no matter which +namespace it was found in. + +{\em {\bf Note carefully:}} if you put an object `myObject' in the searchList, +you {\em cannot} look up \code{\$myObject}! You can look up only the +attributes/keys {\em inside} `myObject'. + +Earlier versions of Cheetah did not allow you to override Python builtin +names, but this was fixed in Cheetah 0.9.15. + +If your template will be used as a Webware servlet, do not override methods +'name' and 'log' in the \code{Template} instance or it will interfere with +Webware's logging. However, it {\em is} OK to use those variables in a higher +namespace, since Webware doesn't know about Cheetah namespaces. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Missing Values} +\label{language.namemapper.missing} + +If NameMapper can not find a Python value for a Cheetah variable name, it will +raise the NameMapper.NotFound exception. You can use the \code{\#errorCatcher} +directive (section \ref{errorHandling.errorCatcher}) or {\bf errorCatcher} +Template constructor argument (section \ref{howWorks.constructing}) to specify +an alternate behaviour. BUT BE AWARE THAT errorCatcher IS ONLY INTENDED FOR +DEBUGGING! + +To provide a default value for a placeholder, write it like this: +\code{\$getVar('varName', 'default value')}. If you don't specify a default +and the variable is missing, \code{NameMapper.NotFound} will be raised. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Directive Syntax Rules} +\label{language.directives.syntax} + + +Directive tags begin with a hash character (\#) and are used for comments, +loops, conditional blocks, includes, and all other advanced features. Cheetah +uses a Python-like syntax inside directive tags and understands any valid +Python expression. {\bf However, unlike Python, Cheetah does not use colons +(:) and indentation to mark off multi-line directives.} That doesn't work in +an environment where whitespace is significant as part of the text. Instead, +multi-line directives like \code{\#for} have corresponding closing tags +(\code{\#end for}). Most directives are direct mirrors of Python statements. + +Many directives have arguments after the opening tag, which must be in the +specified syntax for the tag. All end tags have the following syntax: +\begin{verbatim} +#end TAG_NAME [EXPR] +\end{verbatim} +The expression is ignored, so it's essentially a comment. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Directive closures and whitespace handling} +\label{language.directives.closures} +Directive tags can be closed explicitly with \code{\#}, or implicitly with the +end of the line if you're feeling lazy. + +\begin{verbatim} +#block testBlock # +Text in the body of the +block directive +#end block testBlock # +\end{verbatim} +is identical to: +\begin{verbatim} +#block testBlock +Text in the body of the +block directive +#end block testBlock +\end{verbatim} + +When a directive tag is closed explicitly, it can be followed with other text on +the same line: + +\begin{verbatim} +bah, bah, #if $sheep.color == 'black'# black#end if # sheep. +\end{verbatim} + +When a directive tag is closed implicitly with the end of the line, all trailing +whitespace is gobbled, including the newline character: +\begin{verbatim} +""" +foo #set $x = 2 +bar +""" +outputs +""" +foo bar +""" + +while +""" +foo #set $x = 2 # +bar +""" +outputs +""" +foo +bar +""" +\end{verbatim} + +When a directive tag is closed implicitly AND there is no other text on the +line, the ENTIRE line is gobbled up including any preceeding whitespace: +\begin{verbatim} +""" +foo + #set $x = 2 +bar +""" +outputs +""" +foo +bar +""" + +while +""" +foo + - #set $x = 2 +bar +""" +outputs +""" +foo + - bar +""" +\end{verbatim} + +The \code{\#slurp} directive (section \ref{output.slurp}) also gobbles up +whitespace. + +Spaces outside directives are output {\em exactly} as written. In the +black sheep example, there's a space before ``black'' and another before +``sheep''. So although it's legal to put multiple directives on one line, +it can be hard to read. + +\begin{verbatim} +#if $a# #echo $a + 1# #end if + - There's a space between each directive, + or two extra spaces total. +#if $a##echo $a + 1##end if + - No spaces, but you have to look closely + to verify none of the ``##'' are comment markers. +#if $a##echo $a + 1##end if ### A comment. + - In ``###'', the first ``#'' ends the directive, + the other two begin the comment. (This also shows + how you can add extra whitespace in the directive + tag without affecting the output.) +#if $a##echo $a + 1##end if # ## A comment. + - More readable, but now there's a space before the + comment. +\end{verbatim} + +% Local Variables: +% TeX-master: "users_guide" +% End: + +% # vim: sw=4 ts=4 expandtab diff --git a/docs/users_guide_src/libraries.tex b/docs/users_guide_src/libraries.tex new file mode 100755 index 0000000..dc9231a --- /dev/null +++ b/docs/users_guide_src/libraries.tex @@ -0,0 +1,306 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Batteries included: templates and other libraries} +\label{libraries} + +Cheetah comes ``batteries included'' with libraries of templates, functions, +classes and other objects you can use in your own programs. The different +types are listed alphabetically below, followed by a longer description of +the SkeletonPage framework. Some of the objects are classes for specific +purposes (e.g., filters or error catchers), while others are standalone and +can be used without Cheetah. + +If you develop any objects which are generally useful for Cheetah sites, +please consider posting them on the wiki with an announcement on the mailing +list so we can incorporate them into the standard library. That way, all +Cheetah users will benefit, and it will encourage others to contribute their +objects, which might include something you want. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{ErrorCatchers} +\label{libraries.ErrorCatchers} + +Module \code{Cheetah.ErrorCatchers} contains error-handling classes suitable for +the \code{\#errorCatcher} directive. These are debugging tools that are not +intended for use in production systems. See section +\ref{errorHandling.errorCatcher} for a description of the error catchers bundled +with Cheetah. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{FileUtils} +\label{libraries.FileUtils} + +Module \code{Cheetah.FileUtils} contains generic functions and classes for +doing bulk search-and-replace on several files, and for finding all the files +in a directory hierarchy whose names match a glob pattern. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Filters} +\label{libraries.Filters} + +Module \code{Filters} contains filters suitable for the \code{\#Filter} +directive. See section \ref{output.filter} for a description of the +filters bundled with Cheetah. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{SettingsManager} +\label{libraries.SettingsManager} + +The \code{SettingsManager} class in the \code{Cheetah.SettingsManager} module is +a baseclass that provides facilities for managing application settings. It +facilitates the use of user-supplied configuration files to fine tune an +application. A setting is a key/value pair that an application or component +(e.g., a filter, or your own servlets) looks up and treats as a configuration +value to modify its (the component's) behaviour. + +SettingsManager is designed to: +\begin{itemize} +\item work well with nested settings dictionaries of any depth +\item read/write \code{.ini style config files} (or strings) +\item read settings from Python source files (or strings) so that + complex Python objects can be stored in the application's settings + dictionary. For example, you might want to store references to various + classes that are used by the application, and plugins to the application + might want to substitute one class for another. +\item allow sections in \code{.ini config files} to be extended by settings in + Python src files. If a section contains a setting like + ``\code{importSettings=mySettings.py}'', \code{SettingsManager} will merge + all the settings defined in ``\code{mySettings.py}'' with the settings for + that section that are defined in the \code{.ini config file}. +\item maintain the case of setting names, unlike the ConfigParser module +\end{itemize} + +Cheetah uses \code{SettingsManager} to manage its configuration settings. +\code{SettingsManager} might also be useful in your own applications. See the +source code and docstrings in the file \code{src/SettingsManager.py} for more +information. + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Templates} +\label{libraries.templates} + +Package \code{Cheetah.Templates} contains stock templates that you can +either use as is, or extend by using the \code{\#def} directive to redefine +specific {\bf blocks}. Currently, the only template in here is SkeletonPage, +which is described in detail below in section +\ref{libraries.templates.skeletonPage}. (Contributed by Tavis Rudd.) + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Tools} +\label{libraries.Tools} + +Package \code{Cheetah.Tools} contains functions and classes contributed by third +parties. Some are Cheetah-specific but others are generic and can be used +standalone. None of them are imported by any other Cheetah component; you can +delete the Tools/ directory and Cheetah will function fine. + +Some of the items in Tools/ are experimental and have been placed there just to +see how useful they will be, and whether they attract enough users to make +refining them worthwhile (the tools, not the users :). + +Nothing in Tools/ is guaranteed to be: (A) tested, (B) reliable, (C) immune +from being deleted in a future Cheetah version, or (D) immune from +backwards-incompatable changes. If you depend on something in Tools/ on a +production system, consider making a copy of it outside the Cheetah/ directory +so that this version won't be lost when you upgrade Cheetah. Also, learn +enough about Python and about the Tool so that you can maintain it and bugfix +it if necessary. + +If anything in Tools/ is found to be necessary to Cheetah's operation (i.e., if +another Cheetah component starts importing it), it will be moved to the +\code{Cheetah.Utils} package. + +Current Tools include: +\begin{description} +\item{Cheetah.Tools.MondoReport} an ambitious class useful when + iterating over records of data (\code{\#for} loops), displaying one + pageful of records at a time (with previous/next links), and printing + summary statistics about the records or the current page. See + \code{MondoReportDoc.txt} in the same directory as the module. Some + features are not implemented yet. \code{MondoReportTest.py} is a test + suite (and it shows there are currently some errors in MondoReport, hmm). + Contributed by Mike Orr. + +\item{Cheetah.Tools.RecursiveNull} Nothing, but in a friendly way. Good + for filling in for objects you want to hide. If \code{\$form.f1} is a + RecursiveNull object, then \code{\$form.f1.anything["you"].might("use")} + will resolve to the empty string. You can also put a \code{RecursiveNull} + instance at the end of the searchList to convert missing values to '' + rather than raising a \code{NotFound} error or having a (less efficient) + errorCatcher handle it. Of course, maybe you prefer to get a + \code{NotFound} error... Contributed by Ian Bicking. + +\item{Cheetah.Tools.SiteHierarchy} Provides navigational links to this + page's parents and children. The constructor takes a recursive list of + (url,description) pairs representing a tree of hyperlinks to every page in + the site (or section, or application...), and also a string containing the + current URL. Two methods 'menuList' and 'crumbs' return output-ready HTML + showing an indented menu (hierarchy tree) or crumbs list (Yahoo-style bar: + home > grandparent > parent > currentURL). Contributed by Ian Bicking. + +\item +\end{description} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Utils} +\label{libraries.Utils} + +Package \code{Cheetah.Utils} contains non-Cheetah-specific functions and +classes that are imported by other Cheetah components. Many of these utils can +be used standalone in other applications too. + +Current Utils include: +\begin{description} +\item{Cheetah.Utils.CGIImportMixin} This is inherited by \code{Template} + objects, and provides the method, \code{.cgiImport} method + (section \ref{webware.cgiImport}). + +\item{Cheetah.Utils.Misc} A catch-all module for small functions. + \begin{description} + \item{\code{UseOrRaise(thing, errmsg='')}} Raise 'thing' if it's a + subclass of Exception, otherwise return it. Useful when one + argument does double duty as a default value or an exception to + throw. Contribyted by Mike Orr. + + \item{\code{checkKeywords(dic, legalKeywords, what='argument'}} + Verifies the dictionary does not contain any keys not listed in + 'legalKeywords'. If it does, raise TypeError. Useful for + checking the keyword arguments to a function. Contributed by + Mike Orr. + \end{description} + +\item{Cheetah.Utils.UploadFileMixin} Not implemented yet, but will contain + the \code{.uploadFile} method (or three methods) to ``safely'' copy a + form-uploaded file to a local file, to a searchList variable, or return + it. When finished, this will be inherited by \code{Template}, allowing + all templates to do this. If you want this feature, read the docstring + in the source and let us know on the mailing list what you'd like this + method to do. Contributed by Mike Orr. + +\item{Cheetah.Utils.VerifyType} Functions to verify the type of a + user-supplied function argument. Contributed by Mike Orr. +\end{description} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsubsection{Cheetah.Templates.SkeletonPage} +\label{libraries.templates.skeletonPage} + +A stock template class that may be useful for web developers is defined in +the \code{Cheetah.Templates.SkeletonPage} module. The \code{SkeletonPage} +template class is generated from the following Cheetah source code: + +\begin{verbatim} +##doc-module: A Skeleton HTML page template, that provides basic structure and utility methods. +################################################################################ +#extends Cheetah.Templates._SkeletonPage +#implements respond +################################################################################ +#cache id='header' +$docType +$htmlTag +<!-- This document was autogenerated by Cheetah(http://CheetahTemplate.org). +Do not edit it directly! + +Copyright $currentYr - $siteCopyrightName - All Rights Reserved. +Feel free to copy any javascript or html you like on this site, +provided you remove all links and/or references to $siteDomainName +However, please do not copy any content or images without permission. + +$siteCredits + +--> + + +#block writeHeadTag +<head> +<title>$title</title> +$metaTags +$stylesheetTags +$javascriptTags +</head> +#end block writeHeadTag + +#end cache header +################# + +$bodyTag + +#block writeBody +This skeleton page has no flesh. Its body needs to be implemented. +#end block writeBody + +</body> +</html> +\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{\$*<interval>*variable}, where \code{<interval>} 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} +<HTML> +<HEAD><TITLE>$title</TITLE></HEAD> +<BODY> + +$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. + +</BODY> +</HTML> +\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{\$*<interval>*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{\$*<interval>*}. 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{<PRE>} 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 <PRE> 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 |