tepam(n)

πŸ“¦
version 2.0 Β· 2 versions
, in fedora 43, fedora 44, nixos 26.05, nixpkgs unstable

πŸ’– tepam(n) β€” Tcl's Enhanced Procedure and Argument Manager πŸ’–

okay so bestie, welcome to tepam β€” an intro to TEPAM, aka Tcl's Enhanced Procedure and Argument Manager. grab a snack, this one's a whole journey πŸ“


✨ NAME ✨

tepam β€” An introduction into TEPAM, Tcl's Enhanced Procedure and Argument Manager πŸŽ€


🌸 DESCRIPTION 🌸

So this doc? It's the informal intro to TEPAM, Tcl's Enhanced Procedure and Argument Manager. Like, the chill vibes version πŸ’…

If you want the detailed, no-stone-unturned tea, that lives in the tepam::procedure and tepam::argument_dialogbox reference manuals. go read those when you're ready to go full academic 🧚


πŸ¦‹ OVERVIEW πŸ¦‹

okay so here's the whole vibe: this package gives you a brand new Tcl procedure declaration syntax that makes implementing procedure subcommands and handling all the different flavors of procedure arguments so much easier β€” flags/switches, options, unnamed arguments, optional vs mandatory stuff, default values, all of it ✨

And you can enrich your procedure declarations with detailed info about the procedure and its arguments. That info then gets used for a bunch of things:

  • First off: when you declare a procedure with TEPAM, a preamble gets added in front of the procedure body. That preamble calls an argument manager which uses all that info you provided to check the validity of argument types and values before the procedure body even runs. slay 🫢
  • Then that same info gets used to generate help and usage texts when requested, or to generate clear error messages when an argument validation fails.
  • It also lets you auto-generate graphical forms for interactively defining all the arguments, in case a procedure gets called interactively. iconic.
  • And finally, that extra info helps self-document your procedure declaration and all its arguments in a clean way πŸ’…

Oh and β€” the graphical form generator that builds those argument specification forms for interactive procedure calls? It's not just for procedure arguments. You can use it for other purposes too. It lets you efficiently create complex parameter entry forms that work independently from TEPAM's new procedure definition method. versatile queen πŸ‘‘

🌈 Here's the short overview of all the major TEPAM features 🌈

  • New self-documenting procedure declaration syntax: You don't need extra statements to properly declare a procedure with all its extra info β€” you can just add it in a natural syntax directly into the procedure header. no cap.
  • Easy way to specify subcommands: A subcommand is declared like a procedure, simply with a procedure name composed of a base name followed by a subcommand name. Sub-subcommands? Same deal β€” just procedure names composed of 3 words. nesting queen πŸŽ€
  • Flexible usage of flags (switches), options (named arguments) and unnamed arguments. Option names are optionally automatically completed ✨
  • Support for default values, mandatory/optional options and arguments, choice lists, value ranges, and multiple usable options/arguments.
  • Choice of calling style: named arguments first + unnamed arguments later (the typical Tcl command style), or unnamed arguments first + named arguments later (the typical Tk command style). pick your fighter πŸ’…
  • In case the named-arguments-first, unnamed-arguments-later style (Tcl) is selected: there's a clean separation between options and arguments via the -- flag. And the unnamed arguments can optionally be accessed as options (named arguments) πŸ‘‘
  • Automatic type and value check before the procedure body is executed β€” taking into account validation ranges, choice lists and custom validation commands. Plus generation of clear error messages if something's off. no silent failures bestie 😭
  • Many predefined types exist β€” integer, boolean, double, color, file, font, ... β€” and other application-specific types can easily be added. DIY queen 🧚
  • Automatic help and usage text generation if a procedure is called with the -help flag.
  • Automatic generation of an interactive argument definition form, in case a procedure is called with the -interactive flag. it's giving luxury πŸ’…
  • Procedure calls can be logged β€” which is useful to get the command call lines for interactively called procedures.
  • Powerful and code efficient generation of complex parameter definition forms πŸ”₯

πŸ’œ PROCEDURE DECLARATION πŸ’œ

TEPAM's procedure declaration syntax is simple and self-explaining. Instead of declaring a procedure with the Tcl key word proc, you declare it with the TEPAM command procedure β€” which takes, just like proc, 3 arguments:

  1. The procedure name
  2. The procedure header
  3. The procedure body

The following example declares the subcommand message of the procedure display. This command has several named and unnamed arguments:

tepam::procedure {display message} {
   -return            -
   -short_description "Displays a simple message box"
   -description       "This procedure allows displaying a configurable message box."
   -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 -default black -description "Message color"}
      {-bg -type color -optional -description "Background color"}
      {-no_border -type none -description "Use a splash window style (no border)"}
      {-log_file -type file -optional -description "Optional message log file"}
      {text -type string -multiple -description "Multiple text lines to display"}
   }
} {
   puts "display message:"
   foreach var {mtype font level fg bg no_border log_file text} {
      if {[info exists $var]} {
         puts  "  $var=[set $var]"
      }
   }
}

A call of a procedure declared this way will first invoke the TEPAM argument manager, before the procedure body gets executed. The argument manager:

  • parses the provided arguments
  • validates them
  • completes them eventually with some default values
  • makes them finally available to the procedure body as local variables

And if an argument is missing or has a wrong type? The argument manager generates an error message that explains the reason for the error. transparent king πŸ‘‘

As the example above shows, the TEPAM command procedure accepts subcommand definitions as the procedure name, and lets you define way more info than just the argument list inside the procedure header. The procedure body, on the other hand, is identical between a command declared with proc and a command declared with procedure. no diff fr fr

The procedure header lets you define, on top of the arguments, some procedure attributes β€” like a description, info about the return value, etc. That info is basically used for the automatic generation of comprehensive help and usage texts ✨

A list of argument definition statements assigned to the -args argument is what defines the procedure arguments. Each argument definition statement starts with the argument name, optionally followed by some argument attributes.

πŸŽ€ Three types of arguments can be defined πŸŽ€

  • Unnamed arguments
  • Named arguments
  • Flags

The distinction between named and unnamed arguments is made by the first character of the argument name β€” which is simply - for named arguments. And a flag is defined as a named argument that has the type none. that's it, that's the whole secret πŸ’…

Named and unnamed arguments are mandatory, unless they're declared with the -optional flag, and unless they have a default value specified with the -default option. Named arguments and the last unnamed argument can have the attribute -multiple, which means they can be defined multiple times ✨

The expected argument data type is specified with the -type option. TEPAM defines a large set of standard data types, which can easily be completed with application-specific data types 🧚

Heads up bestie: the argument declaration order only matters for unnamed arguments β€” which by default are parsed after the named arguments (Tcl style). There's a variable that lets you change this behavior so that unnamed arguments get parsed first, before the named arguments (Tk style). plot twist πŸ’…

🌟 PROCEDURE HELP 🌟

Your declared procedure can simply be called with the -help option to get all the info about the usage of the procedure and its arguments:

display message -help
  ->
NAME
      display message - Displays a simple message box
SYNOPSYS
      display message
            [-mtype <mtype>] :
               Message type, default: "Warning", choices: {Info Warning Error}
            [-font <font>] :
               Message text font, type: font, default: Arial 10 italic
            [-level <level>] :
               Message level, type: integer, range: 1..10
            [-fg <fg>] :
               Message color, type: color, default: black
            [-bg <bg>] :
               Background color, type: color
            [-no_border ] :
               Use a splash window style (no border)
            [-log_file <log_file>] :
               Optional message log file, type: file
            <text> :
               Multiple text lines to display, type: string
DESCRIPTION
      This procedure allows displaying a configurable message box.

look at that. auto-generated, perfectly formatted, chef's kiss πŸ˜­πŸ’–

πŸ¦‹ PROCEDURE CALL πŸ¦‹

okay so your procedure can get called in so many ways, it's giving versatile πŸ’… here's a whole list of totally valid calls, look at her go:

       display message "The document hasn't yet been saved!"
       -> display message:
            mtype=Warning
            font=Arial 10 italic
            fg=black
            no_border=0
            text={The document hasn't yet been saved!}

       display message -fg red -bg black "Please save first the document"
       -> display message:
            mtype=Warning
            font=Arial 10 italic
            fg=red
            bg=black
            no_border=0
            text={Please save first the document}

       display message -mtype Error -no_border "Why is here no border?"
       -> display message:
            mtype=Error
            font=Arial 10 italic
            fg=black
            no_border=1
            text={Why is here no border?}

       display message -font {Courier 12} -level 10 \
          "Is there enough space?" "Reduce otherwise the font size!"
       -> display message:
            mtype=Warning
            font=Courier 12
            level=10
            fg=black
            no_border=0
            text={Is there enough space?} {Reduce otherwise the font size!}

bestie notice how the defaults just show up in the output even when you didn't pass them? yeah. she's generous like that ✨


now let's talk about when things go wrong, because they will, and tepam is not quiet about it. The next lines show how wrong arguments are recognized. The text argument that is mandatory is missing in the first procedure call:

       display message -font {Courier 12}
         -> display message: Required argument is missing: text

Only known arguments are accepted:

       display message -category warning Hello
         -> display message: Argument '-category' not known

Argument types are automatically checked and an error message is generated in case the argument value has not the expected type:

       display message -fg MyColor "Hello"
         -> display message: Argument 'fg' requires type 'color'.  Provided value: 'MyColor'

Selection choices have to be respected ...

       display message -mtype Fatal Hello
         -> display message: Argument (mtype) has to be one of the  following elements: Info, Warning, Error

... as well as valid value ranges:

       display message -level 12 Hello
         -> display message: Argument (level) has to be between 1 and 10
fr fr tepam is watching you at every single step and she will call you out. respectfully. πŸ’€

✨ INTERACTIVE PROCEDURE CALLS ✨

okay this is the fun part. The most intuitive way to call the procedure is using an form that allows specifying all arguments interactively. This form will automatically be generated if the declared procedure is called with the -interactive flag. To use this feature the Tk library has to be loaded. πŸ‘‘

       display message -interactive

The generated form contains for each argument a data entry widget that is adapted to the argument type. Check buttons are used to specify flags, radio boxes for tiny choice lists, disjoint list boxes for larger choice lists and files, directories, fonts and colors can be selected with dedicated browsers. πŸŽ€

After acknowledging the specified argument data via an OK button, the entered data are first validated, before the provided arguments are transformed into local variables and the procedure body is executed. In case the entered data are invalid, a message appears and the user can correct them until they are valid. no cap, she will keep asking until you get it right πŸ™ˆ

The procedure calls can optionally be logged in a variable. This is for example useful to get the command call lines of interactively called procedures. handy bestie behavior


🌈 FLEXIBLE ARGUMENT DIALOG BOX 🌈

The form generator that creates in the previous example the argument dialog box for the interactive procedure call is also available for other purposes than for the definition of procedure arguments. If Tk has been loaded TEPAM provides and argument dialog box that allows creating complex parameter definition forms in a very efficient way. reusable queen πŸ’…

The following example tries to illustrate the simplicity to create complex data entry forms. It creates an input mask that allows specifying a file to copy, a destination folder as well as a checkbox that allows specifying if an eventual existing file can be overwritten. Comfortable browsers can be used to select files and directories. And finally, the form offers also the possibility to accept and decline the selection. Here is the code snippet that is doing all this:

       tepam::argument_dialogbox \
          -existingfile {-label "Source file" -variable SourceFile} \
          -existingdirectory {-label "Destination folder" -variable DestDir} \
          -checkbutton {-label "Overwrite existing file" -variable Overwrite}

The argument_dialogbox returns ok if the entered data are validated. It will return cancel if the data entry has been canceled. After the validation of the entered data, the argument_dialogbox defines all the specified variables with the entered data inside the calling context. 🫢

An argument_dialogbox requires a pair of arguments for each variable that it has to handle. The first argument defines the entry widget type used to select the variable's value and the second one is a lists of attributes related to the variable and the entry widget. two args, one job, iconic.

Many entry widget types are available: Beside the simple generic entries, there are different kinds of list and combo boxes available, browsers for existing and new files and directories, check and radio boxes and buttons, as well as color and font pickers. If necessary, additional entry widgets can be defined. 🌸

The attribute list contains pairs of attribute names and attribute data. The primary attribute is -variable used to specify the variable in the calling context into which the entered data has to be stored. Another often used attribute is -label that allows adding a label to the data entry widget. Other attributes are available that allow specifying default values, the expected data types, valid data ranges, etc. ⭐

The next example of a more complex argument dialog box provides a good overview about the different available entry widget types and parameter attributes. The example contains also some formatting instructions like -frame and -sep which allows organizing the different entry widgets in frames and sections:

       set ChoiceList {"Choice 1" "Choice 2" "Choice 3" "Choice 4" "Choice 5" "Choice 6"}

       set Result [tepam::argument_dialogbox \
          -title "System configuration" \
          -context test_1 \
          -frame {-label "Entries"} \
             -entry {-label Entry1 -variable Entry1} \
             -entry {-label Entry2 -variable Entry2 -default "my default"} \
          -frame {-label "Listbox & combobox"} \
             -listbox {-label "Listbox, single selection" -variable Listbox1 \
                       -choices {1 2 3 4 5 6 7 8} -default 1 -height 3} \
             -listbox {-label "Listbox, multiple selection" -variable Listbox2
                       -choicevariable ChoiceList -default {"Choice 2" "Choice 3"}
                       -multiple_selection 1 -height 3} \
             -disjointlistbox {-label "Disjoined listbox" -variable DisJntListbox
                               -choicevariable ChoiceList \
                               -default {"Choice 3" "Choice 5"} -height 3} \
             -combobox {-label "Combobox" -variable Combobox \
                        -choices {1 2 3 4 5 6 7 8} -default 3} \
          -frame {-label "Checkbox, radiobox and checkbutton"} \
             -checkbox {-label Checkbox -variable Checkbox
                        -choices {bold italic underline} -choicelabels {Bold Italic Underline} \
                        -default italic} \
             -radiobox {-label Radiobox -variable Radiobox
                        -choices {bold italic underline} -choicelabels {Bold Italic Underline} \
                        -default underline} \
             -checkbutton {-label CheckButton -variable Checkbutton -default 1} \
          -frame {-label "Files & directories"} \
             -existingfile {-label "Input file" -variable InputFile} \
             -file {-label "Output file" -variable OutputFile} \
             -sep {} \
             -existingdirectory {-label "Input directory" -variable InputDirectory} \
             -directory {-label "Output irectory" -variable OutputDirectory} \
          -frame {-label "Colors and fonts"} \
             -color {-label "Background color" -variable Color -default red} \
             -sep {} \
             -font {-label "Font" -variable Font -default {Courier 12 italic}}]

The argument_dialogbox defines all the specified variables with the entered data and returns ok if the data have been validated via the Ok button. If the data entry is cancelled by activating the Cancel button, the argument_dialogbox returns cancel.

       if {$Result=="cancel"} {
          puts "Canceled"
       } else { # $Result=="ok"
          puts "Arguments: "
          foreach Var {
             Entry1 Entry2
             Listbox1 Listbox2 DisJntListbox
             Combobox Checkbox Radiobox Checkbutton
             InputFile OutputFile InputDirectory OutputDirectory
             Color Font
          } {
             puts "  $Var: '[set $Var]'"
          }
       }
       -> Arguments:
          Entry1: 'Hello, this is a trial'
          Entry2: 'my default'
          Listbox1: '1'
          Listbox2: '{Choice 2} {Choice 3}'
          DisJntListbox: '{Choice 3} {Choice 5}'
          Combobox: '3'
          Checkbox: 'italic'
          Radiobox: 'underline'
          Checkbutton: '1'
          InputFile: 'c:\tepam\in.txt'
          OutputFile: 'c:\tepam\out.txt'
          InputDirectory: 'c:\tepam\input'
          OutputDirectory: 'c:\tepam\output'
          Color: 'red'
          Font: 'Courier 12 italic'

πŸ‘€ SEE ALSO πŸ‘€

tepam::argument_dialogbox(n), tepam::procedure(n)


πŸ”₯ KEYWORDS πŸ”₯

argument integrity, argument validation, arguments, entry mask, parameter entry form, procedure, subcommand


πŸ’œ CATEGORY πŸ’œ

Procedures, arguments, parameters, options


Copyright (c) 2009-2013, Andreas Drollinger


and that's the whole page bestie!! πŸ¦‹ this one's from tcllib, version 0.5.4, and it's the tepam(n) page β€” go forth and validate those arguments πŸ’…βœ¨ periodt πŸ’–

πŸ“¦ where this page comes from