From 1c6d2fd4cbed08baea35ad2096e4691615af077a Mon Sep 17 00:00:00 2001 From: csilvers Date: Wed, 21 Mar 2007 23:25:48 +0000 Subject: [PATCH] docs/ directory is now called doc/, to keep consistent with the p4 tree --- docs/designstyle.css | 119 ------ docs/example.html | 262 ------------ docs/howto.html | 946 ------------------------------------------- docs/index.html | 94 ----- docs/tips.html | 468 --------------------- 5 files changed, 1889 deletions(-) delete mode 100644 docs/designstyle.css delete mode 100644 docs/example.html delete mode 100644 docs/howto.html delete mode 100644 docs/index.html delete mode 100644 docs/tips.html diff --git a/docs/designstyle.css b/docs/designstyle.css deleted file mode 100644 index 8aba14b..0000000 --- a/docs/designstyle.css +++ /dev/null @@ -1,119 +0,0 @@ -/* This file is duplicated at http://www.corp.google.com/css/designstyle.css - * If you change this file, copy it to ~web/html/css/designstyle.css - */ - -body { - background-color: #ffffff; - color: black; - margin-right: 1in; - margin-left: 1in; -} - - -h1, h2, h3, h4, h5, h6 { - color: #3366ff; - font-family: sans-serif; -} -@media print { - /* Darker version for printing */ - h1, h2, h3, h4, h5, h6 { - color: #000080; - font-family: helvetica, sans-serif; - } -} - -h1 { - text-align: center; - font-size: 18pt; -} -h2 { - margin-left: -0.5in; -} -h3 { - margin-left: -0.25in; -} -h4 { - margin-left: -0.125in; -} -hr { - margin-left: -1in; -} - -/* Definition lists: definition term bold */ -dt { - font-weight: bold; -} - -address { - text-align: right; -} -/* Use the tag for bits of code and for variables and objects. */ -code,pre,samp,var { - color: #006000; -} -/* Use the tag for file and directory paths and names. */ -file { - color: #905050; - font-family: monospace; -} -/* Use the tag for stuff the user should type. */ -kbd { - color: #600000; -} -div.note p { - float: right; - width: 3in; - margin-right: 0%; - padding: 1px; - border: 2px solid #6060a0; - background-color: #fffff0; -} - -UL.nobullets { - list-style-type: none; - list-style-image: none; - margin-left: -1em; -} - -/* -body:after { - content: "Google Confidential"; -} -*/ - -/* pretty printing styles. See prettify.js */ -.str { color: #080; } -.kwd { color: #008; } -.com { color: #800; } -.typ { color: #606; } -.lit { color: #066; } -.pun { color: #660; } -.pln { color: #000; } -.tag { color: #008; } -.atn { color: #606; } -.atv { color: #080; } -pre.prettyprint { padding: 2px; border: 1px solid #888; } - -.embsrc { background: #eee; } - -@media print { - .str { color: #060; } - .kwd { color: #006; font-weight: bold; } - .com { color: #600; font-style: italic; } - .typ { color: #404; font-weight: bold; } - .lit { color: #044; } - .pun { color: #440; } - .pln { color: #000; } - .tag { color: #006; font-weight: bold; } - .atn { color: #404; } - .atv { color: #060; } -} - -/* Table Column Headers */ -.hdr { - color: #006; - font-weight: bold; - background-color: #dddddd; } -.hdr2 { - color: #006; - background-color: #eeeeee; } \ No newline at end of file diff --git a/docs/example.html b/docs/example.html deleted file mode 100644 index 8685612..0000000 --- a/docs/example.html +++ /dev/null @@ -1,262 +0,0 @@ - - - -Template Examples - - - - - - - - - -

Template Examples

-(as of 27 February 2006) -
- - -

Search Results Page

- -

Here is an example template that could be used to format a Google -search results page:

- -
-
-{{>HEADER}}
-<body bgcolor=white>
-
-{{>PAGE_HEADING}}{{!The following div must be on the same line}}<div>
-
-{{!The ONE_RESULT section displays a single search item}}
-{{#ONE_RESULT}}
-    {{! Note: there are two SUBITEM_SECTIONs. They both show or hide together}}
-    {{#SUBITEM_SECTION}}<blockquote>{{/SUBITEM_SECTION}}
-    <p><a href={{JUMP_TO_URL:html_escape}}  target=nw>{{LEAD_LINE}}</a><font size=-1>
-
-    {{#SNIPPET1_SECTION}}
-        <br>{{SNIPPET1}}
-    {{/SNIPPET1_SECTION}}
-
-    {{#SNIPPET2_SECTION}}
-        <br>{{SNIPPET2}}
-    {{/SNIPPET2_SECTION}}
-
-    {{#DESCRIPTION_SECTION}}
-        <br><span class=f>Description:</span> {{DESC}}
-    {{/DESCRIPTION_SECTION}}
-
-    {{#CATEGORY_SECTION}}
-        <br><span class=f>Category:</span> <a href={{CAT_URL:html_escape}} class=f>
-	{{CATEGORY}}</a>
-    {{/CATEGORY_SECTION}}
-
-    {{#LASTLINE_SECTION}}
-        <br><font color={{ALT_TEXT_COLOR}}>{{URL}}
-        {{#KS_SECTION}}} - {{KSIZE}}{{/KS_SECTION}}}
-        {{#CACHE_SECTION}}} - <a href={{CACHE_URL:html_escape}} class=f>Cached</A>
-	{{/CACHE_SECTION}}}
-        {{#SIM_SECTION}}} - <a href={{SIM_PAGES_URL:html_escape}} class=f>Similar pages</A>
-	{{/SIM_SECTION}}}
-
-        {{#STOCK_SECTION}}
-             -  <a href={{STOCK_URL:html_escape}} class=f>Stock quotes: {{STOCK_SYMBOL}}</a>
-        {{/STOCK_SECTION}}
-        </font>
-    {{/LASTLINE_SECTION}}           
-
-    {{#MORE_SECTION}}
-        <br>[ <a href={{MORE_URL:html_escape}} class=f>More results from {{MORE_LABEL}}</a> ]
-    {{/MORE_SECTION}}
-
-    </font><br>
-    {{! Note: there are two SUBITEM_SECTIONs. They both show or hide together}}
-    {{#SUBITEM_SECTION}}</blockquote>{{/SUBITEM_SECTION}}
-{{/ONE_RESULT}}
-</div> {{! this /div closes the div at the top of this file}}
-{{>PAGE_FOOTING}}
-
-
- -

Here is a sample procedure that could populate a dictionary for -expanding that template. The "one procedure" entry point is -fill_search_results_dictionary. The -SetTemplateValues function is a separate entry point for -initializing each top-level template with some standard values.

- -
-#include "template.h"
-
-RegisterTemplateFilename(SEARCH_RESULTS_FN, "search_results.tpl");
-#include "search_results.tpl.varnames.h"  // defines ksr_HEADER, etc.
-
-using google::Template;
-using google::TemplateDictionary;
-using google::STRIP_WHITESPACE;
-
-// IsEmpty
-//    A simple utility function
-static bool IsEmpty(const string &str) {
-  return str.empty();
-}
-
-// SetTemplateValues
-//   Use the TemplateDictionary object to set template-wide values that
-//   may be used in the top-level template and all its sub-sections
-//   and included templates. The template-wide values are all
-//   colors from the Palette object
-void SetTemplateValues(TemplateDictionary *dictionary, const Palette* colors) {
-  // better would be to use ksr_LINK_COLOR, etc, assuming those are
-  // defined in search_results.tpl.varnames.h.  But using literal
-  // text, as here, is legal as well.
-  dictionary->SetValue("LINK_COLOR", colors->link_color);
-  dictionary->SetValue("BAR_TEXT_COLOR", colors->bar_text_color);
-  dictionary->SetValue("TEXT_COLOR", colors->text_color);
-  dictionary->SetValue("FAINT_COLOR", colors->faint_color);
-  dictionary->SetValue("IMPORTANT_COLOR", colors->important_color);
-  dictionary->SetValue("BAR_COLOR", colors->bar_color);
-  dictionary->SetValue("ALT_TEXT_COLOR", colors->alt_text_color);
-  dictionary->SetValue("ALINK_COLOR", colors->alink_color);
-  dictionary->SetValue("VLINK_COLOR", colors->vlink_color);
-}
-
-// fill_search_results_dictionary
-//   Iterates through all the QueryResults contained in the Query object.
-//   For each one, it sets corresponding template dictionary values
-//   (or hides sections containing their variables, if appropriate) in
-//   a sub-dictionary and then adds that dictionary to the parent
-void fill_search_results_dictionary(TemplateDictionary *dictionary,
-                                    const Query *query) {
-  dictionary->SetFilename(SEARCH_RESULTS_FN);
-
-  // These two functions are defined elsewhere
-  fill_header_dictionary(dictionary->AddIncludeDictionary(ksr_HEADER));
-  fill_page_heading_dictionary(dictionary->AddIncludeDictionary(ksr_PAGE_HEADING),
-                               query);
-
-  ResultsList *results = query->GetResults();
-  int resCount = 0;
-
-  for (ResultsList::const_iterator iter = results->begin();
-       iter != results->end();
-       ++iter) {
-    QueryResult *qr = (*iter);
-
-    // Create a new sub-dictionary named "Result Dict " for this entry
-
-    ++resCount;
-
-    TemplateDictionary *result_dictionary =
-      dictionary->AddSectionDictionary(ksr_ONE_RESULT);
-
-    result_dictionary->SetValue(ksr_JUMP_TO_URL, qr->GetUrl());
-
-    if (qr->IsSubItem()) {
-      result_dictionary->ShowSection(ksr_SUBITEM_SECTION);
-    }
-
-    result_dictionary->SetValue(ksr_LEAD_LINE, qr->GetLeadLine());
-
-    result_dictionary->SetValueAndShowSection(ksr_SNIPPET1, qr->GetSnippet1(),
-                                              ksr_SNIPPET1_SECTION);
-    
-    result_dictionary->SetValueAndShowSection(ksr_SNIPPET2, qr->GetSnippet2(),
-                                              ksr_SNIPPET2_SECTION);
-    
-    result_dictionary->SetValueAndShowSection(ksr_DESC, qr->GetDescription(),
-                                              ksr_DESCRIPTION_SECTION);
-
-    result_dictionary->SetValueAndShowSection(ksr_CAT_URL, qr->GetCategoryUrl(),
-                                              ksr_CATEGORY_SECTION);
-
-    result_dictionary->SetValueAndShowSection("CATEGORY", qr->GetCategoryName(),
-                                              "CATEGORY_SECTION");
-
-
-    if (IsEmpty(qr->GetDisplayUrl()) &&
-        IsEmpty(qr->GetPageSize()) &&
-        IsEmpty(qr->GetCachedUrl()) &&
-        IsEmpty(qr->GetSimilarPagesUrl()) &&
-        (IsEmpty(qr->GetStockUrl()) ||
-         IsEmpty(qr->GetStockSymbol())) ) {
-      // there is nothing on the last line, so hide it altogether
-    } else {
-      result_dictionary->ShowSection("LASTLINE_SECTION");
-
-      result_dictionary->SetValue(ksr_URL, qr->GetDisplayUrl());
-
-      result_dictionary->SetValueAndShowSection(ksr_KSIZE, qr->GetPageSize(),
-                                                ksr_KS_SECTION);
-
-      result_dictionary->SetValueAndShowSection(ksr_CACHE_URL, qr->GetCachedUrl(),
-                                                ksr_CACHE_SECTION);
-
-      result_dictionary->SetValueAndShowSection(ksr_SIM_PAGES_URL,
-                                                qr->GetSimilarPagesUrl(),
-                                                ksr_SIM_SECTION);
-
-      result_dictionary->SetValueAndShowSection(ksr_STOCK_URL, qr->GetStockUrl(),
-                                                ksr_STOCK_SECTION);
-
-      result_dictionary->SetValueAndShowSection(ksr_STOCK_SYMBOL,
-                                                qr->GetStockSymbol(),
-                                                ksr_STOCK_SECTION);
-    }
-
-    result_dictionary->SetValueAndShowSection(ksr_MORE_URL, qr->GetMoreUrl(),
-                                              ksr_MORE_SECTION);
-
-    result_dictionary->SetValueAndShowSection(ksr_MORE_LABEL, qr->GetMoreLabel(),
-                                              ksr_MORE_SECTION);
-
-  }    
-
-  fill_page_footing_dictionary(dictionary->AddIncludeDictionary(ksr_PAGE_FOOTING),
-                               query);
-}        
-
-void output_page(const Query* query) {
-  Template* tpl = Template::GetTemplate(SEARCH_RESULTS_FN, STRIP_WHITESPACE);
-  TemplateDictionary dict("search-results dict");
-  string output;
-  fill_search_results_dictionary(&dict, query);
-  tpl->Expand(&output, &dict);
-  // output now holds the expanded template
-}
-
-
- - -
- - -
-
-Craig Silverstein
-27 February 2006 -
- - - diff --git a/docs/howto.html b/docs/howto.html deleted file mode 100644 index 346451b..0000000 --- a/docs/howto.html +++ /dev/null @@ -1,946 +0,0 @@ - - - - -How To Use the Google Template System - - - - - - - - - -

How To Use the Google Template System

-(as of 27 February 2006) -
- - -

Motivation

- -

A template system can be used to separate output formatting -specifications, which govern the appearance and location of output -text and data elements, from the executable logic which prepares the -data and makes decisions about what appears in the output.

- -

Template systems lie along a continuum of power versus separation. -"Powerful" constructs like variable assignment or conditional -statements make it easy to modify the look of an application within -the template system exclusively, without having to modify any of the -underlying "application logic". They do so, however, at the cost of -separation, turning the templates themselves into part of the -application logic.

- -

This template system leans strongly towards preserving the -separation of logic and presentation. It is intentionally constrained -in the features it supports and, as a result, applications tend to -require quite a bit of code to instantiate a template. This may not -be to everybody's tastes. However, while this design limits the power -of the template language, it does not limit the power or -flexibility of the template system. This system supports -arbitrarily complex text formatting. Many Google applications, -including the "main" Google web search, use this system exclusively -for formatting output.

- -

Finally, this system is designed with an eye towards efficiency. -Template instantiation is very quick, with an eye towards minimizing -both memory use and memory fragmentation.

- - -

Overview

- -

There are two parts to the Google Template System:

- -
    -
  • Templates -
  • Data dictionaries -
- -

The templates are text files that contain the format specification -for the formatted output, i.e, the template language. The data -dictionaries contain the mappings from the template elements (markers) -embedded in the templates to the data that they will format. Here's -a simple template:

-
-   <html><head><title>{{TITLE}}</title>{{META_TAGS}}</head>
-   <body>{{BODY}}</body>
-
- -

Here's a dictionary that one could use to instantiate the template:

-
-   {"TITLE": "Template example",
-    "BODY": "This is a simple template example.\nIt's boring",
-    "DATE": "11/20/2005"}
-
- -

If we instantiated the template with this dictionary, here's the -output we would get:

-
-   <html><head><title>Template example</title></head>
-   <body>This is a simple template example.
-It's boring</body></html>
-
- -

{{TITLE}} and {{{BODY}} are template -elements, also called markers. In the dictionary, -TITLE, BODY, and DATE are -dictionary names, and the values associated with each one, such -as 11/20/2005, are dictionary values.

- -

A few points are clear even from this simple example:

-
    -
  1. Dictionary keys and values are strings; the Google template - system is not typed.
  2. -
  3. Dictionary values come already formatted. It was up to the - application code to decide how to format the value for - DATE, and to insert the date into the dictionary - already formatted.
  4. -
  5. Not all dictionary values must be used by a templete. - DATE is entirely ignored.
  6. -
  7. Not all template elements may exist in the dictionary. In this - example, {{META_TAGS}} is not found in the - dictionary. This is perfectly legal; missing variable markers - evaluate to the empty string.
  8. -
- - -

Templates

- -

The template language has four types of markers:

-
    -
  1. VARIABLE markers, which are replaced by text based on - dictionary values. All markers in the above example are - variable markers. Variable markers look like this: - {{VARIABLE}}
  2. - -
  3. START SECTION and END SECTION markers, which delimit - sections which may appear zero, one, or N times in - the output. The number of times a section appears is - determined by the data dictionaries, as explained below. - Each time a section is expanded, it uses a different - dictionary, so that the output values may be different from one - iteration of a section expansion to another. Note that the - specification of how sections expand is entirely dependent on - the dictionary, as set up by the application; there is no way - to specify a repeat rate in the template language itself. - Section markers look like this: - {{#SECTION_NAME}}...{{/SECTION_NAME}}
  4. - -
  5. TEMPLATE-INCLUDE markers, which designate other templates to be - expanded and inserted at the location where the marker appears. - These are treated much like sections -- one may think of them - as sections whose content is specified in a - different file instead of inline -- and just like sections, can - be expanded zero, one or N times in the output, each with a - different dictionary. Template-include markers look like this: - {{>FILENAME}}
  6. - -
  7. COMMENT markers, which may annotate the template - structure but drop completely out of the expanded - output. Comment markers look like this: - {{! comment lives here -- cool, no?}}
  8. -
- -

These marker types each have their own namespace. For readability, -however, it is best to not overuse a single name.

- -

Anything found in a template of the form {{...}} is -interpreted as a template marker. All other text is considered -formatting text and is output verbatim at template expansion time. -Formatting text may consist of HTML tags, XML tags, linefeeds and -other spacing characters, constant text, etc.

- - -

Data Dictionaries

- -

A data dictionary is a map from keys to values. The keys are -always strings, each string representing either a variable, a section, -or a template-include file. (Comments are not stored in the data -dictionary!) These values correspond to the name of the associated -template marker: a section {{#FOO}} in the template text -is matched to the key "FOO" in the dictionary, if it -exists. Note the case must match as well.

- -

The value associated with a key differs according to key type. The -value associated with a variable is simple: it's the value for -that variable. (Niggly implementation note: this value may not have -internal NUL -- that is, \0 -- characters. It's a TODO to allow this -one day.)

- -

The value associated with a section is more complicated, and -somewhat recursive: it's a list of data dictionaries. Come -template-expansion time, the section is expanded once for each -dictionary in the list, so if there are two dictionaries in the list, -then the section text will occur in the output twice. The first time, -all variables/etc. in the section will be evaluated taking into -account the first dictionary. The second time, all -variables/etc. will be evaluated taking into account the second -dictionary. (See below for a definition of -"taking into account.")

- -

A template-include is a special type of section, so the -associated value is the same: a list of dictionaries. -Template-includes also have one other, mandatory associated piece of -information: the filename of the template to include. This filename -may be specified either as an absolute path, or as a relative path. -(In the latter case, the path is taken relative to the -template_root, as set by the -application.)

- -

The application program is responsible for building this data -dictionary, including all nesting. It then applies this dictionary to -a single template to produce formatted output.

- - -

Expanding a Template

- -

A program using Google Templates typically reads in templates at -load time. During the course of program execution, the program will -repeatedly perform the following two steps: first, instantiate a data -dictionary, and second, apply the dictionary to the template to -produce output.

- -

The template system applies a dictionary to a template by finding -all template markers in the template, and replacing them with the -appropriate dictionary values. It matches template markers to -dictionary keys in the obvious way. For instance, a template marker -{{FOO}} matches the dictionary key FOO. -{{FOO:html_escape}} matches FOO as well. The -marker {{#BAR}} matches the dictionary key -BAR, as does the marker {{/BAR}}. The -marker {{>BAZ}} matches the dictionary key -BAZ. (And of course, the marker {{! -comment}} doesn't match any dictionary key at all.)

- -

Template-variables can also have modifiers. In that case, the template-system -starts by finding the appropriate value for that variable in the -dictionary, just like normal. Then it applies each modifier to the -variable, left to right. Finally, it emits the modified value to the -output.

- -

If no dictionary key is found for a given template marker, then the -template marker is ignored: if a variable, it expands to the empty -string; if a section or include-template, the section or -include-template is expanded zero times.

- -

All names are case sensitive. Names -- that is, variable keys and, -as a result, template markers -- must be made of (7-bit ascii) -alphanumeric characters and the underscore. The commment marker, -which does not map to dictionary keys, may contain any chararacters -whatsoever except }, the close-curly brace. It's a -syntax error for any template marker to violate this rule.

- -

Outside of the template markers, templates may contain any text -whatsoever, including (single) curly braces and NUL characters.

- - -

Variable Modifiers

- -

Recall that variables look like this: {{VARNAME}}. We -actually allow a more generic form: the variable name may be followed -by one or more modifiers. A modifier is a filter that's -applied at template-expand time, that munges the value of the variable -before it's output. For instance, consider a template that looks like -this:

-
-   <html><body>{{NAME:html_escape}}</body></html>
-
- -

This asks the template system to apply the built-in -html_escape modifier when expanding -{{NAME}}. If you set NAME in your -dictionary to be Jim & Bob, what will actually be -emitted in the template is Jim &amp; Bob.

- -

You can chain modifiers together. This template first html-escapes -NAME, and then javascript-escapes that result:

-
-   <html><body>{{NAME:html_escape:javascript_escape}}</body></html>
-
- -

Modifiers typically have a long, descriptive name and also a -one-letter abbreviation. So this example is equivalent to the -previous one:

-
-   <html><body>{{NAME:h:j}}</body></html>
-
- -

Only the modifiers built in to the template system may be used: -It is not possible at the time for users to register modifiers. Here -are the modifiers that are supported:

- - - - - - - - - - -
long nameshort namedescription
:html_escape:hhtml-escapes the variable before output - (eg & -> &amp)
:javascript_escape:jjavascript-escapes the variable before output - (eg " -> \")
- - -

Details on Dictionary Lookup

- -

The dictionary structure is a tree: there's a 'main' dictionary, -and then sub-dictionaries for each section or include-template. Even -with all this complexity, the lookup rules are mostly straightforward: -when looking up a marker -- be it a variable, section, or -include-template marker -- the system looks in the currently -applicable dictionary. If it's found there, great. If not, and the -parent dictionary is not an include-template, it continues the look in -the parent dictionary, and possibly the grandparent, etc. That is, -lookup has static scoping: you look in your dictionary and any -parent dictionary that is associated with the same template-file. As -soon as continuing the lookup would require you to jump to a new -template-file (which is what include-template would do), we stop the -lookup.

- -

For instance, for a template that says -{{#RESULTS}}{{RESULTNUM}}. {{>ONE_RESULT}}{{#RESULTS}}, -"ONE_RESULT" is looked for in the "RESULTS" dictionary, -and if not found there, is looked for in the main, top-level -dictionary. Likewise, the variable "RESULTNUM" is looked -for first in the "RESULTS" dictionary, then in the main dictionary if -necessary. However, "ONE_RESULT" will not do equivalent cascading -lookups. In fact, it will have no parent dictionaries at all, because -it's a different template file and thus in a different scope.

- -

Because of these scoping rules, it's perfectly reasonable to set -all variables that are needed in a given template file, in the -top-level dictionary for that template. In fact, the ShowSection() function is provided to -support just this idiom. To avoid confusion in such a usage mode, -it's strongly encouraged that you give unique names to all sections -and include-templates in a single template file. (It's no problem, -given the template scoping rules, for a single section or -include-template name to be repeated across different template -files.)

- -

There's a single special case: the global variable -dictionary. Every dictionary inherits its initial set of values -from the global dictionary. Clients can set -variables in the global dictionary just like they can in normal -template dictionaries they create.

- -

The system initializes the global dictionary with a few useful -values for your convenience. All system variables are prefixed with -BI, to emphasize they are "built in" variables.

-
    -
  • BI_SPACE, which has the value - <space>. It is used to force a space - at the beginning or end of a line in the template, - where it would normally be suppressed. (See below.)
  • - -
  • BI_NEWLINE, which has the value - <newline> It is used to force a - newline at the end of a line, where it would normally - be suppressed. (See below.)
  • -
- -

As is usual for inheritence, if a user explicitly assigns a value -to these variable-names in its own dictionary, this overrides the -inherited value. So, dict->SetValue("BI_SPACE", -"&nbsp;") causes BI_SPACE to have the value -&nbsp;, rather than <space>, when -expanding dict.

- -

Note that only variables can be inherited from the global -dictionary, not section dictionaries or include-file dictionaries.

- -

A couple of small implementation notes: global inheritence is "last -chance", so if a section's parent dictionary redefined -BI_SPACE, say, the section dictionary inherits the -parent-dict value, not the global-dict value. Second, variable -inheritence happens at expand time, not at dictionary-create time. So -if you create a section dictionary, and then afterwards set a variable -in its parent dictionary (or in the global dictionary), the section -will inherit that variable value, if it doesn't define the -value itself.

- - -

Writing Application Code To Use Templates

- -

Most application code concerns filling a template dictionary, but -there is also code for loading templates themselves from disk. A -final category of code lets you inspect and control the template -system.

- -

The code below assumes the default configuration option of putting -all template code in namespace google. - - -

Loading A Template

- -

The main routine to load a template is -google::Template::GetTemplate(), defined in -template.h. This is a static, factory method, that loads -a template from either disk or from an internal template cache, and -returns a pointer to a Template object. Besides a -filename to load from, this routine takes a 'strip' argument which -defines how to expand whitespace found in a template file. It can -have one of the following values:

- -
    -
  • google::DO_NOT_STRIP: do nothing. This expands the - template file verbatim. - -
  • google::STRIP_BLANK_LINES: remove all blank - lines when expanding. This ignores any blank lines found in - the template file when expanding. When the template is html, - this reduces the size of the output text without requiring a - sacrifice of readability for the input file. - -
  • google::STRIP_WHITESPACE: remove not only blank lines when - expanding, but also whitespace at the beginning and end of each - line. It also removes any linefeed (possibly following - whitespace) that follows a closing '}}' of any kind of template - marker except a template variable. (This means a - linefeed may be removed anywhere by simply placing a comment - marker as the last element on the line.) When the template is - html, this reduces the size of the output html without changing - the way it renders (except in a few special cases). When using - this flag, the built-in template variables - BI_NEWLINE and BI_SPACE can be useful - to force a space or newline in a particular situation. -
- -

This factory method returns NULL if the template cannot be found, -or if there is a syntax error trying to load it.

- -

Besides loading templates, the application can also ask the -template system to reload a template, via -template->ReloadIfChanged(). (You can also reload all -templates at once via google::Template::ReloadAllIfChanged().) -ReloadIfChanged() looks on disk, and if it notices the -template file has changed since the last load, it will reload the -template from disk, replacing the old contents. Actually, the reload -is done lazily: ReloadIfChanged just sets a bit that -causes the template to be reloaded next time GetTemplate -is called.

- - -

Creating A Template Dictionary

- -

The class google::TemplateDictionary is used for all template -dictionary operations. new google::TemplateDictionary(name) is -used to create a new top-level dictionary. -dict->AddSectionDictionary(name) and -dict->AddIncludeDictionary(name) are used to create -sub-dictionaries for sections or include-files. After -creating a dictionary, the application should call one or more -functions for each marker in the template. As an example, consider -the following template: -

-<html><body> {{! This page has no head section.}}
-{{#CHANGE_USER}}
-<A HREF="/login">Click here</A> if you are not {{USERNAME}}<br>
-{{/CHANGE_USER}}
-
-Last five searches:<ol>
-{{#PREV_SEARCHES}
-<li> {{PREV_SEARCH}}
-{{/PREV_SEARCH}}
-</ol>
-
-{{>RESULT_TEMPLATE}}
-
-{{FOOTER}}
-</body></html>
-
- -

To instantiate the template, the user should call a function to set -up FOOTER, and a function to say what to do for the -sections CHANGE_USER and PREV_SEARCHES, and -for the include-template RESULT_TEMPLATE. Quite likely, -the application will also want to create a sub-dictionary for -CHANGE_USER, and in that sub-dictionary call a function -to set up USERNAME. There will also be sub-dictionaries -for PREV_SEARCHES, each of which will need to set -PREV_SEARCH. Only when this is all set up will the -application be able to apply the dictionary to the template to get -output.

- -

The appropriate function to call for a given template marker -depends on its type.

- -

Variables

- -

For variables, the only interesting action is to set the variable's -value. For most variables, the right method to call is -dict->SetValue(name, value). (The name and value -can be specified as strings in a variety of ways: C++ strings, char -*'s, or char *'s plus length.) You can also call -google::TemplateDictionary::SetGlobalValue(name, value) -- no -TemplateDictionary instance needed here -- to set a -variable that can be used by all templates in an applications. This is -quite rare.

- -

In addition to SetValue(), there are a few helper -routines to help setting values of a few special forms.

- -
    -
  • SetIntValue(name, int): takes an int as the value.
  • -
  • SetEscapedValue(name, value, escape_functor): - escapes the value, using the escape-functor, which takes a - string as input and gives a "munged" string as output. - TemplateDictionary has a few escape-functors built - in, including html_escape, which replaces - <, >, &, and - " with the appropriate html entity; - xml_escape, which deals with the - &nbsp; entity; and - javascript_escape, which escapes quotes and other - characters that are meaningful to javascript. These are - helpful in avoiding security holes when the template is - html/xml/javascript. You can also define your own functor; see - the example below.
  • -
  • SetFormattedValue(name, fmt, ...): the - fmt and ... work just like in - printf: SetFormattedValue("HOMEPAGE", - "http://%s/", hostname).
  • -
  • SetEscapedFormattedValue(name, escape_functor, fmt, - ...): formats the value just like printf, - and then escapes the result using the given functor.
  • -
- -

Example:

-
-   google::TemplateDictionary* dict = new google::TemplateDictionary("var example");
-   dict->SetValue("FOOTER", "Aren't these great results?");
-   class StarEscape { string operator()(const string& in) const { return string("*") + in + string("*"); } };
-   dict->SetEscapedValue("USERNAME", username, StarEscape());
-
- -

Note that the template itself can also specify escaping via variable modifiers! It's very possible for you -to escape the value when setting it in the dictionary, and then have -the template escape it again when outputting, so be careful you escape -only as much as you need to.

- -

Sections

- -

Sections are used in two ways in templates. One is to expand some -text multiple times. This is how PREV_SEARCHES is used -in the example above. In this case we'll have one small -sub-dictionary for each of the five previous searches the user did. -To do this, call AddSectionDictionary(section_name) -to create the sub-dictionary. It returns a -TemplateDictionary* that you can use to fill the -sub-dictionary. - -

The other use of sections is to conditionally show or hide a block -of text at template-expand time. This is how CHANGE_USER -is used in the example template: if the user is logged in, we show the -section with the user's username, otherwise we choose not to show the -section.

- -

This second case is a special case of the first, and the "standard" -way to show a section is to expand it exactly one time, by calling -AddSectionDictionary() once, and then setting -USERNAME in the sub-dictionary.

- -

However, the hide/show idiom is so common there are a few -convenience methods to make it simpler. The first takes advantage of -the fact sections inherit variables from their parent: you set -USERNAME in the parent dictionary, rather than a section -sub-dictionary, and then call ShowSection(), which adds a -single, empty dictionary for that section. This causes the section to -be shown once, and to inherit all its variable values from its -parent.

- -

A second convenience method is written for the particular case we -have with USERNAME: if the user's username is non-empty, -we wish to -show the section with USERNAME set to the username, -otherwise we wish to hide the section and show neither -USERNAME nor the text around it. The method -SetValueAndShowSection(name, value, section_name) does -exactly that: if value is non-empty, add a single single dictionary to -section_name and call section_dict->AddValue(name, -value). There's also SetEscapedValueAndShowSection(name, -value, escape_functor, section_name), which lets you escape -value.

- -

Example:

-
-   using google::TemplateDictionary;
-   TemplateDictionary* dict = new TemplateDictionary("section example");   
-   const char* username = GetUsername();   // returns "" for no user
-   if (username[0] != '\0') {
-      TemplateDictionary* sub_dict = dict->AddSectionDictionary("CHANGE_USER");
-      sub_dict->SetValue("USERNAME", username);
-   } else {
-      // don't need to do anything; we want a hidden section, which is the default
-   }
-
-   // Instead of the above 'if' statement, we could have done this:
-   if (username[0] != '\0') {
-      dict->ShowSection("CHANGE_USER");       // adds a single, empty dictionary
-      dict->SetValue("USERNAME", username);   // take advantage of inheritence
-   } else {
-      // don't need to do anything; we want a hidden section, which is the default
-   }
-
-   // Or we could have done this:
-   dict->SetValueAndShowSection("USERNAME", username, "CHANGE_USER");
-
-   // Moving on...
-   GetPrevSearches(prev_searches, &num_prev_searches);
-   if (num_prev_searches > 0) {
-      for (int i = 0; i < num_prev_searches; ++i) {
-         TemplateDictionary* sub_dict = dict->AddSectionDictionary("CHANGE_USER");
-         sub_dict->SetEscapedValue("PREV_SEARCH", prev_searches[i],
-                                   TemplateDictionary::html_escape);
-      }
-   }
-
- -

Template-includes

- -

Template-include markers are much like section markers, so -SetIncludeDictionary(name) acts, not surprisingly, -exactly like SetSectionDictionary(name). However, since -variable inheritence doesn't work across include boundaries, there is -no template-include equivalent to ShowSection() or -SetValueAndShowSection().

- -

One difference bewteen template-includes and sections is that for a -sub-dictionary that you create via -SetIncludeDictionary(), you must call -subdict->SetFilename() to indicate the name of the -template to include. If you do not set this, the sub-dictionary will -be ignored. The filename may be absolute, or relative, in which case -it's relative to template_root.

- -

Example:

-
-   using google::TemplateDictionary;
-   TemplateDictionary* dict = new TemplateDictionary("include example");   
-   GetResults(results, &num_results);
-   for (int i = 0; i < num_results; ++i) {
-      TemplateDictionary* sub_dict = dict->AddIncludeDictionary("RESULT_TEMPLATE");
-      sub_dict->SetFilename("results.tpl");
-      FillResultsTemplate(sub_dict, results[i]);
-   }
-
- -

In practice, it's much more likely that -FillResultsTemplate() will be the one to call -SetFilename(). Note that it's not an error to call -SetFilename() on a dictionary even if the dictionary is -not being used for a template-include; in that case, the function is a -no-op, but is perhaps still useful as self-documenting code.

- - -

Expanding a Template

- -

Once you have a template and a template dictionary, it's simplicity -itself to expand the template with those dictionary values, putting -the output in a string:

-
-   google::Template* tpl = google::Template::GetTemplate(<filename>, google::STRIP_WHITESPACE);
-   google::TemplateDictionary dict("debug-name");
-   FillDictionary(&dict, ...);
-   string output;
-   tpl->Expand(&output, &dict);
-   // output now holds the expanded template
-
- -

The expanded template is written to the string output. -If output was not empty before calling -Expand(), the expanded template is appended to the end of -output. - - -

Getting a Template From a String Rather Than a File

- -

The TemplateFromString class, in -template_from_string.h, is an alternative to the -Template class when you really want your template to be -built in to the executable rather than read from a file. It's a -drop-in replacement, that takes an extra argument which is the -template contents.

- -

Prefer Template to TemplateFromString, -for several reasons. For one, updating the template requires merely a -data push, rather than pushing the new executable. Also, you can load -the new template without needing to restart the binary. It also makes -it easier for non-programmers to modify the template. Finally, -string-templates cannot be included by other -templates, since {{>include}} takes a filename.

- -

One reason to use TemplateFromString is if you are in -an environment where having data files could be dangerous -- for -instance, you work on a disk that is usually full, or need the -template to work even in the face of disk I/O errors.

- -

This package comes with a script, template-converter, that takes a template file -as input and emits a C++ code snippet (an .h file) that defines a -string with those template contents. This makes it easy to start by -using a normal, file-based template, and then switch to -template-from-string later if you so desire.

- - -

Working Effectively with Templates

- -

Registering Template Strings

- -

Both dictionary keys and template filenames are strings. Instead -of using raw strings, we encourage you to use a bit of machinery to -help protect against various types of errors.

- -

For dictionary keys, you can use the make_tpl_varnames_h tool to create -static string variables to use instead of a string constant. This -will protect against typos, as the make_tpl_varnames_h documentation -describes.

- -

For template filenames that a program uses -- including -sub-templates -- we suggest the following idiom:

- -
-   #include "example.tpl.varnames.h"   // defines 1 string per dictionary key
-   RegisterTemplateFilename(EXAMPLE_FN, "example.tpl");   // defines template
-   ...
-   google::Template* tpl = google::Template::GetTemplate(EXAMPLE_FN, ...);
-   ...
-   include_dict->SetFilename(EXAMPLE_FN);
-
- -

By registering the filename, you can query -the template system to detect syntax errors, reload-status, and so -forth.

- - -

Managing Templates

- -

The following functions affect the global state of the template -system.

- -
    -
  • google::Template::SetTemplateRootDirectory(root): when - GetTemplate() is called with a relative filename, - the template system will try to load the template from - root/file. This defaults to ./.
  • -
- -

There are some administrative tools that can help with tweaking -template performance and debugging template problems. The following -functions work on registered templates.

- -
    -
  • google::TemplateNameList::GetMissingList(): returns a list - of all registered templates where the file could not be found - on disk.
  • -
  • google::TemplateNameList::AllDoExist(): true iff the - missing-list is empty.
  • -
  • google::TemplateNameList::GetBadSyntaxList(): returns a - list of all registered templates where the template contains a - syntax error, and thus cannot be used.
  • -
  • google::TemplateNameList::IsAllSyntaxOkay(): true iff the - bad-syntax list is emtpy.
  • -
  • google::TemplateNameList::GetLastmodTime(): the latest - last-modified time for any registered template-file.
  • -
- -

The following functions help with debugging, by allowing you to -examine the template dictionaries and expanded templates in -more detail.

- -
    -
  • dict->Dump(): dumps the contents of the dictionary - (and any sub-dictionaries) to stderr.
  • -
  • dict->DumpToString(): dumps the contents of the - dictionary (and sub-dictionaries) to the given string.
  • -
  • dict->SetAnnotateOutput(): when applying this - dictionary to a template, add marker-strings to the output to - indicate what template-substitutions the system was making. - This takes a string argument which can be used to shorten the - filenames printed in the annotations: any filename that starts - with the string you give, that string is elided from the - filename before printing. It's confusing, but fear not: it's - safe to just always pass in the empty string.
  • -
- -

Finally, ClearCache() removes all template objects -from the cache used by GetTemplate(). Typically, this is -only used in environments that check for memory leaks: calling this at -the end of the program will clean up all memory that the template -system uses.

- - -

Template and Threads

- -

All static methods on Template and -TemplateDictionary objects are threadsafe: you can safely -call google::TemplateDictionary::SetGlobalValue() without needing -to worry about locking.

- -

Non-static methods are not thread-safe. It is not safe for two -threads to assign values to the same template-dictionary without doing -their own locking. Note that this is expected to be quite rare: -usually only one thread will care about a given -template-dictionary.

- -

For Template objects, the most common idiom is that a -template is loaded via GetTemplate(), and after that only -const methods like Expand() are called on the template. -With such usage, it's safe to use the same Template -object in multiple threads without locking. Be careful, however, if -you also call functions like ReloadIfChanged().

- - -

Development Tools

- -

This package includes several tools to make it easier to use write -and use templates.

- - -

make_tpl_varnames_h: - Template Syntax Checker and Header File Generator

- -

make_tpl_varnames_h is a "lint" style syntax checker -and header file generator. It takes the names of template files as -command line arguments and loads each file into a Template object by -retrieving the file via the Template factory method. The loading of -the file does pure syntax checking and reports such errors as -mis-matched section start/end markers, mis-matched open/close -double-curly braces, such as "{{VAR}", or invalid characters -in template variables/names/comments.

- -

If the template passes the syntax check, by default the utility -then creates a header file for use in the executable code that fills -the dictionary for the template. If the developer includes this -header file, then constants in the header file may be referenced in -the dictionary building function, rather than hard-coding strings as -variable and section names. By using these constants, the compiler -can notify the developer of spelling errors and mismatched names. -Here's an example of how this is used, and how it helps prevent -errors:

- -
-   const char * const kosr_RESULT_NUMBER = "RESULT_NUMBER";  // script output
-   dict.SetValue("RESSULT_NUMBER", "4");    // typo is silently missed
-   dict.SetValue(kosr_RESSULT_NUMBER, "4");   // compiler catches typo
-
- -

Each constant is named as follows:

- -
    -
  • The initial letter 'k', indicating a defined constant.
  • - -
  • One or more prefix letters which are derived from the - template file name. These prefix letters consist of the first - letter of the file name, followed by the first letter following - each underscore in the name, with the exception of the letter - 'p' when it is followed by the letters "ost", as is a recommended convention for - template versioning. For example, the prefix letters for the - file one_search_result_post20020815.tpl are - osr.
  • - -
  • An underscore.
  • - -
  • The varible or section name itself, same casing.
  • -
- -

As an example, the section name "RESULT_NUMBER" in the file -one_search_result_post20020815.tpl would be given the constant name -kosr_RESULT_NUMBER and would appear in the header file as -const char * const kosr_RESULT_NUMBER = "RESULT_NUMBER"; --- as in the example above.

- -

By default, the header file is produced in the current directory. -An alternate output directory may be specified -by the command line flag --header_dir. - -

The name of the generated header file is the same as the name of -the template file with an extension added to the name. By default, -that extension is .varnames.h. In the above example, the -header file containing the constant declarations would be named -one_search_result_post20020815.tpl.varnames.h. An -alternate extension may be provided via the command line flag ---outputfile_suffix. - -

Important command line flags:

- -
    -
  • --noheader -- Indicates that a header file - should not be generated; only syntax checking should be done.
  • - -
  • --header_dir -- sets the directory where the header - is written. Default: "./"
  • - -
  • --template_dir -- sets the template root - directory. Default: ./ which is the correct - specification when it is run from the directory where the templates - are located. This is only used if the input template filenames - are specified as relative paths rather than absolute - paths.
  • - -
  • --outputfile_suffix -- the extension added to the - name of the template file to create the name of the generated - header file. Default: .varnames.h. -
- -

For a full list of command line flags, run -make_tpl_varnames_h --help.

- - -

template-converter: convert a template to a C++ string

- -

The TemplateFromString class lets you load a template -from a string instead of a file. Applications may prefer this option -to reduce the dependencies of the executable, or use it in -environments where data files are not practical. In such cases, -template-converter can be used as a template "compiler", -letting the developer write a template file as a data file in the -normal way, and then "compiling" it to a C++ string to be included in -the executable.

- -

Usage is template-converter <template filename>. -C++ code is output is to stdout; it can be stored in a .h file or -included directly into a C++ file. Perl must be installed to use this -script.

- -


- - -
-
-Craig Silverstein
-27 February 2006 -
- - - diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index cf00738..0000000 --- a/docs/index.html +++ /dev/null @@ -1,94 +0,0 @@ - - - - Google Template System - - - - - - - - -

Google Template System

-
Status: Current   -(as of 16 February 2006)
-
- -Welcome to the Google C++ template system! As a quick start, here's a -small but complete program that uses this template library. For more -details see, the links below. - -

Template file example.tpl

-
-   Hello {{NAME}},
-   You have just won ${{VALUE}}!
-   {{#IN_CA}}Well, ${{TAXED_VALUE}}, after taxes.{{/IN_CA}}
-
- -

C++ program example.cc

-
-   #include <stdlib.h>
-   #include <string>
-   #include <iostream>
-   #include <google/template.h>
-   int main(int argc, char** argv) {
-      google::TemplateDictionary dict("example");
-      dict.SetValue("NAME", "John Smith");
-      int winnings = random() % 100000;
-      dict.SetIntValue("VALUE", winnings);
-      dict.SetFormattedValue("TAXED_VALUE", "%.2f", winnings * 0.83);
-      // For now, assume everyone lives in CA.
-      // (Try running the program with a 0 here instead!)
-      if (1) {
-        dict.ShowSection("IN_CA");
-      }
-
-      google::Template* tpl = google::Template::GetTemplate("example.tpl",
-                                                            google::DO_NOT_STRIP);
-      std::string output;
-      tpl->Expand(&output, &dict);
-      std::cout << output;
-      return 0;
-   }
-
- -

In-depth Documentation

- -
    -
  1. Howto: Introduction to the Google - Template system, and a tutorial for using it.
  2. - -
  3. Tips: Advice, tips, and recommendations - for best practices with templates, to make them easier to write - and maintain, and to avoid common template mistakes.
  4. - -
  5. Examples: Some example templates and - application code that uses them. These are taken from actual - Google applications.
  6. -
- -
-
-Craig Silverstein
-Last modified: Wed Feb 15 23:21:42 PST 2006 -
- - - diff --git a/docs/tips.html b/docs/tips.html deleted file mode 100644 index fde4c18..0000000 --- a/docs/tips.html +++ /dev/null @@ -1,468 +0,0 @@ - - - -Tips and Guidelines for Using the Google Template System - - - - - - - - - -

Tips and Guidelines for Using the Google Template System

-(as of 27 February 2006) - -
- -

The basic rules of the template system are -enough to use it, but over time, we at Google have developed some -tips, guidelines, and best practices that make it easier to use -templates effectively, and to avoid common template errors.

- - -

Program Design Considerations

- -

Template naming and versioning

- -

Early in Google's use of templates, we noticed a problem: if a -binary that uses a template and its corresponding template were both -modified, particularly if the change were such that the old binary -could not work with the new template or the new binary cannot work -with the old template, then somehow they both had to be deployed at -the same instant to not present errors to our users. This was hard to -do. The solution was to adopt a template naming and versioning -convention. The procedure to use it follows:

- -
    -
  • Each template name ends with _postYYYYMMDD.tpl, - where YYYMMDD is the date of this version's initial - creation.
  • - -
  • Before making (non-backward-compatible) modifications to a - template, copy the template to a new name, incorporating a - later date than the original one being copied.
  • - -
  • Edit the new file, and push it to the production server.
  • - -
  • Finally, update the code to refer to the new template-name - (ideally, using the RegisterTemplateFilename - idiom), and push the new executable to the production - server.
  • -
- -

When this convention is followed, the new template file does not -overwrite the old one when it is deployed, because it is a new file -with a new name. The old template file is still there to be used as -long as the old binary is still in production and the new template -file just sits there being ignored. Then when the new binary finally -gets deployed, it immediately starts using the new template file, -because it is coded (in RegisterTemplateFilename) to do -so. After that, it is the old template file that continues to sit -there ignored.

- -

The make_tpl_varnames_h -utility knows about the "_postYYYYMMDD" naming convention, so it -is important that you use that convention exactly if you use the -make_tpl_varnames_h.

- - -

Processing Phases

- -

Typically a program using the Google Template System will -perform the following phases, usually in this order:

- -
    -
  1. Retrieve and prepare the data used to fill a dictionary.
  2. - -
  3. Build the data dictionary, including all its - sub-dictionaries, that will supply the values to the - designated template object, its sections, and its - included templates.
  4. - -
  5. Retrieve the top-level template object required to - format the data. (This may or may - not involve reading and parsing a template file, - depending on whether the requested file has already - been read and parsed by the running program or - whether that file has been marked "reload if changed" - and was in fact changed.)
  6. - -
  7. Expand the template object into an output buffer - using the completed data dictionary.
  8. - -
  9. Output the buffer.
  10. - -
  11. Clean up: Destroy the top-level data dictionary - whenever it is no longer needed.
  12. - -
  13. Optionally, clear the cache at the end of program - execution.
  14. -
- - -

One template / One procedure call

- -

Most of the code of the program will be in Phases 1 and -2. Clearly, Phase 1 is outside the scope of the template system. But -in designing the code for Phase 2 (building the data dictionary), it -is wise to have the structure of the program reflect the structure of -the templates being used. Specifically, there should be a single -procedure call to build the dictionary for a single template. That -procedure call should take parameters that include all the data -required to populate the data dictionary for that template and all the -templates it includes. Following this "one template/one procedure -call" guideline further, for each included template, another procedure -should be called to populate the (or each) data dictionary for -that included template. This maintains the "one template/one procedure -call" principle in a nested fashion that reflects the nesting of the -templates.

- -

This is not to imply that the "one procedure call" for a template -should not be modularized into sub-procedures for readability and -maintainability, or that it should not call other auxilliary -procedures for such things as formatting the data and converting it to -the appropriate strings, etc. But it does mean that there should be -one entry point for building the dictionary tree for one template and -that entry point should show the data dependencies of that template -through its parameter list. This code for populating the data -dictionary should NOT be intermingled with data gathering code -that should have been done in Phase 1.

- -

(Inside Google, the convention has been used to name the dictionary -building procedure using the pattern fill_..._dictionary -where the dots are related to the name of the template the data is -being prepared for. For instance, the data for the template named -one_search_result.tpl might be placed in a dictionary via a function -named fill_one_search_result_dictionary.) - - -

Tips, Idioms, and Conventions

- -
    - -
  1. Choose template names to create unique constant prefixes. - -

    Template names should contain at least two words - to avoid constant prefix clashes (e.g. kxy_ - instead of kx_ ) The name of a new template - should be checked against the existing names before - proceeding. If your new template name produces a prefix that - conflicts with an already existing template, you should change - the name of your new template, even though it may be the only - perfect name you can come up with. You'll have to use a less - than perfect name in that case. (See "Template Syntax Checker - and Header File Generator" below for more explanation about - constant prefixes.)

  2. - -
  3. Use SetFormattedValue discriminately. - -

    This method should never be used to sneak HTML into the - executable as in

    - -
    -     dictionary->SetFormattedValue(kxy_VAR,
    -                                   "<b>%s</b>",
    -                                   some_const_char_string);
    -     
    - -

    In that case, the <b> and - </b> should be moved into the template.

    - -
  4. Never have a section encompass an entire template. - -

    If the first line of a template is a start section marker - and the last line is its matching end section marker, then - those markers are unnecessary in almost all cases. They are - usually put there to allow the entire template to be hidden or - iterated, but since it encompasses the entire file, the - section may be hidden by not expanding the file (or by hiding - the template-include section that includes the file) and it - may be iterated by iterating the template-include marker of - the including template. (The only exception might be if the - entire page is to be iterated, but this seems a bit of a - stretch.)

  5. - -
  6. An included template is just a section whose contents are - located in a separate file. You may iterate over it just - like you do sections. - -

    For example, if your template has the following - template-include marker:

    -
    -     {{>MY_INCLUDED_TEMPLATE}}
    -     
    -

    you may call

    -
    -     google::TemplateDictionary *child_dict =
    -        dictionary->AddIncludeDictionary(kxy_MY_INCLUDED_TEMPLATE);
    -     
    -

    to iterate that section. (Note: Make sure you call - child_dict->SetFilename()! If your included - template is not showing in the output, this is the first thing - you should check.)

  7. - -
  8. The recommended idiom to fill an include-template dictionary is - like this: -
    -        fill_include_template_dictionary(dict->AddIncludeDictionary(name), ...);
    -     
    - -

    But what do you do if you decide, in - fill_include_template_dictionary, that you don't - want to display anything for this include-template after all? It - seems like it's too late: you've already created the - sub-dictionary. The solution is simple: just be sure that - fill_include_template_dictionary() doesn't call - SetFilename() in that case.

    - -
  9. Never have a section which only contains another section. -

    For example, don't do this:

    -
    -     {{#OUTER_SECTION}}
    -        {{#INNER_SECTION}}
    -        section contents here
    -        {{/INNER_SECTION}}
    -     {{/OUTER_SECTION}}
    -     
    -

    or this equivalent template code (see the previous item):

    -
    -     {{#OUTER_SECTION}}
    -        {{>INCLUDED_SECTION}}
    -     {{/OUTER_SECTION}}
    -     
    - -

    This is usually done because the developer thinks the outer - section must be used to hide the section when the inner - section, intended for iteration, has no iterations. In both - cases, you should only have one section (either - INNER_SECTION or INCLUDED_SECTION in - the examples) and iterate that section either 0 times or more - than 0 times. It's the wonder of the dual use of sections, - i.e. that they may be conditional or iterative or, in this case, - both.

    - -

    A related suggestion: Do not have a section whose entire - contents is one variable marker with nothing else, unless you - need to iterate over that section with multiple values of that - variable. You don't need the surrounding section just to hide - the marker. A variable marker that is not set, does not - produce output. By convention, we set such variables to the - empty string. But in neither case do you need to hide it by - hiding a surrounding section that contains nothing else.

    - -
  10. Use this hide/show idiom for if-else blocks. - -

    Since sections are hidden by default, you can use represent - if-else logic in your code via ShowSection. For - example:

    - -
    -     if ( my_test ) {
    -        dict->ShowSection(kxyz_TRUE_BLOCK);
    -        [ more code to fill the values for that section]
    -     } else {
    -        dict->ShowSection(kxyz_FALSE_BLOCK);
    -        [ more code to fill the values for that section]
    -     }
    -     
    - -
  11. Write... vs. Fill...Dictionary methods - - Observe the proper division of labor, don't mix them. - -

    The output (or write) function should create the top level - template dictionary, call one or more fill-dictionary routines - with it, then get the template and expand it. It should not call - dictionary modifying methods, like ShowSection - and SetValue. By keeping these separated into - their own fill-dictionary routine, the code is more modular and - lends itself to template re-use. If you maintain the proper - division of labor, the template you are filling and outputting - may be filled and included in a larger template by someone - else.

  12. - -
  13. Use AddSectionDictionary only when you want to - iterate over a section or, secondarily, if you need to avoid name - conflicts. - -

    Sometimes developers get the idea that every section requires - its own child dictionary created by an - AddSectionDictionary call. Because of variable - inheritence, this isn't usually so. The intended purpose of - AddSectionDictionary is to enable iteration over a - section. Secondarily, if the section contains generic names that - may conflict with the same name in other parts of the template, - it may be safer to call AddSectionDictionary to - create a separate namespace. In any case, do not assume you must - call AddSectionDictionary just because you are - working within a section. The main dictionary can be used for all - levels of conditional sections as long as you avoid name - conflicts by keeping the marker names unique.

  14. - -
  15. Do not place RegisterTemplateFilename - statements in header (.h) files. - -

    RegisterTemplateFilename is a macro that - instantiates a TemplateNamelist object. If you place - it in a header file, a different object will get created each time - it is included in another .cc file. - -

    The RegisterTemplateFilename statement and its - associated #include of the varnames.h - file should occur only in the .cc file that - implements the fill-dictionary routine for that template. You - should never have more than one - RegisterTemplateFilename for a single template and - you should try hard not to copy the #include file to - other files as well. The template versioning makes this more - important because a developer may not know that the template name - with included version number needs to be updated in more than one - file when versioning occurs. [Also see above for more information - about what routine uses the filename declared by the - RegisterTemplateFilename statement.]

  16. - -
  17. Never reference more than one template in a - fill...dictionary method. - -

    Each template should have its own fill-dictionary - routine. That routine should only reference marker names defined - in that template. If this convention is followed, then all the - prefixes in a fill-dictionary routine will be the same. [Note - that an implication of this convention is that if the template - includes another template, via a template-include marker, then - containing template's fill-dictionary routine should call the - included template's fill-dictionary routine (being careful to - observe the convention described above). But - then, this is merely a restatement of "One - template / One procedure call".]

  18. - -
  19. Have fill...dictionary call SetFilename even if the - dictionary is never used for a template-include. - -

    SetFilename() is required when a dictionary is created via - AddIncludeDictionary(). However, it's safe to set - all the time. By setting it always, you make the code work - properly if this dictionary ever changes to be template-included - after all. Even if not, by saying what template file the - dictionary is intended to go with, you are self-documenting your - code.

  20. - -
  21. Do not call c_str() on strings to pass them to - TemplateDictionary methods. - -

    Note that all the TemplateDictionary methods are defined to - take TemplateString objects. These are created - automatically from both strings and char*'s (and can be created - manually if you have a char* and a length). So if you have a - string, it's safe and efficient to just pass it in directly; you - do not need to extract the const char * from your string object - to pass it to these methods. For some reason, this is a common - error of noviced template coders.

    - -

    The one exception to this rule is when using the method - SetFormattedValue. When calling that - method, you must call c_str() on strings that are to - be inserted - into the format string, just as you would when providing data for - any other printf format string.

  22. - -
  23. Do not use SetGlobalValue when you could use - SetValue. - -

    SetGlobalValue should be used quite rarely, for - constants that really are consistent across all your templates. - It's slower to look up a value in the global dictionary than it - is in the template-specific dictionary.

  24. - -
  25. Do not use TemplateFromString unless you have - a specific need for its non-file-based attributes. - -

    TemplateFromString was created for use in highly - constrained cases where file I/O may be impaired or - undesirable, for instance to produce a server error message - where there may be disk problems or to produce formatted - output where there are processes that do not have a facility - for updating data files dynamically. It is not recommended for - ordinary use as it is limited in functionality in at least the - following ways:

    -
      -
    • It can neither include nor be included from - another template. -
    • It cannot be updated dynamically via a - data-push; changes always require a binary push. -
    -
  26. - -
  27. Use variable-modifiers (eg {{VAR:html_escape}}) or - SetEscapedValue when necessary to prevent security - violations. - -

    Variable-modifiers make it very easy to html-escape (or - otherwise escape) text that needs to be escaped for safety. Use - :h, :j and friends liberally.

    - -

    For situations where you need to provisionally escape, or use - an escape routine other than the built-in ones, the - Escaped versions of the set-value methods - are useful utility functions to use.

    - -

    As a guide for when to use this: every value accepted - from a user must be HTML-escaped before redisplaying it on - another page. The escaping - prevents the user from executing scripts or displaying raw HTML - via their input values. These methods make it simple to prevent - scripting security violations when used where necessary.

  28. - -
  29. Do not leave an extra space when using {{BI_SPACE}} - -

    The built-in template variable BI_SPACE is itself - replaced by a single space. It is used where you need to make - sure a space is preserved at the end of a line. It is a common - mistake to leave an extra space before this marker, which results - in not one, but two, spaces created in the document.

  30. - -

    Incorrect:

    -<table border=0 {{BI_SPACE}}
    -       align=center>

    - -

    Correct:

    -<table border=0{{BI_SPACE}}
    -       align=center>

    - - -
    - - -
    -
    -Craig Silverstein
    -27 February 2006 -
    - - -