tepam::procedure(3tcl) | Tcl's Enhanced Procedure and Argument Manager | tepam::procedure(3tcl) |
tepam::procedure - TEPAM procedure, reference manual
package require Tcl 8.3
package require tepam ?0.5?
tepam::procedure name attributes body
This package provides an alternative way to declare Tcl procedures and to manage its arguments. There is a lot of benefit to declare a procedure with TEPAM rather than with the Tcl standard command proc: TEPAM allows specifying inside the procedure declaration all information that is required to generate comprehensive documentations and help support. The information is also used by an automatically invoked argument checker that validates the provided procedure arguments before the procedure body is executed. Finally, a procedure can be called interactively which will open a graphical form that allows specifying the procedure arguments.
TEPAM simplifies also the handling of the different types of argument, like the named arguments (often also called options) and the unnamed arguments. TEPAM supports the named first, unnamed later style (typical Tcl command style) as well as also the unnamed first, named later style (typical Tk command style). TEPAM takes care about default values for arguments, optional arguments, multiple applicable arguments, etc. and eliminates the need to check the validity of the argument inside the procedure bodies.
An informal overview of all the TEPAM procedure declaration and calling features as well as a short introduction into TEPAM is provided by tepam(3tcl).
The exact meaning of several terms that are used in this document will be shortly explained to avoid any ambiguities and misunderstandings.
The string command is an example of such a command that implements for example subcommands to check a character string length, to compare strings, to extract substrings, etc:
string length string string compare string string string range string first last ...
TEPAM provides a framework that allows implementing easily such subcommands in form of Tcl procedures. It allows not only defining a first level of subcommands, but also a higher level of subcommands. The string command class check could be implemented as independent sub-sub-commands of the string command:
string is alnum string string is integer string string is double string ...
The following example calls the subcommand string compare with several arguments:
string compare -nocase -length 3 "emphasized" "emphasised"
TEPAM uses the term named argument for such options as well as for the flags (see next item).
Flags are considered by TEPAM like a special form of named arguments.
string compare -nocase -length 3 Water $Text
pack .ent1 .ent2 -fill x -expand yes -side left
TEPAM allows declaring new Tcl procedures with the command tepam::procedure that has similar to the standard Tcl command proc also 3 arguments:
The TEPAM procedure declaration syntax is demonstrated by the following example:
tepam::procedure {display message} { -short_description "Displays a simple message box" -description "This procedure allows displaying a configurable\ message box. The default message type that is\ created is a warning, but also errors and info can\ be generated. The procedure accepts multiple text lines." -example {display message -mtype Warning "Save first your job"} -args { {-mtype -choices {Info Warning Error} \ -default Warning -description "Message type"} {text -type string -multiple \ -description "Multiple text lines to display"} } } { puts "Message type: $mtype" puts "Message: $text" }
Here are some valid procedure declarations using different procedure names (the attribute and body arguments are empty for simplicity):
# Simple procedure name: tepam::procedure display_message {} {} # Procedure declared in the main namespace: tepam::procedure ::display_message {} {} # Procedure in the namespace ::ns: tepam::procedure ::ns::display_message {} {} # Declaration of the subcommand message of the procedure display: tepam::procedure {display message} {} {}
Most procedure attributes are providing information for documentation purposes. But some of them affect also the way how the procedure can be called. The section Procedure Attributes discusses in detail the available procedure attributes.
The procedure arguments are defined in form of a special procedure attribute. Most of the information provided in the argument definition is not just used for documentation purposes. This information is in fact used by the TEPAM argument manager to handle and validate the various forms of arguments that are provided during the procedure calls. The section Argument Declaration discusses in detail all the argument definition attributes.
The procedure body will only be executed if the provided set of arguments could be validated by the TEPAM argument manager.
tepam::procedure {display_message} { -args { {-mtype -default Warning -choices {Warning Error}} {text -type string} } } { puts "Message type: $mtype" puts "Message: $text" }
The commands procedure as well as argument_dialogbox are exported from the namespace tepam. To use these commands without the tepam:: namespace prefix, it is sufficient to import them into the main namespace:
namespace import tepam::* procedure {display_message} { -args { ...
The first group of attributes affect the behavior of the declared procedure:
The choice to use short or extended forms can be globally configured via the variable tepam::interactive_display_format. This global setting can then be changed individually for a procedure with the -interactive_display_format procedure attribute.
The argument definition syntax will be described more in detail in the following sub section.
The next attributes allow specifying custom argument checks as well as custom error messages in case these checks are failing:
Validation command declaration example:
tepam::procedure {display_message} { -args { {text -type string -description "Message text"} } -validatecommand {IllegalWordDetector $text} } { }
The attribute -validatecommand can be repeated to declare multiple custom checks.
The following attribute allows controlling the logging settings for an individual procedure:
Setting this argument to 0 will disable any procedure call loggings, setting it to 1 will log any procedure calls and setting it to interactive will log just the procedures that are called interactively (procedures called with the -interactive flag).
The next group of procedure attributes is just used for the purpose of documentation and help text generation:
The following example shows the structure that is used for the argument definitions in the context of a procedure declaration:
tepam::procedure {display_message} { -args { {-mtype -default Warning -choices {Info Warning Error} -description "Message type"} {-font -type font -default {Arial 10 italic} -description "Message text font"} {-level -type integer -optional -range {1 10} -description "Message level"} {-fg -type color -optional -description "Message color"} {-log_file -type file -optional -description "Optional message log file"} {text -type string -multiple -description "Multiple text lines to display"} } } { }
tepam::procedure <name> { -args { {<argument_name_1> <arg_attr_name_1a> <arg_attr_value_1a> <arg_attr_name_1b> <arg_attr_value_1b> ...} {<argument_name_2> <arg_attr_name_2a> <arg_attr_value_2a> <arg_attr_name_2b> <arg_attr_value_2b> ...} ... } } <body>
tepam::procedure {print_string} { -args { {text -type string -description "This is an unnamed argument"} } } { puts $text } print_string "Hello" -> Hello
tepam::procedure {print_string} { -args { {-text -type string -description "This is a named argument"} } } { puts $text } print_string -text "Hello" -> Hello
If the unnamed arguments first, named arguments later style (Tk) style is selected, this flag is ignored if the unnamed arguments have already been parsed. Otherwise it will be assigned to the corresponding unnamed argument.
tepam::procedure {print_time} { -interactive_display_format short -args { {hours -type integer -description "Hour"} {minutes -type integer -description "Minute"} {- The following arguments are optional:} {seconds -type integer -default 0 -description "Seconds"} {milliseconds -type integer -default 0 -description "Milliseconds"} } } { puts "${hour}h${minutes}:[expr $seconds+0.001*$milliseconds]" }
Section comments can be used to structure visually the argument definition code. Section comments are also used to structure the generated help texts and the interactive argument definition forms.
tepam::procedure {complex_multiply} { -description "This function perform a complex multiplication" -args { {#### First complex number ####} {-r0 -type double -description "First number real part"} {-i0 -type double -description "First number imaginary part"} {#### Second complex number ####} {-r1 -type double -description "Second number real part"} {-i1 -type double -description "Second number imaginary part"} } } { return [expr $r0*$r1 - $i0*$i1] }
The section ARGUMENT TYPES provides a list of predefined data types and explains how application specific types can be specified.
The argument type none has a special meaning. An argument that has the type none is handled as a flag. A flag is always optional and its related variable contains the logical value 1 if the flag has been defined during the procedure call, or otherwise 0.
In case an optional argument is not defined during a procedure call, the corresponding variable will not be defined. The flag -mandatory is the opposite to -optional. This flag exists only for completion reason, since an argument is anyway mandatory by default.
The -multiple attribute can be attributed to unnamed arguments and to named arguments. The pair of argument name/argument value has to be repeated for each provided value in case of a named argument. In case the argument with the -multiple attribute is an unnamed argument, this one has to be the absolute last one of all unnamed arguments.
The -choicelabels attribute is optional, but if it is defined, its list needs to have the identical size as the -choices argument list.
Validation command declaration example:
tepam::procedure {display_message} { -args { {text -type string -description "Message text" \ -validatecommand {IllegalWordDetector %P}} } { }
-auxargs {-<arg_attr_name_1a> <arg_attr_value_1a> \ -<arg_attr_name_1b> <arg_attr_value_1b> ... }
tepam::procedure LoadPicture { -args { {FileName -type existingfile -description "Picture file" \ -auxargs {-filetypes {{"GIF" {*.gif}} {"JPG" {*.jpg}} }}} } } { }
-auxargs_commands {-<arg_attr_name_1a> <arg_attr_command_1a> \ -<arg_attr_name_1b> <arg_attr_command_1b> ... }
Several variables defined inside the ::tepam namespace impact the mode of operation of the procedures that have been declared with the TEPAM procedure command.
By setting this variable to 0, the named arguments first, unnamed arguments later style is globally selected (Tk style):
set tepam::named_arguments_first 0
While this variable defines the general calling style, the procedure attribute -named_arguments_first can adapt this style individually for each declared procedure.
By setting this variable to 0 the automatic argument name matching mode is disabled:
set tepam::auto_argument_name_completion 0
While this variable defines the general matching mode, the procedure attribute -auto_argument_name_completion can adapt this mode individually for each declared procedure.
There are two display modes for these interactive forms. The extended mode which is the default mode is more adapted for small procedure argument sets. The short form is more adequate for huge procedure argument sets:
set tepam::interactive_display_format "short"
The choice to use short or extended forms can be globally configured via the variable interactive_display_format. This global setting can be changed individually for a procedure with the procedure attribute -interactive_display_format.
set tepam::help_line_length 120
TEPAM provides a comprehensive set of procedure argument types. They can easily be completed with application specific types if necessary.
To remember, a type can be assigned to each specified procedure argument:
tepam::procedure {warning} { -args { {-font -type font -default {Arial 10 italic}} {-severity_level -type integer -optional -range {1 10}} {-fg -type color -optional -description "Message color"} {text -type string -multiple -description "Multiple text lines to display"} } } { ... }
A flag, also called switch, is defined as a named argument that has the type none. Flags are always optional and the default value of the assigned variable is set to 0. In contrast to the (normal) named arguments, no argument value has to be provided to a flag.
tepam::procedure flag_test { -args { {-flag -type none -description "This is a flag"} } } { puts $flag } flag_test -> 0 flag_test -flag -> 1
Since no argument value has to be provided to a flag, also no data check is performed for this argument type.
String is a generic argument data type. Any data string can be provided to a string type argument and no data type checks are therefore performed. The string type allows defining single line strings during the interactive procedure calls.
Text is identical to string with the only difference that it allows entering multi line strings during interactive procedure calls.
A blank argument type signifies an undefined argument type. This is the default argument type that will be used if no type has been explicitly specified. An argument that has a blank type behaves identically than an argument that has a string type, e.g. no argument data checks are performed. The only difference is that the data type string is mentioned in the generated help documentation, while this is not the case for the blank type.
Several numerical types are defined by TEPAM. The type validation procedures are using the string is <type> -strict commands to check the validity of the provided arguments, which assures that no empty strings are accepted as argument value. The type validation expression for the numerical types and the argument types to which this expression is applied are:
string is <type_to_check> -strict <argument_value>
Empty strings are accepted as argument value for all the alpha numeric argument types. The argument types that are falling into this category and validation expression used for them are:
string is <type_to_check> <argument_value>
In addition to the data types checked with the string is <type> commands, TEPAM specifies some other useful data types:
Each string that has a length of 1 character meets the character type. The type check is made with the following expression:
expr [string length <argument_value>]==1
Any character strings that are accepted by Tk as a color are considered as valid color argument. Please note that the Tk package has to be loaded to use the type color. TEPAM is using the following command to validate the color type:
expr ![catch {winfo rgb . <argument_value>}]
Any character strings that are accepted by Tk as a font are considered as valid font argument. Please note that the Tk package has to be loaded to use the font type. TEPAM is using the following command to validate the color type:
expr ![catch {font measure <argument_value> ""}]
Any strings that are not containing one of the following characters are considered as valid file names: * ? " < >. It is not necessary that the file and its containing directory exist. Zero-length strings are not considered as valid file names.
The following expression is used to validate the file names:
expr [string length <argument_value>]>0 && ![regexp {[\"*?<>:]} <argument_value>]
The argument is valid if it matches with an existing file. The following check is performed to validate the arguments of this type:
file exists <argument_value>
The directory argument is validated exactly in the same way as the file arguments.
The argument is valid if it matches with an existing directory. The following check is performed to validate the arguments of this type:
file isdirectory <argument_value>
To add support for a new application specific argument type it is just necessary to add into the namespace tepam a validation function Validation(<type>). This function requires one argument. It has to returns 1 if the provided argument matches with the relevant data type. The function has to return otherwise 0.
The validation command section of the "tepam.tcl" package provides sufficient examples of validation functions, since it implements the ones for the standard TEPAM types.
The following additional code snippet shows the validation function for a custom argument type that requires values that have a character string length of exactly 2:
proc tepam::Validate(two_char) {v} {expr {[string length $v]==2}}
Each procedure can be called with the -help flag. The procedure will then print a generated help text to stdout and will then return without performing any additional actions.
Taking the first procedure declared in PROCEDURE CALLS, the help request and the printed help text would be:
display message -help -> NAME display message - Displays a simple message box SYNOPSIS display message [-mtype <mtype>] Message type, default: "Warning", choices: {Info, Warning, Error} <text> Multiple text lines to display, type: string DESCRIPTION This procedure allows displaying a configurable message box. The default message type that is created is a warning, but also errors and info can be generated. The procedure accepts multiple text lines. EXAMPLE display message -mtype Warning "Save first your job"
display message -mtype Info "It is 7:00" -help
display message -help -mtype Info "It is 7:00" -> display message: Argument '-help' not known
If Tk has been loaded a procedure can be called with the -interactive flag to open a graphical form that allows specifying interactively all procedure arguments. The following example assures that the Tk library is loaded and shows the command line to call interactively the procedure declared in PROCEDURE CALLS:
package require Tk display message -interactive
display message -mtype Info "It is 7:00" -interactive
Unnamed arguments are typically provided to the called procedure as simple parameters. This procedure calling form requires that the provided arguments are strictly following the order of the specified arguments. Several parameters can be assigned to the last argument if this one has the -multiple attribute. So, the following declared procedure ...
tepam::procedure {display_message} { -args { {mtype -choices {Info Warning Error}} {text -type string -multiple} } } { puts "$mtype: [join $text]" }
display_message Info "It is PM 7:00." -> Info: It is PM 7:00. display_message Info "It is PM 7:00." "You should go home." -> Info: It is PM 7:00. You should go home.
display_message -mtype Info -text "It is PM 7:00." -> Info: It is PM 7:00. display_message -text "It is PM 7:00." -mtype Info -> Info: It is PM 7:00. display_message -mtype Info -text "It is PM 7:00." -text "You should go home." -> Info: It is PM 7:00. You should go home. display_message -text "It is PM 7:00." -text "You should go home." -mtype Info -> Info: It is PM 7:00. You should go home.
Named arguments have to be provided to a procedure in form of a parameter pairs composed by the argument names and the argument values. The order how they are provided during a procedure call is irrelevant and has not to match with the argument specification order.
The following declared procedure ...
tepam::procedure {display_message} { -args { {-mtype -choices {Info Warning Error}} {-text -type string -multiple} } } { puts "$mtype: [join $text]" }
display_message -mtype Info -text "It is PM 7:00." -> Info: It is PM 7:00. display_message -text "It is PM 7:00." -mtype Info -> Info: It is PM 7:00. display_message -mtype Info -text "It is PM 7:00." -text "You should go home." -> Info: It is PM 7:00. You should go home. display_message -text "It is PM 7:00." -text "You should go home." -mtype Info -> Info: It is PM 7:00. You should go home.
display_message -mtype Info -text "It is PM 7:00." -mtype Warning -> Warning: It is PM 7:00.
A procedure that has been defined while the variable tepam::named_arguments_first was set to 1, or with the procedure attribute -named_arguments_first set to 1 has to be called in the Tcl style. The following procedure declaration will be used in this section to illustrate the meaning of this calling style:
set tepam::named_arguments_first 1 tepam::procedure my_proc { -args { {-n1 -default ""} {-n2 -default ""} {u1 -default ""} {u2 -default ""} } } { puts "n1:'$n1', n2:'$n2', u1:'$u1', u2:'$u2'" }
my_proc -n1 N1 -n2 N2 U1 U2 -> n1:'N1', n2:'N2', u1:'U1', u2:'U2'
my_proc U1 U2 -> n1:'', n2:'', u1:'U1', u2:'U2'
my_proc -n1 N1 -n2 N2 -n1 M1 U1 U2 -> n1:'M1', n2:'N2', u1:'U1', u2:'U2'
my_proc -n1 N1 -n2 N2 "->" "<-" -> my_proc: Argument '->' not known set U1 "->" my_proc -n1 N1 -n2 N2 $U1 U2 my_proc: Argument '->' not known
my_proc -n1 N1 -n2 N2 -- "->" "<-" -> n1:'N1', n2:'N2', u1:'->', u2:'<-' set U1 "->" my_proc -n1 N1 -n2 N2 -- $U1 U2 -> n1:'N1', n2:'N2', u1:'->', u2:'<-'
The Tk calling style will be chosen if a procedure is defined while the variable tepam::named_arguments_first is set to 0, or if the procedure attribute -named_arguments_first has been set to 0. The following procedure will be used in this section to illustrate this calling style:
set tepam::named_arguments_first 0 tepam::procedure my_proc { -args { {-n1 -default ""} {-n2 -default ""} {u1} {u2 -default "" -multiple} } } { puts "n1:'$n1', n2:'$n2', u1:'$u1', u2:'$u2'" }
my_proc U1 U2 -n1 N1 -n2 N2 -> n1:'N1', n1:'N1', u1:'U1', u2:'U2'
An argument value will only be assigned to an unnamed argument that is optional (that has either the -optional attribute or that has a default value), if the value is not beginning with the '-' character or if no named arguments are defined. The value that starts with '-' is otherwise considered as the name of a named argument.
Argument values are assigned to an argument that has the -multiple attribute as long as the parameter value doesn't starts with the '-' character.
Values that start with the '-' character can therefore not be assigned to optional unnamed arguments, which restricts the usage of the Tcl procedure calling style. The Tk style may be preferable in some cases, since it allows separating unambiguously the named arguments from the unnamed ones with the '--' flag.
Let's explore in a bit less theoretically the ways how the previously defined procedure can be called: The first example calls the procedure without any parameters, which leads to an error since u1 is a mandatory argument:
my_proc -> my_proc: Required argument is missing: u1
my_proc U1 -> n1:'', n2:'', u1:'U1', u2:''
my_proc U1 U2 U3 U4 -> n1:'', n2:'', u1:'U1', u2:'U2 U3 U4'
my_proc U1 U2 U3 U4 -U5 -> my_proc: Argument '-U5' not known
my_proc -n1 N1 -> n1:'', n2:'', u1:'-n1', u2:'N1'
my_proc U1 -n1 N1 -> n1:'N1', n2:'', u1:'U1', u2:''
my_proc U1 -n1 N1 U2 -> my_proc: Argument 'U2' is not an option
my_proc -- -n1 N1 -> n1:'N1', n2:'', u1:'--', u2:''
my_proc U1 -- -n1 N1 -> n1:'N1', n2:'', u1:'U1', u2:'' my_proc U1 -n1 N1 -- -n2 N2 -> n1:'N1', n2:'N2', u1:'U1', u2:''
It may be necessary sometimes that the procedure body is able to access the entire list of arguments provided during a procedure call. This can happen via the args variable that contains always the unprocessed argument list:
tepam::procedure {display_message} { -args { {-mtype -choices {Warning Error} -default Warning} {text -type string -multiple} } } { puts "args: $args" } display_message -mtype Warning "It is 7:00" -> args: -mtype Warning {It is 7:00}
tepam(3tcl), tepam::argument_dialogbox(3tcl)
argument integrity, argument validation, arguments, procedure, subcommand
Procedures, arguments, parameters, options
Copyright (c) 2009-2013, Andreas Drollinger
0.5.0 | tcllib |