Module: Como
- Defined in:
- lib/como.rb,
lib/version.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 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.
- :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_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. 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 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.
- :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
- :multi
-
:one, :many
- :opt_single
-
:one, :opt
- :opt_multi
-
:one, :many, :opt
- :opt_any
-
:none, :one, :many, :opt
- :default
-
:none, :one, :many, :opt, :default
- :exclusive
-
:none, :one, :many, :opt, :mutex
- :silent
-
:none, :opt, :hidden
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
Defined Under Namespace
Classes: ArgsParseState, ComoCommon, MainOpt, Opt, RuleCheck, RuleDisplay, Spec
Constant Summary
- VERSION =
"0.2.1"
Class Method Summary (collapse)
-
+ (Object) postHook(&code)
Set “postHook” routine.
-
+ (Object) preHook(&code)
Set “preHook” routine.
- + (Object) version
Class Method Details
+ (Object) postHook(&code)
Set “postHook” routine.
554 555 556 |
# File 'lib/como.rb', line 554 def Como.postHook( &code ) ComoCommon.setHook( :postHook, &code ) end |
+ (Object) preHook(&code)
Set “preHook” routine.
548 549 550 |
# File 'lib/como.rb', line 548 def Como.preHook( &code ) ComoCommon.setHook( :preHook, &code ) end |
+ (Object) version
3 4 5 |
# File 'lib/version.rb', line 3 def Como.version Como::VERSION end |