Module: Como
- Defined in:
- lib/como.rb
Overview
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 "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"...
Usage:
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.
Subccommand 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
subcmd( "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." ],
] )
checkRule 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 "subcmd" method call defines the main command ("Opt.main") which represents the program. It has two "subcmd" options.
The rest of the "subcmd" methods define subcommands for the parent command. This example includes one subcommand level, but multiple levels are allowed.
The "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 "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" in a pair.
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.
- :multi
-
Mandatory multiple argument option (one or many). Option values in array.
- :opt_single
-
Optional single argument option.
- :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 coexist with other options.
- :silent
-
Option that does not coexist with other options and is not displayed as an option in Usage Help display. In effect a sub-option of :exclusive.
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. The recommended solution is to use a ":silent" option that can be used to terminate the argument list. For example:
[ :silent, "terminator", "-", "The terminator." ],
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).
- :tab
-
Tab stop column for option documentation (default: 12).
- :help_exit
-
Exit program if help displayed (default: true).
- :error_exit
-
Exit program if error in options (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 "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 "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 is 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
If the default behavior is not satisfactory, changes can be implemented simply by overloading the existing functions. Some knowledge of the internal workings of Como is required though.
Defined Under Namespace
Classes: ArgsParseState, ComoCommon, MainOpt, Opt, RuleCheck, RuleDisplay, Spec