Added sections explaining purpose and use of Variable Templates.
1 parent 6d39ed9 commit 15a5987e62bb9495716cef079b942deaa54fafcf
@tundra tundra authored on 27 Apr 2004
Showing 1 changed file
View
514
tconfpy.3
 
.TP
.B LiteralVars (Default: \fCFalse\fP)
 
If set to \fCTrue\fP this option enables variable substitutions within
If set to \fCTrue\fP, this option enables variable substitutions within
\fC.literal\fP blocks of a configuration file. See the section in the
language reference below on \fC.literal\fP usage for details.
 
 
.TP
.B ReturnPredefs (Default: \fCTrue\fP)
\fCtconfpy\fC "prefefines" some variables internally. By default,
\fCtconfpy\fP "prefefines" some variables internally. By default,
these are returned in the symbol table along with the variables
actually defined in the configuration file. If you want a
"pure" symbol table - that is, a table with
.B only
be referenced in a string substitution or conditional test,
but cannot be changed.
 
.IP \(bu 4
You may want to place limits on what values can be assigned to
a particular variable. When a variable is newly defined in a
a configuration file, it just defaults to being a string
variable without any limits on its length or content. But
variables that are created by a program have access to the
variable's "descriptor". By setting various attribues
of the variable descriptor you can control variable type,
content, and range of values. In other words, you can have
\*(TC "validate" what values the user assigns to particular
variables. This substantially simplifies your application because
no invalid variable value will ever be returned from the parser.
You may want to place limits on what values can be assigned to a
particular variable. When a variable is newly defined in a a
configuration file, it just defaults to being a string variable
without any limits on its length or content (unless you are using
Variable Templates). But variables that are created by a program have
access to the variable's "descriptor". By setting various attribues
of the variable descriptor you can control variable type, content, and
range of values. In other words, you can have \*(TC "validate" what
values the user assigns to particular variables. This substantially
simplifies your application because no invalid variable value will
ever be returned from the parser.
 
 
.SS How To Create An Initial Symbol Table
 
and \fCrealvar\fP are predefined in the initial symbol
table passed to the parser.
 
 
.SS Using Variable Templates - The \fCTemplates\fP And \fCTemplatesOnly\fP API Options
.SS Using Variable Templates
 
By default, any time a new variable is encountered in a configuration
file, it is created as a string type with no restrictions on its
content or length. As described above, you can predefine the variable
in the initial symbol table you pass to the parser. This allows you
to define that variable's type and to optionally place various
restrictions on the values it may take. In other words, you can "declare"
the variable ahead of time and \*(TC will do so-called "type
and value enforcement".
 
"Variable Templates" are a related kind of idea, with a bit of
a twist. They give you a way to "declare" variable type
and content restrictions for selected
.B new variables
discovered in the configuration file. In other words,
by using Variable Templates, you can make sure that
a new variable also has restrictions placed on its type
and/or values.
 
The obvious question here is, "Why not just do this
by predefining every variable of interest in the
initial symbol table passed to the parser?" There
are several answers to this:
 
.IP \(bu 4
The \*(TC configuration language has very powerful "existential"
conditional tests. These test to see if a variable "exists".
If you predefine every variable you will ever need, then
the kinds of existential tests you can do will be
somewhat limited (since every variable
.B does
already exist).
 
With Variable Templates, you can define the type and value
constraints of a variable which will be applied,
.B but only if you actually bring that variable into existence.
This allows constructs like this to work:
 
.ft C \" Courier
.nf
.if [.PLATFORM] == posix
posix = True
.endif
 
.if [.PLATFORM] == nt
nt = True
.endif
 
.ifall posix
...
.endif
 
.ifall nt
...
.endif
 
.ifnone posix nt
...
.endif
 
.fi
.ft \" revert
 
In this example, notice that the variables \fCposix\fP and \fCnt\fP
may- or may not be actually created, depending on the value of
\fC.PLATFORM\fP. The logic later in the example depends upon this.
If you were to predefine these two variables (to specify type
and/or value restrictions), this type of logical flow would not
be possible.
 
By providing Variable Templates for \fCposix\fP and \fCnt\fP,
you can define their type (likely Boolean in this case)
ahead of time
.B and this will be applied if the variable does come into existence.
 
 
.IP \(bu 4
The other reason for Variable Templates is more subtle, but
gives \*(TC tremendous versatility beyond just processing
configuration files. Variable Templates give you a way to use
\*(TC to build data validation tools.
 
Suppose you have a list of employee records exported in this
general format (easy to do with most databases):
 
.ft C \" Courier
.nf
[Employee#]
LastName = ...
FirstName = ...
Address = ...
City = ...
 
... and so on
 
.fi
.ft \" revert
 
 
By using the empoyee's ID as a lexical namespace, we end up creating
new variables for each employee. Say the employee number is
\fC1234\fP. Then we would get, \fC1234.LastName\fP,
\fC1234.FirstName\fP, and so on.
 
Now, here's the subtle part. Notice that the type and content
restrictions of these variables is likely to be the
.B same
for each different employee.
 
By defining Variable Templates for each of the variables we
intend to use over and over again in different namespace
contexts, we can
.B validate
each of them to make sure their content, type, length, and so forth
are correct. This makes it possible to use \*(TC as the underpinnings
of a "data validation" or "cleansing" program.
 
.IP \(bu 4
Another way to look at this is that Variable Templates give you
a way to define type/value restrictions on an entire "class"
of variables. Instead of having to explictly predefine
variables for every employee in our example above, you
just define templates for the variable set that is common to
all employees. This is
.B way
simpler than predefining every possible variable combination
ahead of time.
 
 
.SS The \fCTemplates\fP And \fCTemplatesOnly\fP API Options
 
Variable Templates are supported with two API options:
\fCTemplates\fP And \fCTemplatesOnly\fP. \fCTemplates\fP
is used to pass a symbol table (separate from the main symbol
table) containing the Variable Templates. By default, this
option is set to \fC{}\fP which means no templates are
defined.
 
So what exactly is a "Variable Template"? It is the
.B exact same thing
as a predefined variable you might pass in the initial symbol
table. In other words, it is a Python dictionary entry where the
key is the variable name and the entry is in \fCVarDescriptor\fP
format.
 
The only difference is that a templated variable does not come into
existence in the main symbol table until a variable by that
.B name
is encountered in the configuration file. Then the variable is
created using the template as its entry in the main symbol table.
 
For example:
 
.ft C \" Courier
.nf
[1234]
LastName = Jones
FirstName = William
Address = 123 Main Street
City = Anywhere
State = WI
ZIP = 00000-0000
 
[1235]
LastName = Jones
FirstName = Susan
Address = 123 Main Street
City = Anywhere
State = WI
ZIP = 00000-0000
 
.fi
.ft \" revert
 
 
Suppose you define variable templates for \fCLastName\fP,
\fCFirstName\fP, \fCAddress\fP, and so on. That is, you
define variables by these names, and define whatever type
and content restrictions you want in each of their
\fCVarDescriptor\fPs. You then pass these to the parser
via the \fCTemplates=\fP option.
 
As \*(TC parses the file and encounters the new variables
\fC1234.LastName\fP ... \fC1235.ZIP\fP, it uses the following
"rules" when creating new variables:
 
.IP \(bu 4
See if there is a template variable whose name is the same as
the "base" name of the new variable. (The "base" name is just
the variable name without the prepended namespace.)
 
If there is a template with a matching name, see if the value the
user wants to assign to that variable passes all the type/validation
rules. If so, load the variable into the symbol table and set its
value as requested,
.B using the \fCVarDescriptor\fP object from the template.
(This ensures that future attempts to change the variable's value will
also be type/validation checked.)
 
If the assignment fails the validation tests, issue an appropriate
error and do
.B not
create the variable in the symbol table.
 
.IP \(bu 4
If there is no template with a matching name, then just
create a new variable as usual - string type with no
restrictions,
.B unless
\fCTemplatesOnly\fP is set to \fCTrue\fP. Setting this
option to \fCTrue\fP tells the program that you want to
allow the creation of
.B only
those variables for which templates are defined. This is
a way to restrict just what new variables can be created
in any namespace. \fCTemplatesOnly\fP defaults to \fCFalse\fP
which means you can create new variables even when no template
for them exists.
 
.P
In summary, Variable Templates give you a way to place
restrictions on variable type and content
.B in the event that the variable actually comes into existence.
They also give you a way to define such restrictions for an
entire class of variables without having to explicitly name
each such variable ahead of time. Finally, Variable Templates
are an interesting way to use \*(TC as the basis for data
validation programs.
 
 
 
.SS The \fCLiteralVars\fP API Option
 
.B only
the variables actually encountered in the configuration file itself,
set \fCReturnPredefs=False\fP in the \fCParseConfig()\fP API call.
This will cause \fCtconfpy\fP to strip out all the predefined
variables before returning the final symbol table. Note that this
option also removes the \fCNAMESPACE\fP variable since it is understood
to also be outside the configuration file (even though you may have
passed an initial version of \fCNAMESPACE\fP to the parser).
variables before returning the final symbol table.
 
Note that this option also removes the \fCNAMESPACE\fP variable since
it is understood to also be outside the configuration file (even
though you may have passed an initial version of \fCNAMESPACE\fP to
the parser).
 
Note also that this option applies only to the variables predefined
by
.B \fCtconfpy\fP
itself. Any variables
.B you
predefine when passing an initial symbol table will be returned as usual,
regardless of the state of this option.
 
 
.SS The \fCDebug\fP API Option