Permalink
Browse files

Revert "Delete the "old" docs directory to make way for fancy smancy …

…sphinx"

This reverts commit 5dc95cf.
  • Loading branch information...
1 parent e43765a commit d9ce7916e309e2393d824e249f512d2629e5e181 @rtyler rtyler committed Nov 17, 2009
Showing with 16,663 additions and 0 deletions.
  1. +122 −0 docs/COPYING
  2. +546 −0 docs/OnePageTutorial.html
  3. +15 −0 docs/README
  4. +46 −0 docs/TODO
  5. +38 −0 docs/devel_guide_src/Makefile
  6. +9 −0 docs/devel_guide_src/README
  7. +7 −0 docs/devel_guide_src/bnf.tex
  8. +365 −0 docs/devel_guide_src/cache.tex
  9. +100 −0 docs/devel_guide_src/comments.tex
  10. +8 −0 docs/devel_guide_src/compiler.tex
  11. +102 −0 docs/devel_guide_src/design.tex
  12. +55 −0 docs/devel_guide_src/devel_guide.tex
  13. +8 −0 docs/devel_guide_src/documenting.tex
  14. +309 −0 docs/devel_guide_src/errorHandling.tex
  15. +11 −0 docs/devel_guide_src/files.tex
  16. +360 −0 docs/devel_guide_src/flowControl.tex
  17. +92 −0 docs/devel_guide_src/history.tex
  18. +232 −0 docs/devel_guide_src/inheritanceEtc.tex
  19. +29 −0 docs/devel_guide_src/introduction.tex
  20. +282 −0 docs/devel_guide_src/output.tex
  21. +9 −0 docs/devel_guide_src/parser.tex
  22. +61 −0 docs/devel_guide_src/parserInstructions.tex
  23. +134 −0 docs/devel_guide_src/patching.tex
  24. +478 −0 docs/devel_guide_src/placeholders.tex
  25. +246 −0 docs/devel_guide_src/pyModules.tex
  26. +44 −0 docs/devel_guide_src/safeDelegation.tex
  27. +11 −0 docs/devel_guide_src/template.tex
  28. +451 −0 docs/howto_extras/comparisions.txt
  29. +291 −0 docs/users_guide_2_src/01_introduction.txt
  30. +66 −0 docs/users_guide_2_src/02_glossary.txt
  31. +262 −0 docs/users_guide_2_src/03_gettingStarted.txt
  32. +369 −0 docs/users_guide_2_src/04_howItWorks.txt
  33. +651 −0 docs/users_guide_2_src/05_language.txt
  34. 0 docs/users_guide_2_src/05_placeholders_and_the_namemapper.txt
  35. +99 −0 docs/users_guide_2_src/06_comments.txt
  36. +548 −0 docs/users_guide_2_src/07_output.txt
  37. +564 −0 docs/users_guide_2_src/08_inheritanceEtc.txt
  38. +414 −0 docs/users_guide_2_src/09_flowControl.txt
  39. +145 −0 docs/users_guide_2_src/10_errorHandling.txt
  40. +116 −0 docs/users_guide_2_src/11_parserInstructions.txt
  41. +1 −0 docs/users_guide_2_src/12_moduleFormatting.txt
  42. +549 −0 docs/users_guide_2_src/13_tipsAndTroubleshooting.txt
  43. +109 −0 docs/users_guide_2_src/13a_precompiledTemplateModules.txt
  44. +582 −0 docs/users_guide_2_src/14_webware.txt
  45. +95 −0 docs/users_guide_2_src/15_otherHtml.txt
  46. +17 −0 docs/users_guide_2_src/16_nonHtml.txt
  47. +306 −0 docs/users_guide_2_src/17_libraries.txt
  48. +39 −0 docs/users_guide_2_src/18_editors.txt
  49. +112 −0 docs/users_guide_2_src/A_links.txt
  50. +24 −0 docs/users_guide_2_src/B_examples.txt
  51. +451 −0 docs/users_guide_2_src/C_comparisions.txt
  52. +32 −0 docs/users_guide_2_src/E_license.txt
  53. +16 −0 docs/users_guide_2_src/Makefile
  54. +293 −0 docs/users_guide_2_src/default.css
  55. +11 −0 docs/users_guide_2_src/eg_1.py
  56. +10 −0 docs/users_guide_2_src/eg_2.py
  57. +18 −0 docs/users_guide_2_src/eg_3.py
  58. +22 −0 docs/users_guide_2_src/eg_4.py
  59. +25 −0 docs/users_guide_2_src/eg_5.py
  60. +45 −0 docs/users_guide_2_src/latex2rst.py
  61. +67 −0 docs/users_guide_2_src/unused.txt
  62. +39 −0 docs/users_guide_src/Makefile
  63. +9 −0 docs/users_guide_src/README
  64. +99 −0 docs/users_guide_src/comments.tex
  65. +451 −0 docs/users_guide_src/comparisons.tex
  66. +39 −0 docs/users_guide_src/editors.tex
  67. +145 −0 docs/users_guide_src/errorHandling.tex
  68. +24 −0 docs/users_guide_src/examples.tex
  69. +414 −0 docs/users_guide_src/flowControl.tex
  70. +266 −0 docs/users_guide_src/gettingStarted.tex
  71. +96 −0 docs/users_guide_src/glossary.tex
  72. +420 −0 docs/users_guide_src/howItWorks.tex
  73. +492 −0 docs/users_guide_src/inheritanceEtc.tex
  74. +392 −0 docs/users_guide_src/introduction.tex
  75. +651 −0 docs/users_guide_src/language.tex
  76. +306 −0 docs/users_guide_src/libraries.tex
  77. +112 −0 docs/users_guide_src/links.tex
  78. +197 −0 docs/users_guide_src/moreverb.sty
  79. +17 −0 docs/users_guide_src/nonHtml.tex
  80. +43 −0 docs/users_guide_src/optikLicense.tex
  81. +95 −0 docs/users_guide_src/otherHtml.tex
  82. +548 −0 docs/users_guide_src/output.tex
  83. +116 −0 docs/users_guide_src/parserInstructions.tex
  84. +544 −0 docs/users_guide_src/tipsAndTricks.tex
  85. +54 −0 docs/users_guide_src/users_guide.tex
  86. +575 −0 docs/users_guide_src/webware.tex
View
122 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.
View
546 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
+ &lt;span class=keywords&gt;$keywords&lt;/span&gt;
+#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
+
+&lt;p&gt; $content
+
+#include "authors.html"
+</pre></blockquote>
+
+Authors.html:
+<blockquote class=example><pre>
+#if $authors
+ &lt;table class=Author&gt;
+ #for $author in $authors
+ &lt;tr class=Author&gt; &lt;td class=Author&gt;
+ $author
+ &lt;/td&gt; &lt;/tr&gt;
+ #end for
+ &lt;/table&gt;
+#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>
View
15 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.
View
46 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.
View
38 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
+
View
9 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'.
View
7 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:
View
365 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:
View
100 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:
View
8 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:
View
102 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:
View
55 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:
View
8 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:
View
309 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
+===============&lt;$noValue could not be found&gt;===============
+\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:
View
11 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:
View
360 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:
View
92 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:
View
232 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}