INTRODUCTION
------------

BoilerPlate is a collection of classes that provide simple yet powerful
macro-type processing of Python text. Blocks within text can be conditionally
included or excluded based on runtime values. Also, text blocks can be iterated
over by a sequence or a dictionary.

Although BoilerPlate was based on ideas found in Jim Fulton's DocTemplate
module, it is *not* a replacement. Most notably, only dictionaries are support
in the __init__ and __call__ methods of the BoilerPlate classes, whereas
Fulton's code supports an instance variable and name resolution for it. Also,
the HTML server-side include format is not recognized, and the block tag
structures are radically different.

The following tags are recognized within text blocks:

 o  @if <condition>: -- start of a conditional block. Condition is evaluated
    at format time and if it returns a Python `true' value, the text block is
    formatted.

 o  @for <tag> in <data>: -- start of an iteration block. Data is evaluated
    at format time and is iterated over. Unlike Python's `for' statement,
    this one supports dictionaries the value for <data>. The following data
    elements are available within a `for' block iteration over a sequence:

      o <tag>.counter -- count of values; starts at 1
      o <tag>.index -- index of value in sequence; starts at 0
      o <tag>.value -- current value in iteration

    These values are available for dictionary iterations:

      o <tag>.key -- current key value in iteration
      o <tag>.value -- current value in iteration

    Finally, `for' blocks attempt to calculate statistics based on the values
    in the iteration. See class `ForCooker' for more info about these.

 o  @elif <condition>: -- (only available after an @if block). Condition is
    evaluated at format time if the owning @if block or previous @elif block
    did not format.

 o  @else: -- (only after an @if or @elif block). Represents text to format
    if all preceding @if and @elif blocks returned a Python `false'.

Runtime text substitution is denoted by using Python's normal %() constructs.
During formatting, we obtain the contents between the `(' and ')' characters,
and evaluate it. Evaluation scope is limited to a set of formatting operations,
Python builtin functions, and a provided dictionary.

*** NOTE: this module REQUIRES a patch to Python's stringobject.c file to allow
*** for embedded `(' and `)' characters within a %() construct. This change
*** should be in Python release 1.5. A patch file should be included with this
*** distribution (strobj.pat).

The Formatter class provides formatting routines that can be embedded inside of
a %() construct to change the value before it is given to Python. These
functions are supported:

 o  Lower() -- convert all text to lowercase
 o  Upper() -- convert all text to uppercase
 o  Capitalize() -- convert first character of every word to uppercase and
    all the rest to lowercase
 o  Spacify() -- convert all '_' characters to spaces
 o  Null() -- sets an alternative to return if the final value of the %()
    construct matches a set of empty values.
 o  Letter() -- returns letter corresponding to a number (`A' == 0)
 o  Roman() -- returns conversion of value into roman numerals
 o  HtmlEncode -- returns value with appropriate conversions for use within
    an HTML tag.
 o  UrlEncode -- returns value with appropriate conversions for use within an
    HTML URL.

Note that since Python's `eval' function is used, any built-in function can
also be used in the %() construct.

Users should create instances of either the String or the File BoilerPlate
class. Here are some examples and expected results:


EXAMPLES
--------

See the bottom of BoilerPlate.py for examples of BoilerPlate usage. There is a
function defined called RegressionTesting that can be used to verify that
everything works OK. This can be run by executing

  python BoilerPlate.py

at a shell prompt.

The following examples were taken from the RegressionTesting function:

  python% a={'foo': 'HeLlO WoRlD', 'bar': (1,2,3,4,5)} 
  python% BoilerPlate.String( '%(foo)s %(Lower(foo))s %(Upper(foo))s', a )()
  'HeLlO WoRlD hello world HELLO WORLD'

  python% BoilerPlate.String( '%(map(Roman(bar))s', a )()
  "['I', 'II', 'III', 'IV', 'V']"

  python% print BoilerPlate.String( '''%for each in bar:
  > index = %(each.index)d   value = %(each.value)d
  > @end for
  > avg = %(each.mean)d''', a )()
  index = 0   value = 1
  index = 1   value = 2
  index = 2   value = 3
  index = 3   value = 4
  index = 4   value = 5
  avg = 3

