tep...ure(3tcl)
โจ NAME โจ
tepam::procedure โ the TEPAM procedure, reference manual ๐
(TEPAM = Tcl's Enhanced Procedure and Argument Manager, and yes bestie, it ate)
๐ธ SYNOPSIS ๐ธ
package require Tcl 8.5 9
package require tepam ?0.5?
tepam::procedure name attributes body
๐ฆ DESCRIPTION ๐ฆ
okay so listen โ this package is literally an alternative way to declare Tcl procedures and to manage their arguments. and the way that declaring a procedure with TEPAM is just so much better than doing it with the standard Tcl proc? iconic, honestly:
- TEPAM lets you specify, inside the procedure declaration itself, every single piece of info you need to generate comprehensive documentation and help support. no more writing docs somewhere else and pretending you'll keep them in sync ๐
- that same info gets used by an automatically invoked argument checker that validates the arguments you hand the procedure before the procedure body even runs. it's giving bodyguard energy ๐ซถ
- and finally โ a procedure can be called interactively, which opens a graphical form that lets you specify the procedure arguments. cute!! ๐
TEPAM also simplifies handling the different types of argument โ the named arguments (which people also call options) and the unnamed arguments. it supports the named first, unnamed later style (the typical Tcl command style) and the unnamed first, named later style (the typical Tk command style). TEPAM takes care of default values for arguments, optional arguments, multiple applicable arguments, etc. etc. and it eliminates the need to check the validity of the argument inside the procedure bodies. periodt. ๐
if you want the informal overview of all the TEPAM procedure declaration and calling features, plus a short intro to TEPAM, that's over in tepam(3tcl). ๐
๐ TERMINOLOGY ๐
before we go any further, let's get the vocabulary locked in, because the exact meaning of these terms matters and we are not doing ambiguities or misunderstandings today โ
Subcommand
the usage of subcommands is heavily used in the Tcl language. several commands get incorporated into a single main command, and you select them via the first argument.
the string command is an example of such a command โ it 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 lets you implement such subcommands easily, in the form of Tcl procedures. and not just a first level of subcommands โ a higher level too, bestie. 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
...
Procedure attribute
TEPAM lets you attach different kinds of attributes to a declared procedure. some of these attributes are just there for documentation purposes, but other attributes specify the way the procedure has to be called. also: the procedure arguments themselves are defined in the form of a procedure attribute. ๐ง
Argument
TEPAM uses the term argument for the parameters of a procedure.
the following example calls the subcommand string compare with several arguments:
string compare -nocase -length 3 "emphasized" "emphasised"
the following paragraphs discuss these different argument types. ๐
Named argument
some parameters โ like -length 3 of the subcommand string compare โ have to be provided as pairs of argument names and argument values. this parameter type is often also called an option.
TEPAM uses the term named argument for such options as well as for the flags (see next item).
Flag, switch
another parameter type is the flag or the switch. flags are provided simply by naming the flag, leading with the - character. the -nocase of the previous string compare example is such a flag.
flags are considered by TEPAM like a special form of named arguments. ๐ซ
Unnamed argument
for the other parameters โ the ones where the argument name has not got to be mentioned โ TEPAM uses the term unnamed argument. the previous string compare example uses two unnamed arguments for the two provided character strings.
Argument attribute
TEPAM lets you describe the purpose of each procedure argument with argument attributes. while some of them are just documenting the attributes, most attributes are used by an argument manager to control and validate the arguments that are provided during a procedure call. argument attributes are used to specify default values, parameter classes (integer, xdigit, font, ...), choice validation lists, value ranges, etc. ๐ฅ
Named arguments first, unnamed arguments later
the string compare command of the previous example requires that the named arguments (options, flags) are provided first. the two mandatory (unnamed) arguments have to be provided as the last argument.
string compare -nocase -length 3 Water $Text
this is the usual Tcl style (exceptions exist) which is referred to in the TEPAM documentation as the named arguments first, unnamed arguments later style.
Unnamed arguments first, named arguments later
in contrast to most Tcl commands, Tk generally (exceptions exist here too) uses a different calling style, where the unnamed arguments have to be provided first, before the named arguments are provided:
pack .ent1 .ent2 -fill x -expand yes -side left
this style is referred to in the TEPAM documentation as the unnamed arguments first, named arguments later style. ๐ธ
๐ PROCEDURE DECLARATION ๐
TEPAM lets you declare new Tcl procedures with the command tepam::procedure, which โ similar to the standard Tcl command proc โ also takes 3 arguments:
tepam::procedure name attributes body
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"
}
the 3 arguments of procedure are:
name
the procedure name can be used in very flexible ways. procedure names can have namespace qualifiers. by providing a two element name list as the procedure name, a subcommand of a procedure will be declared. it is even possible to declare sub-sub-commands of a procedure by providing name lists with three elements. ๐
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} {} {}
attributes
all procedure attributes are provided in the form of an option list that contains pairs of option names and option values. the example above has, as procedure attributes, a short and a normal description โ but also the procedure arguments are defined in the form of a procedure attribute.
most procedure attributes are providing information for documentation purposes. but some of them also affect the way the procedure can be called. the section Procedure Attributes discusses the available procedure attributes in detail.
the procedure arguments are defined in the form of a special procedure attribute. most of the information provided in the argument definition is not just used for documentation purposes โ that 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 all the argument definition attributes in detail.
body
this is the normal procedure body. the declared arguments will be available to the procedure body in the form of variables.
the procedure body will only be executed if the provided set of arguments could be validated by the TEPAM argument manager. no valid args, no body. simple as that bestie ๐
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 {
...
๐ PROCEDURE ATTRIBUTES ๐
the first group of attributes affect the behavior of the declared procedure:
-named_arguments_first 0|1
this attribute defines the calling style of a procedure. TEPAM uses by default the named arguments first, unnamed arguments later style (Tcl). this default behavior can globally be changed by setting the variable tepam::named_arguments_first to 0. this global calling style can be changed individually for a procedure with the -named_arguments_first attribute. ๐ฆ
-auto_argument_name_completion 0|1โ bestie, by default every procedure you declare will automatically try to match abbreviated argument names against the actual defined ones (so you can type half an option name and it just gets it ๐ ). Wanna kill that globally? Set the variabletepam::auto_argument_name_completionto0. Wanna change it for one single procedure instead? That's what the-auto_argument_name_completionprocedure attribute is for. per-procedure control, iconic behavior. โจ-interactive_display_format extended|shortโ any procedure declared with the TEPAM procedure command can always be called with the-interactiveoption, and when you do that, a whole graphical form pops up so you can fill in all the argument values. There are two display modes for these forms. The extended mode is more adapted for small procedure argument sets, while the short form is more adequate for huge procedure argument sets. ๐
You can set the short-vs-extended choice globally through the variable tepam::interactive_display_format. And that global setting can then be changed individually for a single procedure with the -interactive_display_format procedure attribute. so much flexibility, we love her. ๐ฆ
-args listโ all the procedure arguments get declared through the-argsattribute. Each argument is defined via a list whose first element is the argument name, followed by eventual argument attributes. Then all those argument definition lists are packaged up themselves into one global list, and that is what you assign to-args. ๐ฆ
The argument definition syntax gets described way more in detail in the following sub section (keep scrolling, bestie, it's right there ๐).
The next attributes let you specify custom argument checks as well as custom error messages for when those checks fail:
-validatecommand scriptโ custom argument validations happen through specific validation commands, which you define with the-validatecommandattribute. โ
Here's a validation command declaration example:
tepam::procedure {display_message} {
-args {
{text -type string -description "Message text"} }
-validatecommand {IllegalWordDetector $text}
} {
}
The validation command is executed in the context of the declared procedure body. The different argument values get accessed via the argument names. ngl, heads up: there's also an argument attribute -validatecommand that lets you declare custom checks for specific arguments. And the attribute -validatecommand can be repeated to declare multiple custom checks. ๐ฅ
-validatecommand_error_text stringโ this attribute lets you override the default error message for a custom argument validation (the one defined by-validatecommand). And yes, this attribute can be repeated too, in case you've declared multiple argument checks. ๐
The following attribute controls the logging settings for an individual procedure:
-command_log 0|1|"interactive"โ this one configures the logging of procedure calls into the list variabletepam::ProcedureCallLogList. If you don't define this argument in a procedure declaration, the default configuration defined by the variabletepam::command_loggets used. ๐
Setting this argument to 0 disables any procedure call loggings. Setting it to 1 logs any procedure calls. And setting it to interactive logs just the procedures that are called interactively (aka procedures called with the -interactive flag). pick your vibe. ๐ธ
The next group of procedure attributes is just used for the purpose of documentation and help text generation:
-category stringโ you can assign a category to a procedure for documentation purposes. Any string is accepted as category. ๐ซ-short_description stringโ the short description of a procedure is used in the documentation summary of a generated procedure list, and also in the NAME section of a generated procedure manual page. ๐-description stringโ the (full) description assigned to a procedure is used to create user manual and help pages. the main character of doc generation, honestly. ๐-return stringโ the-returnattribute lets you define the expected return value of a procedure (used for documentation purposes). ๐-example stringโ a help text or manual page of a procedure can be enriched with eventual examples, using the-exampleattribute. show don't tell, periodt. โจ
๐ ARGUMENT DECLARATION ๐
Okay so this example shows the structure used for 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"}
}
} {
}
Each of the procedure arguments is declared with a list that has as first element the argument name, followed by eventual attributes. And the argument definition syntax can be formalized like this:
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>
The argument names and attributes have to be used in the following way:
๐ Argument name (<argument_name_<n>>)
The argument name you provide specifies whether the argument is an unnamed argument or a named argument. On top of that, an argument name can also be blank to indicate an argument comment, or it can start with # to indicate a section comment. three whole personalities, honestly. ๐
"<Name>"โ this is the simplest form of an argument name: an argument whose name does not start with-is an unnamed argument. The parameter provided during a procedure call gets assigned to a variable with the name<Name>. ๐
tepam::procedure {print_string} {
-args {
{text -type string -description "This is an unnamed argument"}
}
} {
puts $text
}
print_string "Hello"
-> Hello
"-<Name>"โ an argument whose name starts with-is a named argument (also called an option, iykyk). The parameter provided during a procedure call gets assigned to a variable with the name<Name>(not-<Name>, mind the dash, bestie). ๐
tepam::procedure {print_string} {
-args {
{-text -type string -description "This is a named argument"}
}
} {
puts $text
}
print_string -text "Hello"
-> Hello
--โ this flag lets you clearly specify the end of the named arguments and the beginning of the unnamed arguments, in case the named arguments first, unnamed arguments later style (Tcl) has been selected. โญ
If the unnamed arguments first, named arguments later style (Tk) is selected instead, this flag is ignored if the unnamed arguments have already been parsed. Otherwise it will be assigned to the corresponding unnamed argument.
"-"or""โ a blank argument name (either-or'') starts a comment for the following arguments. ๐
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]"
}
Argument comments are basically used in the graphical argument definition forms that get created if a procedure is called interactively. ๐ฆ
"#*"โ an argument definition list that starts with#is considered a section comment. The argument definition list gets trimmed of the#characters, and the remaining string is used as the section comment. ๐
Section comments can be used to structure visually the argument definition code. They're also used to structure the generated help texts and the interactive argument definition forms. cute and functional.
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 "First number real part"}
{-i1 -type double -description "First number imaginary part"}
}
} {
return [expr $r0*$r1 - $i0*$i1]
}
๐ Argument attributes (<arg_attr_name_<mn>> <arg_attr_value_<mn>>)
The following argument attributes are supported:
-description stringโ the description argument attribute is used for documentation purposes. Interactive argument definition forms use this attribute to provide explanations for an argument. ๐-typetype โ assigns your argument to either a predefined data type or one of your very own application-specific data types ๐ . Every value that gets passed in during a procedure call is automatically vibe-checked against the type you declared.
The ARGUMENT TYPES section has the full list of predefined data types and explains how you can roll your own application specific ones.
Now here's the โจspecialโจ one: the type none. An argument typed none gets handled as a flag. A flag is always optional, and its variable holds the logical value 1 if the flag was defined during the procedure call โ otherwise 0. Periodt.
-defaultvalue โ you can hand an argument eventual default values with the-defaultattribute. And heads up bestie: arguments with default values automatically become optional arguments. No extra work, it's giving effortless ๐.-optional|-mandatoryโ arguments are mandatory by default, unless a default value is defined. The flag-optionaltransforms an argument into an optional one.
If an optional argument isn't defined during a procedure call, its corresponding variable justโฆ won't be defined. That's it, that's the whole thing ๐.
The flag -mandatory is the opposite of -optional. It literally only exists for completion reasons, since an argument is mandatory by default anyway. Iconic filler energy ๐.
-multipleโ arguments with the-multipleattribute can be defined more than once during a procedure call ๐ฅ. All the values provided for such an argument get stored in a list variable โ and yes, even if that argument is only defined once during the call. List variable, always.
You can slap -multiple on unnamed arguments and on named arguments. For a named argument, the argument name/argument value pair has to be repeated for each provided value. And if the -multiple argument is an unnamed one? It has to be the absolute last one of all unnamed arguments. Non-negotiable, it's the main character of the list ๐.
-choiceslist โ you can attribute a possible set of valid argument values to an argument via the-choicesattribute. Whatever value shows up during a procedure call gets checked against those choice values. If it's not on the list, it's not invited to the party ๐ซ.-choicelabelslist โ every choice option can get its own eventual short description via the-choicelabelsattribute ๐ท๏ธ. These descriptions get used in the generated help texts, and as the radio and check box labels for interactive calls.
It's optional, but if you define it, its list needs to have the identical size as the -choices argument list. Matching sizes only, no exceptions ๐ซถ.
-range {double double}โ another argument constraint, served fresh with the-rangeattribute. The valid range is defined with a list containing the minimum valid value and a maximum valid value. And this one has to be used only for numerical arguments, like integers and doubles. Math only, bestie ๐งฎ.-validatecommandscript โ you can run your own custom argument value validations through specific validation commands, defined with the-validatecommandattribute โจ. The validation command you provide can be a complete script, and inside it the pattern%Pgets replaced by the argument value that has to be validated.
Validation command declaration example:
tepam::procedure {display_message} {
-args {
{text -type string -description "Message text" \
-validatecommand {IllegalWordDetector %P}}
} {
}
So like โ the whole point of this custom attribute is validating one specific argument. But plot twist: there's also a global attribute -validatecommand that lets you do validation involving multiple arguments. Both exist, both serve ๐.
-validatecommand_error_textstring โ this attribute lets you override the default error message for a custom argument validation (the one defined by-validatecommand). Customize your own chaos text ๐ญ.-widgetstring โ when a procedure is called interactively, the widgets that let you define the different arguments are normally picked automatically, based on the argument type. The-widgetattribute lets you explicitly specify a certain widget type for an argument. Manual override unlocked ๐.-auxargslist โ if a procedure gets called interactively, you can feed additional argument attributes to the interactive argument definition form via the-auxargsattribute. And that attribute is itself a list of attribute name/attribute value pairs:
-auxargs {-<arg_attr_name_1a> <arg_attr_value_1a> \
-<arg_attr_name_1b> <arg_attr_value_1b>
...
}
For example โ if a procedure takes a file name as an argument, it might be a whole vibe to specify the required file type for the interactive argument definition form. You can pass that info via -auxargs to the argument definition form:
tepam::procedure LoadPicture {
-args {
{FileName -type existingfile -description "Picture file" \
-auxargs {-filetypes {{"GIF" {*.gif}} {"JPG" {*.jpg}} }}}
}
} {
}
-auxargs_commandsscript โ if your auxiliary argument attributes aren't static but need to be dynamically adaptable,-auxargs_commandslets you define them via commands that are executed during a procedure call ๐. You provide a list of pairs of auxiliary attribute names and commands. Those commands run in the context of the calling procedure.
-auxargs_commands {-<arg_attr_name_1a> <arg_attr_command_1a> \
-<arg_attr_name_1b> <arg_attr_command_1b>
...
}
โจ VARIABLES โจ
There are several variables defined inside the ::tepam namespace, and they impact the mode of operation of the procedures you declared with the TEPAM procedure command. Basically: global knobs, bestie ๐๏ธ.
๐ธ named_arguments_first
This variable defines the general calling style of the procedures. By default it's set to 1, which selects the named arguments first, unnamed arguments later style (Tcl style).
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
And while this variable sets the general calling style, the procedure attribute -named_arguments_first can adapt this style individually for each declared procedure. Global vibe, local override ๐
.
๐ธ auto_argument_name_completion
This variable controls the general automatic argument name matching mode. By default it's 1, meaning the called procedures try to match eventually abbreviated argument names with the declared argument names. So you can be lazy with your typing and it just gets you ๐ซถ.
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.
๐ธ interactive_display_format
A procedure declared via the TEPAM procedure command can always be called with the -interactive switch. When you do that, a graphical form gets generated that lets you enter all procedure arguments interactively โจ.
There are two display modes for these interactive forms. The extended mode is the default, and it's 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 between short and extended forms can be globally configured via the variable interactive_display_format. And that global setting can be changed individually for a procedure with the procedure attribute -interactive_display_format ๐.
๐ธ help_line_length
The maximum line length used by the procedure help text generator can be specified with this variable. The default length is set to 80 (characters), and it can easily be adapted to the need of an application:
set tepam::help_line_length 120
Since this variable is applied directly during the help text generation, its value can continuously be adapted to the current need. Live tweaking, we love to see it ๐ฅ.
๐ธ command_log
Procedure calls can be logged inside the list variable tepam::ProcedureCallLogList. The variable tepam::command_log controls the default logging settings for any procedures. Here's what's supported:
0: Disables any procedure call loggings1: Enables any procedure call loggings"interactive": Will log any procedures called interactively (e.g. procedures called with the-interactiveflag). This is the default configuration.
This default logging configuration can be changed individually for each procedure with the -command_log attribute ๐.
๐ ARGUMENT TYPES ๐
okay bestie, this is the part where it gets good. TEPAM ships with a whole wardrobe of procedure argument types โ a comprehensive set, fr fr. And if none of them slay for your app, you can add your own application specific types. Easy. ๐
โจ PREDEFINED ARGUMENT TYPES โจ
so quick refresher bestie: you can assign a type to each argument you specify in a procedure. Like this:
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"}
}
} {
...
}
now, there are some special purpose types that build up the first category of predefined argument types. Let's go one by one ๐ซถ
noneโ a flag, also called a switch, is a named argument that has the typenone. Flags are always optional, and the default value of the assigned variable gets set to0. And here's the twist: unlike the (normal) named arguments, you don't have to hand a flag any argument value at all. โจ
tepam::procedure flag_test {
-args {
{-flag -type none -description "This is a flag"}
}
} {
puts $flag
}
flag_test
-> 0
flag_test -flag
-> 1
and since no argument value is provided to a flag, no data check is performed for this argument type either. periodt.
stringโ the generic argument data type, the main character of types honestly. Any data string can be given to astringtype argument, so no data type checks are performed. Thestringtype also lets you define single line strings during interactive procedure calls. ๐ธtextโ literally identical tostring, the only difference being that it lets you enter multi line strings during interactive procedure calls. that's it, that's the tea. ๐ฆ{}โ a blank argument type means an undefined argument type. This is the default argument type used when you didn't explicitly specify one. An argument with a blank type behaves identically to one with astringtype โ like, no argument data checks, none. The only difference: the data typestringis mentioned in the generated help documentation, while for the blank type it isn't. ๐
Several numerical types are defined by TEPAM. Their type validation procedures use the string is <type> -strict commands to check whether the provided arguments are valid, which assures that no empty strings are accepted as argument value. The type validation expression for the numerical types, and the argument types it applies to, is:
string is <type_to_check> -strict <argument_value>
booleanintegerdouble
Empty strings are accepted as argument value for all the alpha numeric argument types. The argument types falling into this category, and the validation expression used for them, are:
string is <type_to_check> <argument_value>
alnumalphaasciicontroldigitgraphlowerprintpunctspaceupperwordcharxdigit
On top of the data types checked with the string is <type> commands, TEPAM specifies some other genuinely useful data types:
charโ any 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
colorโ any character strings that Tk accepts as a color are considered valid color arguments. Please note that the Tk package has to be loaded to use the typecolor. TEPAM uses the following command to validate the color type:
expr ![catch {winfo rgb . <argument_value>}]
fontโ any character strings that Tk accepts as a font are considered valid font arguments. Please note that the Tk package has to be loaded to use the typefont. TEPAM is using the following command to validate the color type:
expr ![catch {font measure <argument_value> ""}]
fileโ any strings that do not contain one of the following characters are considered valid file names:*?"<>. It is not necessary that the file and its containing directory exist. Zero-length strings are not considered valid file names. The following expression is used to validate the file names:
expr [string length <argument_value>]>0 && ![regexp {[\"*?<>:]} <argument_value>]
existingfileโ the argument is valid if it matches with an existing file. The following check is performed to validate arguments of this type:
file exists <argument_value>
directoryโ the directory argument is validated exactly in the same way as the file arguments. iykyk.existingdirectoryโ the argument is valid if it matches with an existing directory. The following check is performed to validate arguments of this type:
file isdirectory <argument_value>
๐ง DEFINING APPLICATION SPECIFIC ARGUMENT TYPES ๐ง
want to add support for a brand new application specific argument type? bestie it's so simple. You just add a validation function Validation(<type>) into the namespace tepam. This function takes one argument, and it has to return 1 if the provided argument matches the relevant data type. Otherwise it has to return 0. no cap. ๐
The validation command section of the "tepam.tcl" package has plenty of examples of validation functions, since it implements the ones for the standard TEPAM types. ๐
and here's a lil extra snippet showing the validation function for a custom argument type that only accepts values with a character string length of exactly 2:
proc tepam::Validate(two_char) {v} {expr {[string length $v]==2}}
๐ฅ PROCEDURE CALLS ๐ฅ
๐ HELP
Every 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. iconic.
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"
the argument manager checks whether the last provided argument is -help, and generates the requested help message if that's the case. So this next example will also print the help message:
display message -mtype Info "It is 7:00" -help
but on the flip side bestie, this call right here will throw an error:
display message -help -mtype Info "It is 7:00"
->
display message: Argument '-help' not known
๐ธ INTERACTIVE PROCEDURE CALL ๐ธ
If Tk has been loaded, a procedure can be called with the -interactive flag to open a graphical form that lets you specify all the procedure arguments interactively. The following example makes sure the Tk library is loaded and shows the command line to call the procedure declared in PROCEDURE CALLS interactively:
package require Tk
display message -interactive
also the -interactive flag has to be placed at the last argument position, same as what's required for the -help flag. Arguments defined before the -interactive flag will be ignored. So this next one is also a valid interactive procedure call:
display message -mtype Info "It is 7:00" -interactive
๐ UNNAMED ARGUMENTS ๐
unnamed arguments are typically handed to the called procedure as simple parameters. This calling form requires that the provided arguments strictly follow the order of the specified arguments. Several parameters can be assigned to the last argument if that one has the -multiple attribute. So the procedure declared like this...
tepam::procedure {display_message} {
-args {
{mtype -choices {Info Warning Error}}
{text -type string -multiple}
}
} {
puts "$mtype: [join $text]"
}
...can for example be called in the following ways:
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.
and the nice thing is that unnamed arguments can also be called as named arguments, which is lowkey handy โ for example if a user doesn't know the exact specified argument order:
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 ๐
Named arguments have to be provided to a procedure in the form of parameter pairs made up of the argument names and the argument values. The order in which you provide them during a procedure call is irrelevant and does not have to match the argument specification order. main character energy fr.
The following declared procedure...
tepam::procedure {display_message} {
-args {
{-mtype -choices {Info Warning Error}}
{-text -type string -multiple}
}
} {
puts "$mtype: [join $text]"
}
...can be called in the following ways:
display_message -mtype Info -text "It is PM 7:00."
-> Info: It is PM 7:00.
Also, named arguments that don't have the -multiple attribute can still be handed over more than once, bestie โ the parser just keeps the last one you gave it and pretends the earlier ones never happened:
display_message -mtype Info -text "It is PM 7:00." -mtype Warning
-> Warning: It is PM 7:00.
๐ UNNAMED ARGUMENTS FIRST, NAMED ARGUMENTS LATER (TK STYLE) ๐
Okay so a procedure that got defined while the variable tepam::named_arguments_first was set to 1, or one that was declared with the procedure attribute -named_arguments_first set to 1, has to be called the Tk way. Here's the declaration we're gonna vibe with for this whole section:
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'"
}
The unnamed arguments go at the end of the procedure call, after all the named ones. Periodt:
my_proc -n1 N1 -n2 N2 U1 U2
-> n1:'N1', n2:'N2', u1:'U1', u2:'U2'
And the way the argument parser decides? The first argument that doesn't start with the - character, plus literally everything after it, counts as unnamed arguments:
my_proc U1 U2
-> n1:'', n2:'', u1:'U1', u2:'U2'
Named arguments can totally be defined multiple times, no drama. If that named argument has the -multiply attribute, all the values get collected into a list. If it doesn't, only the last value survives the vibe check:
my_proc -n1 N1 -n2 N2 -n1 M1 U1 U2
-> n1:'M1', n2:'N2', u1:'U1', u2:'U2'
So this means the name of the first unnamed argument cannot start with the - character. If it does, the unnamed argument gets read as the name of yet another named argument instead. This is a whole thing when that first unnamed argument comes from a variable that could hold any string, iykyk:
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
Enter the -- flag, our savior ๐
. It separates the unnamed arguments from the named ones with zero ambiguity. Everything after -- is treated as unnamed argument, full stop:
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:'<-'
โจ NAMED ARGUMENTS FIRST, UNNAMED ARGUMENTS LATER (TCL STYLE) โจ
The Tk calling style gets picked if a procedure is defined while tepam::named_arguments_first is set to 0, or if the procedure attribute -named_arguments_first was set to 0. Here's our star procedure for this section:
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'"
}
Now the unnamed arguments come first, and the named ones show up after:
my_proc U1 U2 -n1 N1 -n2 N2
-> n1:'N1', n1:'N1', u1:'U1', u2:'U2'
The argument parser hands a value to each defined unnamed argument before it even thinks about switching over to read the named arguments. But heads up โ that default behavior gets a little โจquirkyโจ when some unnamed arguments are optional or can take multiple values.
An argument value only gets assigned to an unnamed argument that's optional (so, one with either the -optional attribute or a default value) if the value doesn't start with the - character โ or if there are no named arguments defined at all. A value that does start with - gets read as the name of a named argument instead.
Argument values keep getting assigned to an argument with the -multiple attribute for as long as the parameter value doesn't start with the - character.
Which means: values starting with - can never be assigned to optional unnamed arguments. That's a real restriction on the Tcl procedure calling style, ngl. The Tk style might be your better bet sometimes, since it lets you separate the named arguments from the unnamed ones unambiguously with the -- flag. Slay.
Let's get a little less theoretical and actually explore how the procedure above can be called. First example: no parameters at all โ which explodes, because u1 is mandatory:
my_proc
-> my_proc: Required argument is missing: u1
The call is valid the moment one parameter is provided for u1:
my_proc U1
-> n1:'', n2:'', u1:'U1', u2:''
If you hand over more parameters that don't start with -, they get attributed to the unnamed arguments. U2 gets 3 of them here, because it accepts multiple values:
my_proc U1 U2 U3 U4
-> n1:'', n2:'', u1:'U1', u2:'U2 U3 U4'
The second a parameter starts with - and all unnamed arguments have been assigned, the argument manager tries to read that parameter as the name of a named argument. And the whole call fails if a value beginning with - gets assigned to an unnamed argument:
my_proc U1 U2 U3 U4 -U5
-> my_proc: Argument '-U5' not known
Attributing a parameter to a named argument will fail if there are still undefined unnamed (non-optional) arguments hanging around. In that case the name specification just gets treated as a plain parameter value, and it goes to the next unnamed argument. Which was absolutely not the intention here, bestie, I promise:
my_proc -n1 N1
-> n1:'', n2:'', u1:'-n1', u2:'N1'
But the whole situation flips completely once values have already been assigned to all the mandatory unnamed arguments. Then a parameter starting with - gets read as a name identifier for a named argument:
my_proc U1 -n1 N1
-> n1:'N1', n2:'', u1:'U1', u2:''
No unnamed arguments allowed behind the named arguments. None. Zero:
my_proc U1 -n1 N1 U2
-> my_proc: Argument 'U2' is not an option
The -- flag has no special meaning at all if not all mandatory arguments have been assigned a value yet. It just gets attributed to one of the unnamed arguments like it's nothing:
my_proc -- -n1 N1
-> n1:'N1', n2:'', u1:'--', u2:''
But -- is simply ignored once the argument parser has started handling the named arguments:
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:''
๐ฆ RAW ARGUMENT LIST ๐ฆ
Sometimes the procedure body just needs to see the entire list of arguments from the call. And it can! Through the args variable, which always holds 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}
๐ SEE ALSO ๐
tepam(3tcl), tepam::argument_dialogbox(3tcl)
โญ KEYWORDS โญ
argument integrity, argument validation, arguments, procedure, subcommand
๐ CATEGORY ๐
Procedures, arguments, parameters, options
๐ COPYRIGHT ๐
Copyright (c) 2009-2013, Andreas Drollinger
And that's a wrap on this whole page, bestie ๐ซถ this was tcllib 0.5.0, and the page itself is dated โ so go forth, validate those arguments, and keep your mandatory params fully assigned. No cap, you ate. ๐ โจ
๐ฆ where this page comes from
- debian trixie: tcllib 2.0+dfsg-4 ยท Tcl
- ubuntu questing: tcllib 2.0+dfsg-4
- ubuntu resolute: tcllib 2.0+dfsg-5 ยท Tcl
- ubuntu stonking: tcllib 2.0+dfsg-6 ยท Tcl
- Copyright (c) 2009-2013, Andreas Drollinger
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms