diff --git a/tconfpy.3 b/tconfpy.3 index 862e7c4..91ed31c 100644 --- a/tconfpy.3 +++ b/tconfpy.3 @@ -165,14 +165,14 @@ .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 @@ -245,17 +245,17 @@ 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 @@ -650,7 +650,236 @@ 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 @@ -735,10 +964,20 @@ 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