module Como
Introduction¶ ↑
Como
provides low manifest command line option parsing and deployment. The command line options are described in compact table format and option values are stored to conveniently named properties. Como
builds command usage information based on the option table (+ generic program info) and displays it automatically if necessary. Como
supports also subcommands and checking for option combinations using a simple DSL.
Usage Examples¶ ↑
Two simple examples are presented in this section. First one includes a straight forward command definition and the second is a bit more complicated with subcommand feature in use.
Simple example¶ ↑
Below is a small example program (“como_simple”) that demonstrates typical usage.
Program listing¶ ↑
require "como" include Como # Define command line arguments: Spec.command( "como_simple", "Programmer", "2013", [ [ :single, "file", "-f", "File argument." ], [ :switch, "debug", "-d", "Enable debugging." ], ] ) puts " File option: #{Opt['file'].value}" puts " Debugging selected!" if Opt['debug'].given
First Como
is required and Como
module is included.
{Spec.command} method takes 4 arguments:
- progname
-
Name of the program (or command).
- author
-
Author of the program.
- year
-
Year (or any date) for the program.
- option table
-
Description of the command options.
Each option table entry (row/sub-array) includes 4 fields and specifies one option:
[ type, name, mnemonic, doc ]
Two different types are present in the example:
- :single
-
Single means that the option requires one argument (and only one).
- :switch
-
Switch is an optional flag (default value is false).
Option name is used to reference the option value that user has given. The command line option values are stored automatically. For example the file option value is returned by:
Opt['file'].value
The option name also doubles as long option format, i.e. one could use “–file <filename>” on the command line.
Existence of optional options can be tested using the {Opt#given} method. For example
Opt['debug'].given
would return “true” if “-d” was given on the command line.
Mnemonic is the short form option specification e.g. “-f”. If short form is replaced with “nil”, the long option format is only available.
Doc includes documentation for the option. It is displayed when “help” (“-h”) option is given. Help option is added to the command automatically as default behavior.
Simple example executions¶ ↑
Normal behavior would be achieved by executing:
shell> como_simple -f example -d
The program would execute with the following output:
File option: example Debugging selected!
Same output would be achieved with:
shell> como_simple --file example --debug
Since option name doubles as long option.
Como
includes certain “extra” behavior out-of-box. Required arguments are checked for existence and error is displayed if arguments are not given.
For example given the command:
shell> como_simple
The following is displayed on the screen:
como_simple error: Option "-f" missing for "como_simple"... como_simple -f <file> [-d] -f File argument. -d Enable debugging. Copyright (c) 2013 by Programmer
Missing option error is displayed since “file” is a mandatory option. The error message is followed by “usage” display (Usage Help). Documentation string is taken from the option specification to “usage” display.
Given the command:
shell> como_simple -h
would display the same “usage” screen except without the error line.
Subcommand example¶ ↑
Subcmd example includes a program which has subcommands. Subcommands can have their own command line switches and options.
Program listing¶ ↑
require "como" include Como Spec.program( "Programmer", "2013" ) do command( "como_subcmd", [ [ :subcmd, "add", nil, "Add file." ], [ :subcmd, "rm", nil, "Remove file." ], ], ) subcmd( "add", [ [ :switch, "force", "-fo", "Force operation." ], [ :opt_single, "password", "-p", "User password." ], [ :opt_single, "username", "-u", "Username." ], [ :single, "file", "-f", "File." ], ] ) check do one( '-fo', all( 'password', 'username' ) ) end subcmd( "rm", [ [ :single, "file", "-f", "File." ], ] ) end subcmd = Opt.main.givenSubcmd case subcmd.name when 'add'; puts " Adding file \"#{subcmd['file'].value}\"..." when 'rm'; puts " Removing file \"#{subcmd['file'].value}\"..." end
{Spec.program} method defines a program (command) with subcommands. The author and date are provided as parameters, and the program and subcommand options are defined in block.
The first {Spec#command} (or {Spec#subcmd}) method call defines the main command ({Opt.main}) which represents the program. It has two “subcmd” options (“add” and “rm”).
The rest of the “subcmd” methods define subcommands for the parent command. This example includes one subcommand level, but multiple levels are allowed.
The “check” (or “checkRule”) method defines option combination ({RuleCheck}) for the previous subcommand definition. In this case the definition allows “add” to have either the “-fo” option defined or “password” and “username” in combination.
Main (root) commands can be referenced through
Opt.main
or alternatively
Opt['como_subcmd']
The subcommands can be referenced through {Opt.main} (etc.)
Opt.main['add'] Opt['como_subcmd']['add']
or directly from {Opt} if subcommand names do not collide:
Opt['add']
The given subcommand can be accessed with {Opt#givenSubcmd} method from each parent command.
Subcommand example executions¶ ↑
Normal behavior would be achieved by executing:
shell> como_subcmd add -fo -f example
The program would execute with the following output:
Adding file "example"...
The option combinations for “add” subcommand are automatically checked. Thus executing:
shell> como_subcmd add -f example
Would result to:
como_subcmd error: Option combination mismatch! Subcommand "add" usage: como_subcmd add [-fo] [-p <password>] [-u <username>] -f <file> -fo Force operation. -p User password. -u Username. -f File. Option Combinations: |--# One of: | |--<-fo> | |--# All of: | | |--<password> | | |--<username>
since the combination rule requires either “-fo”, or both “password” and “username”.
Help is automatically provided on each command level, thus these are both valid.
shell> como_subcmd -h
and
shell> como_subcmd rm -h
Option specification¶ ↑
Overview¶ ↑
Option specification includes the minimum set of information required for command line parsing. It is used to:
-
Parse the command line.
-
Check for wrong options and report.
-
Check for mandatory arguments and report.
-
Set the options given/non-given state.
-
Set the options value. Array/String for all except true/false for switches.
-
Generate Usage Help printout.
Option types¶ ↑
The following types can be defined for the command line options:
- :subcmd
-
Subcmd option. Subcmd specific options are provided separately.
- :switch
-
Single switch option (no arguments).
- :single
-
Mandatory single argument option.
- :comp
-
Mandatory single argument option (multiple times). Option values in array.
- :multi
-
Mandatory multiple argument option (one or many). Option values in array.
- :opt_single
-
Optional single argument option. Value is nil when option is not given.
- :opt_comp
-
Optional single argument option (multiple times). Value is nil when option is not given.
- :opt_multi
-
Optional multiple argument option (one or many). Option values in array.
- :opt_any
-
Optional multiple argument option (also none accepted). Option values in array.
- :default
-
Default option (no switch associated). Name and option String values can be left out, since only the document string is used. Default option is referred with “:default” or “nil”.
- :exclusive
-
Option that does not co-exist with other options. :exclusive can have arguments as with :opt_any.
- :silent
-
Switch option that is not displayed as an option in Usage Help display.
Options use typically all the 4 option fields:
[ type, name, mnemonic, doc ]
“type” field is mandatory for all options.
“name” field is also mandatory for all options. “mnemonic” can be left out, but then option accepts only long option format.
“:default” uses only “doc” and “:subcmd” doesn't use the “mnemonic” field.
“:multi”, “:opt_multi”, and “:opt_any” option arguments are terminated only when an option specifier is found. This can be a problem if “:default” option follows. There are two simple solutions to this issue. “:comp” option takes only one argument per given switch, and hence is not ambiguous towards “:default” option. Another possibility is to use a “:silent” option that can be used to terminate the argument list. For example:
[ :silent, "terminator", "-", "The terminator." ],
Option type primitives¶ ↑
Como
converts option types into option type primitives. Option types are not completely orthogonal, but primitives are.
Primitives:
- :none
-
No arguments (i.e. switch).
- :one
-
One argument.
- :many
-
More than one argument.
- :repeat
-
Option can be repeated.
- :opt
-
Optional argument(s).
- :default
-
Default option.
- :mutex
-
Mutually exclusive option.
- :hidden
-
Hidden option (no usage doc).
Types to primitives mapping:
- :switch
-
:none, :opt
- :single
-
:one
- :comp
-
:one, :repeat
- :multi
-
:one, :many, :repeat
- :opt_single
-
:one, :opt
- :opt_comp
-
:one, :repeat, :opt
- :opt_multi
-
:one, :many, :repeat, :opt
- :opt_any
-
:none, :one, :many, :repeat, :opt
- :default
-
:none, :one, :many, :opt, :default
- :exclusive
-
:none, :one, :many, :opt, :mutex
- :silent
-
:none, :opt, :hidden, :repeat
Primitives can be used in place of types if exotic options are needed. Instead of a single Symbol an Array of primitives are given for option type. Order of primitives is not significant.
For example:
[ [ :none, :hidden, :opt ], "terminator", "-", "The terminator." ],
Como
does not check the primitive combinations, thus care and consideration should be applied.
Option specification method configuration¶ ↑
Option behavior can be controlled with several configuration options.
The configuration options are provided in a Hash. These are the passed as the last regular parameter for both {Spec.command} and {Spec.program} methods. Setting the configuration at {Spec.program} will propagate the config options to all the subcommands as well. Configuration can be given to each subcommand separately to override the inherited config values. Subcommand settings are not inherited, but apply only in the subcommand.
The usable configuration Hash keys:
- :autohelp
-
Add help option automatically (default: true). Custom help option can be provided and it can be made also visible to user.
- :rulehelp
-
Include
RuleCheck
help to Usage Help (default: false). - :header
-
Header lines before standard usage printout.
- :footer
-
Footer lines after standard usage printout.
- :subcheck
-
Automatically check that a subcommand is provided (default: true).
- :check_missing
-
Check for missing arguments (default: true).
- :check_invalid
-
Error for unknown options (default: true).
- :tab
-
Tab stop column for option documentation (default: 12).
- :help_exit
-
Exit program if help displayed (default: true).
- :copyright
-
Display copyright/author in usage printout (default: true).
Option referencing¶ ↑
Existence and values¶ ↑
Opt
class includes the parsed option values. All options can be tested whether they are specified on the command line using:
Opt['name'].given
The {Opt#given} method takes optionally a block argument. When block argument is used, the block is supplied with option value and the block is executed if the option has been set (See: {Opt#given}).
Provided value is returned by:
Opt['name'].value
For “:switch” type it is true/false value and for the other types a String or an Array of Strings.
If an option takes multiple arguments, the value for the option is an Array. The values can be iterated simply by:
Opt['files'].value.each do |val| puts val end
Short syntax for value referencing is performed with unary operator “~”. Thus
~Opt['files']
is equal to
Opt['files'].value
With “:opt_any” type, the user should first check if the option was given:
Opt['many_files_or_none'].given
Then check how many arguments where given:
Opt['many_files_or_none'].value.length
And finally decide what to do.
Options including parameters¶ ↑
Sometimes it is convenient for the program to use an option to include multiple parameter settings. These settings can be parsed and mapped to a Hash. Como
performs automatic conversion to numeric values if possible. For example with option:
--set rounds=10 length=5
Como
can be used extract the parameter values with the “params” method:
Opt['set'].params
And a Hash is returned:
{ 'rounds' => 10, 'length' => 5 }
Subcommand options¶ ↑
The given subcommand for the parent command is return by {Opt#givenSubcmd}. Commonly the program creator should just check directly which subcommand has been selected and check for any subcommand options set. For example:
if Opt['como_subcmd']['add'].given ...
Program external options¶ ↑
If the user gives the “–” option (double-dash), the arguments after that option are returned as an Array with {Opt.external}.
Option combination checks¶ ↑
Como
provides a facility to create relations between options using RuleCheck
DSL. This is needed since sometimes options have to be used in combination to make sense for the program. Also options might be mutually exclusive.
The following rules can be used (in combination):
- all
-
All options in the list.
- one
-
One and only one from the list.
- any
-
At least one of the list is given.
- none
-
No options are required.
- inv
-
Logical negation for existence.
- incr
-
Incremental options in order i.e. have to have previous to have later.
- follow
-
Incremental options in order i.e. have to have all later if had first.
- meh
-
Dont care, always succeeds.
Examples can be found above.
Customization¶ ↑
A Como
user specific customization file can be referenced through the “COMO” environment variable. If environment variable “COMO” is defined, the referenced file is read in as Ruby file as a last phase when Como
is loaded from the program (require). Proposed naming convention for the customization is:
$HOME/.como
User can define a pre and a post action hook in the file.
The pre-hook can be used for example to change the Como
config defaults. It is run before the body of {Spec.command} or {Spec.program} is executed. It is passed all the parameters that has been passed to {Spec.command} or {Spec.program}, only collected into a Hash. The Hash keys are method parameter names as symbols.
Example:
# Define pre parser hook for Como. Como.preHook do |args| # Get default config for options. config = Como::Opt.configGet # Disable 'copyright' lines from usage. config[ :copyright ] = false # Test if "Spec.command" is the entry method (it has arg named "prog"). if args[ :prog ] # Place a custom header for all programs. config[ :header ] = "\nProgram \"#{args[ :prog ]}\" is ...\n\n" end end
There is no predefined use cases for post-hook. Post-hook is passed the {Opt.main} as parameter.
{Spec.program} and {Spec.command} both process and check options in one pass. Como
user can separate the definition and checking phase. Definition phase is performed by executing {Spec.defineProgram} or {Spec.defineCommand}. After definition phase the user can for example programmatically add new subcommands or options, in addition to existing options. When the subcommands and options are complete, {Spec.execute} should be called to perform options checking.
If the provided customization facilities are not satisfactory, changes can be implemented simply by overloading the existing functions. Some knowledge of the internal workings of Como
is required though.
Como
version is returned with:
Como.version
Constants
- VERSION
Public Class Methods
Set “postHook” routine.
# File lib/como.rb, line 569 def Como.postHook( &code ) ComoCommon.setHook( :postHook, &code ) end
Set “preHook” routine.
# File lib/como.rb, line 563 def Como.preHook( &code ) ComoCommon.setHook( :preHook, &code ) end
# File lib/version.rb, line 3 def Como.version Como::VERSION end