Parser for command line arguments, keywords, options and environment variables
- Parse command line arguments, keywords, flags, options and environment variables.
- Define command line parameters with DSL or keyword arguments.
- Access all parameter values from hash-like params.
- Define global parameters with inheritance.
- Accept command line parameters in any order.
- Handle complex inputs like lists and maps.
- Convert inputs to basic and more complex object types.
- Generate help from parameter definitions.
- Customise help with usage methods such as header, example and more.
- Collect parsing errors for a better user experience.
Add this line to your application's Gemfile:
gem "tty-option"
And then execute:
$ bundle install
Or install it yourself as:
$ gem install tty-option
- 1. Usage
- 2. API
Include the TTY::Option
module and define parameters to parse command
line input.
Choose from arguments, keywords, flags, options and environment variables.
For example, here is a quick demo of how to create a command that mixes all parameter types:
class Command
include TTY::Option
usage do
program "dock"
command "run"
desc "Run a command in a new container"
example "Set working directory (-w)",
" $ dock run -w /path/to/dir/ ubuntu pwd"
example <<~EOS
Mount volume
$ dock run -v `pwd`:`pwd` -w `pwd` ubuntu pwd
EOS
end
argument :image do
required
desc "The name of the image to use"
end
argument :command do
optional
desc "The command to run inside the image"
end
keyword :restart do
default "no"
permit %w[no on-failure always unless-stopped]
desc "Restart policy to apply when a container exits"
end
flag :detach do
short "-d"
long "--detach"
desc "Run container in background and print container ID"
end
flag :help do
short "-h"
long "--help"
desc "Print usage"
end
option :name do
required
long "--name string"
desc "Assign a name to the container"
end
option :port do
arity one_or_more
short "-p"
long "--publish list"
convert :list
desc "Publish a container's port(s) to the host"
end
def run
if params[:help]
print help
elsif params.errors.any?
puts params.errors.summary
else
pp params.to_h
end
end
end
Then create a command instance:
cmd = Command.new
And given the following input on the command line:
restart=always -d -p 5000:3000 5001:8080 --name web ubuntu:16.4 bash
Read the command line input (aka ARGV
) with parse:
cmd.parse
Or provide an array of inputs:
cmd.parse(%w[restart=always -d -p 5000:3000 5001:8080 --name web ubuntu:16.4 bash])
Finally, run the command to see parsed values:
cmd.run
# =>
# {:help=>false,
# :detach=>true,
# :port=>["5000:3000", "5001:8080"],
# :name=>"web",
# :restart=>"always",
# :image=>"ubuntu:16.4",
# :command=>"bash"}
Use the params to access all parameters:
cmd.params[:name] # => "web"
cmd.params["command"] # => "bash
Given the --help
flag on the command line:
cmd.parse(%w[--help])
Use the help method to print help information to the terminal:
print cmd.help
This will result in the following output:
Usage: dock run [OPTIONS] IMAGE [COMMAND] [RESTART=RESTART]
Run a command in a new container
Arguments:
IMAGE The name of the image to use
COMMAND The command to run inside the image
Keywords:
RESTART=RESTART Restart policy to apply when a container exits (permitted:
no, on-failure, always, unless-stopped) (default "no")
Options:
-d, --detach Run container in background and print container ID
-h, --help Print usage
--name string Assign a name to the container
-p, --publish list Publish a container's port(s) to the host
Examples:
Set working directory (-w)
$ dock run -w /path/to/dir/ ubuntu pwd
Mount volume
$ dock run -v `pwd`:`pwd` -w `pwd` ubuntu pwd
Given an invalid command line input:
cmd.parse(%w[--unknown])
Use the errors method to print all errors:
puts params.errors.summary
This will print a summary of all errors:
Errors:
1) Invalid option '--unknown'
2) Option '--publish' should appear at least 1 time but appeared 0 times
3) Option '--name' must be provided
4) Argument 'image' must be provided
Use the argument
method to parse positional arguments.
Provide a name as a string or symbol to define an argument. The name will serve as a default label for the help display and a key to retrieve a value from the params:
argument :foo
Given the following command line input:
11 12 13
This would result only in one argument parsed and the remaining ignored:
params[:foo] # => "11"
The argument
method accepts a block to define
parameter settings.
For example, use the arity and convert settings to parse many positional arguments:
argument :foo do
name "foo(int)" # name for help display
arity one_or_more # how many times can appear
convert :int_list # convert input to a list of integers
validate ->(v) { v < 14 } # validation rule
desc "Argument description" # description for help display
end
Parser would collect all values and convert them to integers given previous input:
params[:foo] # => [11, 12, 13]
The argument
method can also accept settings as keyword arguments:
argument :foo,
name: "foo(int)",
arity: "+",
convert: :int_list,
validate: ->(v) { v < 14 },
desc: "Argument description"
Use the keyword
method to parse keyword arguments.
Provide a name as a string or symbol to define a keyword argument. The name will serve as a command line input name, a default label for the help display and a key to retrieve a value from the params:
keyword :foo
Parser will use the parameter name to match the input name on the command line by default.
Given the following command line input:
foo=11
This would result in:
params[:foo] # => "11"
Note that the parser performs no conversion of the value.
The keyword
method accepts a block to define
parameter settings.
For example, use the arity and convert settings to parse many keyword arguments:
keyword :foo do
required # by default keyword is not required
arity one_or_more # how many times can appear
convert :int_list # convert input to a list of integers
validate ->(v) { v < 14 } # validation rule
desc "Keyword description" # description for help display
end
Given the following command line input:
foo=10,11 foo=12 13
This would result in an array of integers:
params[:foo] # => [10, 11, 12, 13]
The keyword
method can also accept settings as keyword arguments:
keyword :foo,
required: true,
arity: :+,
convert: :int_list,
validate: ->(v) { v < 14 },
desc: "Keyword description"
Use the flag
or option
methods to parse options.
Provide a name as a string or symbol to define an option. The name will serve as a command line input name, a label for the help display and a key to retrieve a value from the params:
option :foo
Parser will use the parameter name to generate a long option name by default.
Given the following command line input:
--foo
This would result in:
params[:foo] # => true
The flag
and option
methods accept a block to define
parameter settings.
For example, to specify a different name for the parsed option, use the short and long settings:
option :foo do
short "-f" # define a short name
long "--foo" # define a long name
end
Given the following short name on the command line:
-f
This would result in:
params[:foo] # => true
An option can accept an argument. The argument can be either required
or optional. To define a required argument, provide an extra label
in short
or long
settings. The label can be any string. When
both short
and long
names are present, only specify an argument
for the long name.
For example, for both short and long names to accept a required integer argument:
option :foo do
short "-f"
long "--foo int"
# or
long "--foo=int"
end
Given the following command line input:
--foo=11
This would result in:
params[:foo] # => "11"
Note that the parser performs no conversion of the argument.
To define an optional argument, surround it with square brackets.
For example, to accept an optional integer argument:
option :foo do
long "--foo [int]"
end
Use the arity and convert settings to parse many options given as a list of integers:
option :foo do
required # by default option is not required
arity one_or_more # how many times option can appear
short "-f" # declare a short flag name
long "--foo ints" # declare a long flag with a required argument
convert :int_list # convert input to a list of integers
validate ->(v) { v < 14 } # validation rule
desc "Option description" # description for help display
end
Given the following command line input:
--foo=10,11 -f 12 13
This would result in an array of integers:
params[:foo] # => [10, 11, 12, 13]
The option method can also accept settings as keyword arguments:
option :foo,
required: true,
arity: :+,
short: "-f",
long: "--foo ints",
convert: :int_list,
validate: -> { |v| v < 14 },
desc: "Option description"
There is a convenience flag
method to specify a command line option that
accepts no argument:
flag :foo
For example, a typical scenario is to specify the help flag:
flag :help do
short "-h"
long "--help"
desc "Print usage"
end
Use the environment
or env
methods to parse environment variables.
Provide a name as a string or symbol to define an environment variable. The name will serve as a command line input name, a default label for the help display and a key to retrieve a value from the params:
environment :foo
# or
env :foo
Parser will use the parameter name to match the input name on the command line by default.
Given the following command line input:
FOO=11
The result would be:
params[:foo] # => "11"
Note that the parser performs no conversion of the value.
The environment
method accepts a block to define
parameter settings.
For example, use the name setting to change a default variable name:
environment :foo do
name "FOO_ENV"
end
Given the following command line input:
FOO_ENV=11
This would result in:
params[:foo] # => "11"
For example, use the arity and convert settings to parse many environment variables given as a list of integers:
environment :foo do
required # by default environment is not required
arity one_or_more # how many times env var can appear
name "FOO_ENV" # the command line input name
convert :int_list # convert input to a map of integers
validate ->(v) { v < 14 } # validation rule
desc "Environment description" # description for help display
end
Given the following command line input:
FOO_ENV=10,11 FOO_ENV=12 13
This would result in an array of integers:
params[:foo] # => [10, 11, 12, 13]
The environment
method can also accept settings as keyword arguments:
environment :foo,
required: true,
arity: :+,
name: "FOO_ENV",
convert: :int_list,
validate: ->(v) { v < 14 },
desc: "Environment description"
All parameter types support the following settings except for
short
and long
, which are option specific.
Use the arity
setting to describe how many times a given parameter may
appear on the command line.
Every parameter can appear only once by default. In the case of arguments, the parser will match the first input and ignore the rest. For other parameter types, any extra parameter occurrence will override previously parsed input. Setting the arity requirement overrides this behaviour.
For example, to match an argument exactly two times:
argument :foo do
arity 2
end
Given the following command line input:
bar baz
This would result in an array of strings:
params[:foo] # => ["bar", "baz"]
Another example is to match exactly three occurrences of a keyword:
keyword :foo do
arity 3
end
And then given the following on the command line:
foo=1 foo=2 foo=3
This would result in an array of strings:
params[:foo] # => ["1", "2", "3"]
Use :any
, :*
, -1
, any
or zero_or_more
to specify that parameter
may appear any number of times.
For example, to expect an argument to appear zero or more times:
argument :foo do
arity zero_or_more
end
Use :+
or one_or_more
to specify that parameter must appear at least once.
For example, to expect an option with an argument to appear one or more times:
option :foo do
arity one_or_more
short "-f"
long "--foo string"
end
Use at_least
to specify the least number of times a parameter can appear:
For example, to expect a keyword to appear at least three times:
keyword :foo do
arity at_least(3)
end
The help method will handle the arity for the usage banner.
For example, given the following argument definition:
argument :foo do
arity one_or_more
end
The usage banner would display:
Usage: foobar FOO [FOO...]
Use the convert
setting to transform any parameter argument to another type.
The convert
accepts a conversion name as a predefined symbol or class.
For example, to convert an argument to an integer:
argument :foo do
convert :int
# or
convert Integer
end
The supported conversion types are:
:bool
or:boolean
- e.g.yes,1,y,t
becomestrue
,no,0,n,f
becomesfalse
:date
- e.g.28/03/2020
becomes#<Date: 2020-03-28...>
:float
- e.g.-1
becomes-1.0
:int
or:integer
- e.g.+1
becomes1
:path
or:pathname
- e.g./foo/bar/baz
becomes#<Pathname:/foo/bar/baz>
:regex
or:regexp
- e.g.foo|bar
becomes/foo|bar/
:uri
- e.g.foo.com
becomes#<URI::Generic foo.com>
:sym
or:symbol
- e.g.foo
becomes:foo
:list
or:array
- e.g.a,b,c
becomes["a", "b", "c"]
:map
or:hash
- e.g.a:1 b:2 c:3
becomes{a: "1", b: "2", c: "3"}
To convert to an array of a given type, specify plural or append an array
orlist
to any base type:
:bools
,:bool_array
or:bool_list
- e.g.t,f,t
becomes[true, false, true]
:floats
,:float_array
or:float_list
- e.g.1,2,3
becomes[1.0, 2.0, 3.0]
:ints
,:int_array
or:int_list
- e.g.1,2,3
becomes[1, 2, 3]
Or, use the list_of
method and pass the type as a first argument.
To convert to a hash with values of a given type, append a hash
or map
to
any base type:
:bool_hash
or:bool_map
- e.ga:t b:f c:t
becomes{a: true, b: false, c: true}
:float_hash
or:float_map
- e.ga:1 b:2 c:3
becomes{a: 1.0, b: 2.0, c: 3.0}
:int_hash
or:int_map
- e.ga:1 b:2 c:3
becomes{a: 1, b: 2, c: 3}
Or, use the map_of
method and pass the type as a first argument.
For example, given options with a required list and map arguments:
option :foo do
long "--foo list"
convert :bools
# or
convert list_of(:bool)
end
option :bar do
long "--bar map"
convert :int_map
# or
convert map_of(:int)
end
And then parsing the following command line input:
--foo t,f,t --bar a:1 b:2 c:3
This would result in an array of booleans and a hash with integer values:
params[:foo] # => [true, false, true]
params[:bar] # => {:a=>1, :b=>2, :c=>3}
Use a Proc
object to define custom conversion.
For example, to convert the command line input to uppercase:
option :foo do
long "--foo string"
convert ->(val) { val.upcase }
end
Use the default
setting to specify a default value for an optional parameter.
The parser will use default when the command line input isn't present.
For example, given the following option definition:
option :foo do
long "--foo string"
default "bar"
end
When the option --foo
isn't present on the command line, the params
will have a default value set:
params[:foo] # => "bar"
Or, use a Proc
object to specify a default value:
option :foo do
long "--foo string"
default -> { "bar" }
end
A parameter cannot be both required and have a default value. This will raise
ConfigurationError
. The parser treats positional arguments as required.
To have a default for a required argument make it optional:
argument :foo do
optional
default "bar"
desc "Argument description"
end
The usage description for a given parameter will display the default value:
Usage: foobar [FOO]
Arguments:
FOO Argument description (default "bar")
Use the description
or desc
setting to provide a summary for
a parameter. The help method uses a parameter
description to generate a usage display.
For example, given an option with a description:
option :foo do
desc "Option description"
end
This will result in the following help display:
Usage: foobar [OPTIONS]
Options:
--foo Option description
2.5.5 hidden
Use the hidden
setting to hide a parameter from the help display.
For example, given a standard argument and a hidden one:
argument :foo
argument :bar do
hidden
end
The above will hide the :bar
parameter from the usage banner:
Usage: foobar FOO
Only flag and option parameters can use
the long
setting.
Use the long
setting to define a long name for an option. By convention,
a long name uses a double dash followed by many characters.
When you don't specify a short or long name, the parameter name will serve as the option's long name by default.
For example, to define the --foo
option:
option :foo
To change the default name to the --fuu
option:
option :foo do
long "--fuu"
end
A long option can accept an argument. The argument can be either required or optional. To define a required argument, separate it from the option name with a space or an equal sign.
For the :foo
option to accept a required integer argument:
option :foo do
long "--foo int"
end
These are all equivalent ways to define a long option with a required argument:
long "--foo int"
long "--foo=int"
To define an optional argument, surround it with square brackets. Like the required argument, separate it from the option name with a space or an equal sign. It is possible to skip the space, but that would make the option description hard to read.
For the :foo
option to accept an optional integer argument:
option :foo do
long "--foo [int]"
end
These are all equivalent ways to define a long option with an optional argument:
long "--foo [int]"
long "--foo=[int]"
long "--foo[int]"
When specifying short and long option names, only define the argument for the long name.
For example, to define an option with short and long names that accepts a required integer argument:
option :foo do
short "-f"
long "--foo int"
end
Note that the parser performs no conversion of the argument. Use the convert setting to transform the argument type.
The parser will use a parameter name to match command line inputs by default. It will convert underscores in a name into dashes when matching input.
For example, given the :foo_bar
keyword definition:
keyword :foo_bar
And the following command line input:
foo-bar=baz
This would result in:
params[:foo_bar] # => "baz"
Use the name
setting to change the parameter default input name.
keyword :foo_bar do
name "fum"
end
Given the following command line input:
fum=baz
This would result in:
params[:foo_bar] # => "baz"
Use uppercase characters when changing the input name for environment variables:
env :foo do
name "FOO_VAR"
end
All parameters are optional apart from positional arguments.
Use the optional
setting to mark a parameter as optional.
For example, given a required argument and an optional one:
argument :foo do
desc "Foo argument description"
end
argument :bar do
optional
desc "Bar argument description"
end
And given the following command line input:
baz
This would result in:
params[:foo] # => "baz"
params[:bar] # => nil
The usage banner will display an optional argument surrounded by brackets:
Usage: foobar FOO [BAR]
Arguments:
FOO Foo argument description
BAR Bar argument description
Use the permit
setting to restrict input to a set of possible values.
For example, to restrict the :foo
option to only "bar"
and "baz"
strings:
option :foo do
long "--foo string"
permit %w[bar baz]
end
Given the following command line input:
--foo bar
This would result in:
params[:foo] # => "bar"
Given not permitted value qux
on the command line:
--foo qux
This would raise a TTY::Option::UnpermittedArgument
error and
make the params invalid.
The parser checks permitted values after applying conversion first. Because of this, permit setting needs its values to be already of the correct type.
For example, given integer conversion, permitted values need to be integers as well:
option :foo do
long "--foo int"
convert :int
permit [11, 12, 13]
end
Then given not permitted integer:
--foo 14
This would invalidate params
and collect the
TTY::Option::UnpermittedArgument
error.
The help method displays permitted values in the parameter description.
For example, given the following option:
option :foo do
short "-f"
long "--foo string"
permit %w[a b c d]
desc "Option description"
end
Then the description for the option would be:
Usage: foobar [OPTIONS]
Options:
-f, --foo string Option description (permitted: a, b, c, d)
Parser only requires arguments to be present on the command line by default. Any other parameters like options, keywords and environment variables are optional.
Use the required
setting to force parameter presence in command line input.
For example, given a required keyword and an optional one:
keyword :foo do
required
desc "Foo keyword description"
end
keyword :bar do
desc "Bar keyword description"
end
And given the following command line input:
foo=baz
This would result in:
params[:foo] # => "baz"
params[:bar] # => nil
Given the following command line input without the foo
keyword:
bar=baz
This would raise a TTY::Option::MissingParameter
error.
Then printing errors summary would display the following error description:
Error: keyword 'foo' must be provided
The usage banner displays the required parameters first. Then surrounds any optional parameters in brackets.
The help display for the above keywords would be:
Usage: foobar FOO=FOO [BAR=BAR]
Keywords:
FOO=FOO Foo keyword description
BAR=BAR Bar keyword description
Only flag and option parameters can use
the short
setting.
Use the short
setting to define a short name for an option. By convention,
a short name uses a single dash followed by a single alphanumeric character.
For example, to define the -f
option:
option :foo do
short "-f"
end
A short option can accept an argument. The argument can be either required or optional. To define a required argument, separate it from the option name with a space or an equal sign. It is possible to skip the space, but that would make the option description hard to read.
For the :foo
option to accept a required integer argument:
option :foo do
short "-f int"
end
These are all equivalent ways to define a short option with a required argument:
short "-f int"
short "-f=int"
short "-fint"
To define an optional argument, surround it with square brackets. Like the required argument, separate it from the option name with a space or an equal sign. It is possible to skip the space, but that would make the option description hard to read.
For the :foo
option to accept an optional integer argument:
option :foo do
short "-f [int]"
end
These are all equivalent ways to define a short option with an optional argument:
short "-f [int]"
short "-f=[int]"
short "-f[int]"
When specifying short and long option names, only define the argument for the long name.
For example, to define an option with short and long names that accepts a required integer argument:
option :foo do
short "-f"
long "--foo int"
end
Note that the parser performs no conversion of the argument. Use the convert setting to transform the argument type.
Use the validate
setting to ensure that inputs match a validation rule.
The rule can be a string, a regular expression or a Proc
object.
For example, to ensure the --foo
option only accepts digits:
option :foo do
long "--foo int"
validate "\d+"
end
Given the following command line input:
--foo bar
This would raise a TTY::Option::InvalidArgument
error that would
make params
invalid.
Then printing errors summary would output:
Error: value of `bar` fails validation for '--foo' option
To define a validation rule as a Proc
object that accepts
an argument to check:
keyword :foo do
convert :int
validate ->(val) { val < 12 }
end
The parser validates a value after applying conversion first. Because of this, the value inside a validation rule is already of the correct type.
Given the following command line input:
foo=13
This would raise a TTY::Option::InvalidArgument
error and make
params
invalid.
Then using the errors summary would print the following error:
Error: value of `13` fails validation for 'foo' keyword
Use the parse
method to match command line inputs against defined parameters.
The parse
method reads the input from the command line (aka ARGV
) and
the environment variables (aka ENV
) by default. It also accepts inputs
as an argument. This is useful when testing commands.
For example, given the following parameter definitions:
argument :foo
flag :bar
keyword :baz
env :qux
Then parsing the command line inputs:
parse(%w[12 --bar baz=a QUX=b])
This would result in:
params[:foo] # => "12"
params[:bar] # => true
params[:baz] # => "a"
params[:qux] # => "b"
The parser doesn't force any order for the parameters except for arguments.
For example, reordering inputs for the previous parameter definitions:
parse(%w[12 QUX=b --bar baz=a])
This would result in the same values:
params[:foo] # => "12"
params[:bar] # => true
params[:baz] # => "a"
params[:qux] # => "b"
The parser handles compact shorthand options that start with a single dash. These must be boolean options except for the last one that can accept an argument.
For example, passing three flags and an option with an argument to parse:
parse(%w[-f -b -q -s 12])
This is equivalent to parsing:
parse(%w[-fbqs 12])
Parameter parsing stops at the --
terminator. The parser collects leftover
inputs and makes them accessible with the remaining method.
For example, given extra input after the terminator:
parse(%w[12 baz=a QUX=b -- --fum])
This would result in:
params[:foo] # => 12
params[:bar] # => false
params[:baz] # => "a"
params[:qux] # => "b"
params.remaining # => ["--fum"]
The parse
method doesn't raise any errors by default. Why? Displaying
error backtraces in the terminal output may not be helpful for users.
Instead, the parser collects any errors and exposes them through the
errors method.
Use the :raise_on_parse_error
keyword set to true
to raise parsing errors:
parse(raise_on_parse_error: true)
Parsing errors inherit from TTY::Option::ParseError
.
For example, to catch parsing errors:
begin
parse(raise_on_parse_error: true)
rescue TTY::Option::ParseError => err
...
end
Users can provide any input, including parameters the parser didn't expect and define.
When the parser finds an unknown input on the command line, it raises
a TTY::Option::InvalidParameter
error and adds it to the
errors array.
Use the :check_invalid_params
keyword set to false
to ignore unknown
inputs during parsing:
parse(check_invalid_params: false)
This way, the parser will collect all the unrecognised inputs into the remaining array.
All defined parameters are accessible from the params
object.
The params
object behaves like a hash with indifferent access. It doesn't
differentiate between arguments, keywords, options or environment variables.
Because of that, each parameter needs to have a unique name.
For example, given a command with all parameter types:
class Command
include TTY::Option
argument :foo
keyword :bar
option :baz do
long "--baz string"
end
env :qux
def run
print params[:foo]
print params["bar"]
print params["baz"]
print params[:qux]
end
end
And the following command line input:
a bar=b --baz c QUX=d
Then instantiating the command:
cmd = Command.new
And parsing command line input:
cmd.parse
And running the command:
cmd.run
This would result in the following output:
abcd
The parse
method only raises configuration errors. The parsing errors are
not raised by default. Instead, the errors
method on the params
object
gives access to any parsing error.
params.errors # => TTY::Option::AggregateErrors
The errors
method returns an TTY::Option::AggregateErrors
object that
is an Enumerable
.
For example, to iterate over all the errors:
params.errors.each do |error|
...
end
The TTY::Option::AggregateErrors
object has the following
convenience methods:
messages
- an array of all error messagessummary
- a string of formatted error messages ready to display in the terminal
For example, given an argument that needs to appear at least two times in the command line input:
argument :foo do
arity at_least(2)
end
And parsing only one argument from the command line input:
parse(%w[12])
Then printing errors summary:
puts params.errors.summary
This would print the following error message:
Error: argument 'foo' should appear at least 2 times but appeared 1 time
Adding integer conversion to the previous example:
argument :foo do
arity at_least(2)
convert :int
end
And given only one invalid argument to parse:
parse(%w[zzz])
The summary would be:
Errors:
1) Argument 'foo' should appear at least 2 times but appeared 1 time
2) Cannot convert value of `zzz` into 'int' type for 'foo' argument
Use the :raise_on_parse_error keyword to raise parsing errors on invalid input.
Consider using the tty-exit gem for more expressive exit code reporting.
For example, the TTY::Exit
module provides the exit_with
method:
class Command
include TTY::Exit
include TTY::Option
def run
if params.errors.any?
exit_with(:usage_error, params.errors.summary)
end
...
end
end
When the parser finds an unknown input on the command line, it raises
a TTY::Option::InvalidParameter
error and adds it to the
errors array.
Use the :check_invalid_params keyword
set to false
to ignore unknown inputs during parsing:
parse(check_invalid_params: false)
This way, the parser will collect all the unrecognised inputs
into an array. The remaining
method on the params
gives access
to all invalid inputs.
For example, given an unknown option to parse:
parse(%w[--unknown])
Then inspecting the remaining
inputs:
params.remaining # => ["--unknown"]
The parser leaves any inputs after the --
terminator alone. Instead,
it collects them into the remaining array. This is useful when passing
inputs over to other command line applications.
Use the valid?
method to check that command line inputs meet all
validation rules.
The valid?
method is available on the params
object:
params.valid? # => true
Use the errors method to check for any errors and not only validation rules:
params.errors.any?
The usage
method accepts a block that configures the
help display.
Use the header
setting to display information above the banner.
For example, to explain a program's purpose:
usage do
header "A command line interface for foo service"
end
This would print:
A command line interface for foo service
Usage: foo [OPTIONS]
The header
setting accepts many arguments, each representing a single
paragraph. An empty string displays as a new line.
For example, to create an introduction with two paragraphs separated by an empty line:
usage do
header "A command line interface for foo service",
"",
"Access and retrieve data from foo service"
end
Or, add two paragraphs using the header
setting twice:
usage do
header "A command line interface for foo service"
header "Access and retrieve data from foo service"
end
Both would result in the same output:
A command line interface for foo service
Access and retrieve data from foo service
Usage: foo [OPTIONS]
The program
setting uses an executable file name to generate a program
name by default.
For example, to override the default name:
usage do
program "custom-name"
end
Then usage banner will display a custom program name:
Usage: custom-name
The command
setting uses a class name to generate a command name by default.
It converts a class name into a dash case.
For example, given the following command class name:
class NetworkCreate
include TTY::Option
end
The command name would become network-create
.
Use the command
or commands
setting to change the default command name.
For example, to change the previous class's default command name:
class NetworkCreate
include TTY::Option
usage do
command "net-create"
end
end
The usage banner would be:
Usage: program net-create
Use the commands
setting for naming a subcommand.
For example, to add create
command as a subcommand:
module Network
class Create
include TTY::Option
usage do
commands "network", "create"
end
end
end
This will result in the following usage banner:
Usage: program network create
Use the no_command
setting to skip having a command name:
usage do
no_command
end
This will display only the program name:
Usage: program
The banner
setting combines program, command and parameter names
to generate usage banner.
For example, given the following usage and parameter definitions:
usage do
program "prog"
command "cmd"
end
argument :foo
keyword :bar
option :baz
env :qux
Then usage banner would print as follows:
Usage: prog cmd [OPTIONS] [ENVIRONMENT] FOO [BAR=BAR]
The help generator displays the usage banner first unless a header is set.
Use the banner
setting to create a custom usage display.
For example, to change the parameters format:
usage do
program "prog"
command "cmd"
banner "Usage: #{program} #{command.first} <opts> <envs> foo [bar=bar]"
end
This would display as:
Usage: prog cmd <opts> <envs> foo [bar=bar]
Use the :param_display setting to change the banner parameters format.
Use description
or desc
setting to display information right after
the usage banner.
For example, to give extra information:
usage do
desc "A description for foo service"
end
This would print:
Usage: foo [OPTIONS]
A description for foo service
The desc
setting accepts many arguments, each representing a single
paragraph. An empty string displays as a new line.
For example, to create a description with two paragraphs separated by an empty line:
usage do
desc "A description for foo service",
"",
"Learn more about foo service\nby reading tutorials"
end
Or, add two paragraphs using the desc
setting twice:
usage do
desc "A description for foo service",
desc <<~EOS
Learn more about foo service
by reading tutorials
EOS
end
Both would result in the same output:
Usage: foo [OPTIONS]
A description for foo service
Learn more about foo service
by reading tutorials
Use the example
or examples
setting to add a usage examples section
to the help display.
The example
setting accepts many arguments, each representing a single
paragraph. An empty string displays as a new line.
For instance, to create an example usage displayed on two lines:
usage do
example "Some example how to use foo",
" $ foo bar"
end
This will result in the following help output:
Examples:
Some example how to use foo
$ foo bar
Or, add two examples using the example
setting twice:
usage do
example "Some example how to use foo",
" $ foo bar"
example <<~EOS
Another example how to use foo"
$ foo baz
EOS
end
The examples section would display the following:
Examples:
Some example how to use foo
$ foo bar
Another example how to use foo
$ foo baz
Use the footer
setting to display text after all information
in the usage help.
For example, to reference further help:
usage do
footer "Run a command followed by --help to see more info."
end
This would print as follows:
Usage: foo [OPTIONS]
Run a command followed by --help to see more info.
The footer
setting accepts many arguments, each representing a single
paragraph. An empty string displays as a new line.
For example, to display further help with two paragraphs separated by an empty line:
usage do
footer "Run a command followed by --help to see more info.",
"",
"Report bugs to the mailing list."
end
Or, add two paragraphs using the footer
setting twice:
usage do
footer "Run a command followed by --help to see more info."
footer "Report bugs to the mailing list."
end
Both would result in the same output:
Usage: foo [OPTIONS]
Run a command followed by --help to see more info.
Report bugs to the mailing list.
Use the help
method to generate usage information about defined parameters.
The usage describes how to add different sections to the help display.
For example, given the following command class definition with
a run
method that prints help:
class Command
include TTY::Option
usage do
program "foobar"
no_command
header "foobar CLI"
desc "CLI description"
example "Example usage"
footer "Run --help to see more info"
end
argument :foo, desc: "Argument description"
keyword :bar, desc: "Keyword description"
option :baz, desc: "Option description"
env :qux, desc: "Environment description"
flag :help do
short "-h"
long "--help"
desc "Print usage"
end
def run
if params[:help]
print help
exit
end
end
end
Running the command with --help
flag:
cmd = Command.new
cmd.parse(%w[--help])
cmd.run
This would result in the following help display:
foobar CLI
Usage: foobar [OPTIONS] [ENVIRONMENT] FOO [BAR=BAR]
CLI description
Arguments:
FOO Argument description
Keywords:
BAR=BAR Keyword description
Options:
--baz Option description
-h, --help Print usage
Environment:
QUX Environment description
Examples:
Example usage
Run --help to see more info
Pass a block to the help
method to change generated usage information.
The block accepts a single argument, a TTY::Option::Sections
object.
This object provides hash-like access to each named part of the help display.
The following are the names of all supported sections ordered by help display from top to bottom:
:header
:banner
:description
:arguments
:keywords
:options
:environments
:examples
:footer
Accessing a named section returns a TTY::Option::Section
object
with name
and content
methods.
For example, to access the arguments section content:
help do |sections|
sections[:arguments].content # => "\nArguments:\n FOO Argument description"
end
To add a new section, use the add_after
and add_before
methods. These
methods accept three arguments. The first argument is the section name
to add after or before. The second argument is a new section name,
and the last is content to add.
For example, to insert a new commands section after the description:
help do |sections|
sections.add_after :description, :commands, <<~EOS.chomp
Commands:
create Create command description
delete Delete command description
EOS
end
Given the following usage and parameter definition:
usage do
program "prog"
command "cmd"
desc "Program description"
end
argument :foo do
desc "Foo argument description"
end
The help display would be:
Usage: prog cmd FOO
Program description
Commands:
create Create command description
delete Delete command description
Arguments:
FOO Argument description
Use delete
and replace
methods to change existing sections.
For example, to remove a header section:
help do |sections|
sections.delete :header
end
Or, to replace the content of a footer section:
help do |sections|
sections.replace :footer, "\nReport bugs to the mailing list."
end
The help output has no indentation except for displaying parameters by default.
Use the :indent
keyword to change the indentation of the help display.
For example, to indent help display by two spaces:
help(indent: 2)
The help generator orders parameters alphabetically within each section by default.
Use the :order
keyword to change the default ordering.
The :order
expects a Proc
object as a value. The Proc
accepts
a single argument, an array of parameters within a section.
For example, to preserve the parameter definition order:
help(order: ->(params) { params })
The usage banner displays positional and keyword arguments in uppercase letters by default.
For example, given the following parameter definitions:
usage do
program "prog"
end
argument :foo, desc: "Argument description"
keyword :bar, desc: "Keyword description"
option :baz, desc: "Option description"
env :qux, desc: "Environment description"
The usage banner would print as follows:
Usage: prog [OPTIONS] [ENVIRONMENT] FOO [BAR=BAR]
Use the :param_display
keyword to change the banner parameter formatting.
The :param_display
expects a Proc
object as a value. The Proc
accepts
a single argument, a parameter name within a section.
For example, to lowercase and surround parameters with <
and >
brackets:
help(param_display: ->(param) { "<#{param.downcase}>" })
This would result in the following usage banner and parameter sections:
Usage: prog [<options>] [<environment>] <foo> [<bar>=<bar>]
Arguments:
<foo> Argument description
Keywords:
<bar>=<bar> Keyword description
Options:
--baz Option description
Environment:
QUX Environment description
The help generator wraps content at the width of 80
columns by default.
Use the :width
keyword to change it, for example, to 120
columns:
help(width: 120)
Use the tty-screen gem to change the help display based on terminal width.
For example, to expand the help display to the full width of the terminal window:
help(width: TTY::Screen.width)
After checking out the repo, run bin/setup
to install dependencies.
Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
.
To release a new version, update the version number in version.rb
, and then
run bundle exec rake release
, which will create a git tag for the version,
push git commits and tags, and push the .gem
file to
rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/piotrmurach/tty-option. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
The gem is available as open source under the terms of the MIT License.
Everyone interacting in the TTY::Option project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
Copyright (c) 2020 Piotr Murach. See LICENSE for further details.