cmdr-spec-dsl-parameter - Cmdr - Parameter Specification Language
Welcome to the Cmdr project, written by Andreas Kupries.
For availability please read Cmdr - How To Get The Sources.
This document is for users of the cmdr framework. It introduces the domain-specific language for the specification of parameters in detail.
The parameters of privates are the heart of the system, providing the space needed to transfer command arguments to their implementations, and having the most attributes controlling their behaviour.
This complexity is strongly mitigated by the use of sensible defaults for each of the three possible kinds of parameter, i.e. positional inputs, named options", and state hidden from the command line.
Each kind has its own construction command in the language for privates (See Cmdr - Private Specification Language) which specifies the common information which cannot have defaults, i.e.
the name identifying it to the system,
the help text describing it in informal speech, and, of course,
the parameter specification itself, using the commands of this section.
We have two commands to influence the visible naming of all parameters.
As background, all parameters are named, to properly identify them within the framework and other Tcl code, i.e. in the various callbacks and the private's action. This system name has to be unique within the private a parameter belongs to. Beyond that however the visible (i.e. non-term state]) parameters have to be identified by users within help texts, and, in the case of options, for detection during the Parsing phase. That is the visible naming, seen by a user of any application whose command line processing is based on the Cmdr framework.
This command declares the parameter's visible name, if different from the system name used as the default. Note that in most cases this default is good enough, obviating the need for this command.
The only use case seen so far is when two semantically equivalent input and option parameters clash, forcing the use of different system names due to the requirement for their uniqueness, yet also use the same visible name and flag within the help to highlight their connection and equivalence.
For options the label command and its default specifies the name of the primary flag recognized during the Parsing phase. If that is not enough for a specific option this command allows the specification of any number additional flags to be recognized.
Note however that the framework automatically recognizes not only the specified flag(s), but also all their unique prefixes, obviating the need for this command in many cases.
The general handling of a parameter is influenced by three commands:
When the framework encounters an unknown flag during the Parsing phase it will not unconditionally throw an error about it, but first check if the next available input parameter (if any) could accept the flag string as its value, per that input's validation type, and if yes, does so.
This command causes the rejection of such flag strings by this parameter on general principle, without having to validate it.
Note that it is only useful for and applicable to input parameters.
This command marks the parameter as optional, i.e. as something the user may skip on the command line, with the application supplying sensible defaults (See section Representations). This causes the framework to expend some effort in the Parsing phase to determine whether an argument word should be assigned to the parameter, or not.
This setting is only applicable to inputs, as options are optional by definition, and state is hidden.
This command is related to the above, switching the runtime from the standard regime for acceptance (based on counting and thresholds) to a different regime based on validation.
More details are explained in section Parsing of Cmdr - Runtime Processing Flow.
This command excludes the parameter from the generated help.
Its main use case is the hiding of options giving an application developer access to the internals of their application, something a regular user has no need of, and doesn't have to know about.
An important concept of parameters is something taken up from Tcl itself. The differentation between string and internal representations. Where Tcl uses internal representations to speed up its execution here this separation is that of between the information delivered to the application by a user, and the application-specific data structures behind them.
All parameters will have an internal representation. This is usually derived from the string representation provided by the user. The details of that process are explained in section Validation. However we have cases where the user cannot specify a string representation (states), or is allowed to choose not to (optional inputs, options). For these cases three specification commands are made available enabling us to programmatically choose the internal representation.
This command specifies a constant default value for the internal representation.
This command specifies a callback to compute the default internal representation at runtime. This is useful if the default is something which cannot be captured as a fixed value. An example would be a handle to some resource, or a dynamically created object.
The command prefix is invoked with a single argument, the cmdr::parameter instance for which to generate the internal representation.
The commands default and generate exclude each other, i.e. only of them can be specified, but not both. If neither are specified, and we need a default (see the cases above) then a default is chosen by the framework itself, as per the two rules below:
Use the empty string for a list parameter.
Use the default value supplied by the chosen validation type (See section Validation).
This command actually does not specify an internal representation, but activates another method for the user to specify the string representation of the parameter, outside of the command line. As such it has priority over either default and generate, and can be specified with either. A parameter marked with it will interactively ask the user for a value if none was specified on the command line.
The default for the prompt is derived from the parameter's system name.
A string representation specified on the command line has the highest priority and goes through the chosen validation type to get the associated internal representation.
If activated via interact a small shell is run asking the user for a value (or more, as per list, see below). The result goes through the chosen validation type to get the associated internal representation.
After that the internal representation is either the declared default value, or the result of invoking the generate callback. As internal representations the resulting values are not run through the chosen validation type.
This command marks the parameter as a list. In other words, its string and internal representation is actually a list of such, instead of a single value. By default all parameters are scalar.
This affects the handling of the parameter by the Parsing phase, by interact above, and the use of the validation type. The last two ask for multiple values, and feed the elements of the string representation separately through validation instead of just the string value in one. In the Parsing phase treatment of options changes from keeping only the last assigned value to the accumulation of all values. Similarly a list-input takes all the remaining words on the command line for itself instead of just the current word. Because of this list-inputs are only allowed as the last parameter of a private.
The last two specification commands dealing with the representations control when the internal representation is created.
This command marks a parameter as defered, causing its internal representation to be computed on first access to its value. This is the default for state parameters.
This command marks a parameter as immediate, causing its internal representation to be computed in the Completion phase. This is the default for input and option parameters.
The answer to the necessity of moving between the string and internal representations described in the previous section are the validation types. Given a string representation they either return the associated internal representation or raise an error, signaling that the string was illegal. This part of their work, the verification of the legality of the input string gave them their name.
The general concept of validation types was taken from snit, and modified to suit Cmdr. Where snit's types expect only a single method to validate the input Cmdr expects all types to support an ensemble of four methods. One for the basic validation and transformation of the input, another for the release of any internal representation so generated, plus two more for delivery of a default representation and support for command line completion.
This command specifies a validation type for the parameter, in the form of a command prefix (or the name of one of the builtin types, see package cmdr::validate). The set of methods this callback has to support, their signatures, etc. are all explained in Cmdr - Writing custom validation types. This document contains the implementation of the standard boolean validation type as an example as well.
Because of the same necessity all parameters must have a validation type assigned to them, and the system will choose which, if the user did not. This choice is made as per the six rules below and always returns one of the standard types implemented by package cmdr::validate.
Use identity if a generate callback is specified.
Use boolean if no default is specified and the parameter is an option.
Use identity if no default is specified and the parameter is an input.
Use boolean if the specified default value is a Tcl boolean.
Use integer if the specified default value is a Tcl integer.
Use identity as fallback of last resort.
This command is best discussed as part of the wider area of boolean options, i.e. options with the standard validation type boolean assigned to them. These have associated special behaviours, both in the handling of the specification, and in the Parsing phase.
First, normal boolean options. They have automatic aliases declared for them, derived from their primary flag. An option named "foo" will have an alias of "no-foo", and the reverse. In the Parsing phase the "foo" and "no-foo" flags have inverse semantics, and both are allowed to occur without option argument following the flag. This is in contrast to all other options which must have such an argument. The parser essentially uses the validation type to decide if the word after the flag is a proper boolean value, or not, i.e. an argument to assign to the parameter, or not.
Now presence declares a variant of the above, a boolean option without the automatic aliases, and never taking an argument during parsing. Its mere presence on the command line will set its parameter. Their default value is consequently fixed to false as well.
This section explains the commonalities between the callbacks in general, and the last two, for notifications about state changes in detail.
All callbacks are treated as command prefixes, not scripts. There are no placeholder substitutions, only arguments added to each command prefix on invokation. This does not harm the generality of the system, as complex scripts can be used via procedures or equivalents (i.e. apply).
The two callbacks not yet described are the state-change callbacks through which the framework can actively drive parts of the application while processing the command line, whereas normally the application drives access to parameters through their methods.
This command declares the state-change callback to invoke when the internal representation of the parameter is generated from the string representation, or the various ways of getting a default.
The callback is invoked with two arguments, the cmdr::parameter instance of the changed parameter, and its internal representation, in this order.
This command declares the state-change callback to invoke when the string representation of the parameter is set during command line parsing.
The callback is invoked with two arguments, the cmdr::parameter instance of the changed parameter, and its string representation, in this order.
Due to their nature these callbacks are invoked at runtime during either the Parsing, Completion, or Execution phases. The details are shown in the table below. The specification commands influencing the timing, i.e. forcing the use in a specific phase are shown in the intersection of callback and phase.
| Dispatch | Parsing | Completion | Execution --------------------+----------+---------+-------------+----------- validate (default) | * | | | --------------------+----------+---------+-------------+----------- validate (complete) | | * | immediate | defered when-set | | * | | --------------------+----------+---------+-------------+----------- generate | | | immediate | defered validate (validate) | | test | immediate | defered validate (release) | | test | immediate | defered --------------------+----------+---------+-------------+----------- when-complete | | | immediate | defered --------------------+----------+---------+-------------+-----------
Please continue reading with Cmdr - Runtime Processing Flow.
Both the package(s) and this documentation will undoubtedly contain bugs and other problems. Please report such at Cmdr Tickets.
Please also report any ideas you may have for enhancements of either package(s) and/or documentation.
arguments, command hierarchy, command line completion, command line handling, command tree, editing command line, help for command line, hierarchy of commands, interactive command shell, optional arguments, options, parameters, processing command line, tree of commands
Copyright © 2013 Andreas Kupries
Copyright © 2013 Documentation, Andreas Kupries