Options
- Defining options
- Configuration
- Value parsing
- Value validation
- Consuming parsed values
- Default values
- Nullable values
- Repeatable option
Option is a named command line parameter that have a value.
Options may have:
- only one-char short name,
- only more-than-one-char long name,
- both short and long names.
Defining options
Use a Option<T>()
method of parser or command to add an option:
// Create an option with short name only
var option = parser.Option<string>('s');
// Create an option with long name only
var option = parser.Option<string>("switch");
// Create an option with both short and long names
var option = parser.Option<string>('s', "switch");
There are two versions of Option()
method:
- a generic
Option<T>()
for arbitrarily-typed arguments - a shorthand
Option()
for string-typed arguments
Configuration
Help text
Use either helpText
parameter of Option<T>()
method or a HelpText()
method of CliOption<T>
to specify description for an autogenerated help:
var option = parser.Option<string>('s', helpText: "Help text");
// or
option.HelpText("Help text");
Hidden option
Use either hidden
parameter of Option<T>()
method or a Hidden()
method of CliOption<T>
to hide an option from an autogenerated help:
var option = parser.Option<string>('s', hidden: true);
// or
option.Hidden();
Display order
Use DisplayOrder()
method of CliOption<T>
to override option display order in an autogenerated help:
// This example with generate help with the following ordering:
//
// OPTIONS
// z Option Z
// a Option A
//
// If you drop the DisplayOrder() call - you'll get this:
//
// OPTIONS
// a Option A
// z Option Z
var optionA = parser.Option('a');
var optionZ = parser.Option('z').DisplayOrder(-1000);
Value parsing
Use UseParser()
method of CliOption<T>
to override option value parsing:
var option = parser.Option<OptValue>("opt");
option.UseParser(new OptValueParser());
Read more about value parsing here
NOTE: you must specify a custom parser unless you use any of built-in types as an option’s value.
Value validation
Not every value of an option might be valid. Command line parser supports value validation via callback functions:
var option = parser.Option<OptValue>("opt");
option.Validate(ValidationFunction);
// This function will be called to validate a result of parsing
// It will be called even if option is not set
// Function should return null if value is valid
// and an error message otherwise
string ValidationFunction(OptValue value, bool isSet)
{
if (!isSet)
{
return "value is not set";
}
if(!value.IsGood)
{
return "value is bad";
}
return null;
}
You can add more than one validation function - they will be called in a chain:
var option = parser.Option<OptValue>("opt");
option.Validate(Validate_IsSet);
option.Validate(Validate_IsGood);
string Validate_IsSet(OptValue value, bool isSet)
{
if (!isSet)
{
return "value is not set";
}
return null;
}
string Validate_IsGood(OptValue value, bool isSet)
{
// No need to check "isSet" parameter here
// If value is not set - Validate_IsGood() will not be called,
// since Validate_IsSet() would return an error
if(!value.IsGood)
{
return "value is bad";
}
return null;
}
There is a helper method for required parameter validation - Required()
. It checks if value is set and fails if an option is missing.
Also it affects autogenerated help, marking an option as required one:
var option = parser.Option<OptValue>("opt");
option.Required();
option.Validate(Validate_IsGood);
string Validate_IsGood(OptValue value, bool isSet)
{
// No need to check "isSet" parameter here since Required() will handle it
if(!value.IsGood)
{
return "value is bad";
}
return null;
}
Consuming parsed values
CliOption<T>
class contains the following properties that might be used to access parsed values:
bool IsSet { get; }
- this property will be set totrue
if an option has any value (including a default one)T Value { get; }
- this property provides access to parsed value
CliOption<T>
is implicitly convertible to T
, so there is no need to access Value
property manually in most cases:
var option = parser.Option<string>("opt");
// These two lines of code are identical
RunCommand(option.Value);
RunCommand(option);
// But these are not - x and y variables will have different types
var x = option.Value;
var y = option;
void RunCommand(string arg)
{
Console.WriteLine($"Option is \"{arg}\"");
}
CliOption<T>
is also implicitly convertible to bool
, simplifying access to IsSet
property:
var option = parser.Option<string>("opt");
// These two lines of code are identical
RunCommand(option.IsSet);
RunCommand(option);
// But these are not - x and y variables will have different types
var x = option.IsSet;
var y = option;
void RunCommand(bool hasValue)
{
Console.WriteLine($"Option is \"{(hasValue ? "set" : "not set")}\"");
}
Default values
There’s a way to provide default values for an option. You may use:
- a plain value
- a value from an environment variable
- a value provided by a custom function
Constant default value
Use the DefaultValue()
method to set an option’s default value:
var option = parser.Option<string>("hostname");
option.DefaultValue("localhost");
// This option will have a value "localhost" if it's not set
Default value from an environment variable
Use the FromEnvironmentVariable()
method to bind option’s default value to an environment variable:
var option = parser.Option<string>("hostname");
option.FromEnvironmentVariable("HOSTNAME");
// This option will have a value getenv("HOSTNAME") if it's not set
Default value provided by a custom function
You may define a custom value provider function to set option’s default value. For example, you may try to read default value from a config file:
var option = parser.Option<string>("hostname");
option.DefaultValue(TryReadHostnameFromConfigFile);
// This option will have a value from a config file if it's not set
// If config file doesn't exists option will have no value
bool TryReadHostnameFromConfigFile(out string value)
{
if(configFile.Exists)
{
value = configFile.GetString("hostname");
return true;
}
return false;
}
Using more than one default value
You may set more that one default value from various sources. Parser will try to take each of values in the same order as they were set.
var option = parser.Option<string>("hostname");
option.FromEnvironmentVariable("HOSTNAME");
option.DefaultValue(TryReadHostnameFromConfigFile);
option.DefaultValue("localhost");
bool TryReadHostnameFromConfigFile(out string value)
{
// ...
}
This example above will do the following:
- First parser will try to read
hostname
option from command line arguments - If
hostname
option is not specified, parser will try to parse environment variableHOSTNAME
. - If
HOSTNAME
variable is either not set or contains an invalid value, parser will usehostname
as an option’s value.
Default value and validation
Default values are applied before any validation takes place. So you should be careful when specifying a default value:
var option = parser.Option<string>("option");
option.DefaultValue("not-empty");
// This validator could be omitted without any damage,
// it would never fire
option.Required();
// ...
var option = parser.Option<string>("option");
// This default value could be omitted
// since it would never pass validation
option.DefaultValue("1");
option.Validate(Validate_IsGood);
string ValidationFunction(string value, bool isSet)
{
if(value == null || value.Length < 2)
{
return "value is too short or empty";
}
return null;
}
Nullable values
Non-mandatory options of struct types provide two helpers to handle them:
-
ToNullable()
extension method allows to get a value from an option or(T?)null
if no value is set:var option = parser.Option<int>("option"); // This line of code isn't valid since CliOption<int> is implicilty convertible to int, // not to Nullable<int> int? value = option; // This line of code is valid due to use of ToNullable() method // ToNullable() method returns a properly initialized Nullable<T> int? value = option.ToNullable();
-
AsNullable()
extension method wraps aCliOption<T>
with aNullableCliOption<T>
.NullableCliOption<T>
is an API-compatible version ofCliOption<T>
, which is implicitly convertible toT?
:var option = parser.Option<int>("option").AsNullable(); // This line of code is valid since NullableCliOption<int> is implicilty convertible to Nullable<int> int? value = option; // This line of code is valid due to use of ToNullable() method // ToNullable() method returns a properly initialized Nullable<T> int? value = option.ToNullable();
Repeatable option
There are cases when you might need to have more than one value for an option. There are two ways to archieve this:
-
An option with comma-separated array value:
program --option value-1,value-2,value-3 program --option "value-1, value-2, value-3"
Two separator characters are supported:
,
and;
. -
A repeatable option:
program --option value-1 --option value-2 --option value-3
Array-values options require only a customized value parser unless you use built-in type array
as a value type (e.g. int[]
) - parser will handle such options without any external efforts:
// Arrays of built-in types don't require custom parser
var option1 = parser.Option<string[]>("option-1");
// Arrays of custom types however do require a custom parser
// ! Note that you will need a IValueParser<MyCustomType[]> implementation
// ! and not a IValueParser<MyCustomType>
var option2 = parser.Option<MyCustomType[]>("option-2")
.UseParser(new ArrayOfMyCustomTypeParser());
Parser offers a better way to handle multi-values options called a repeatable option.
Use via RepeatableOption()
method to create a repeatable option:
var option = parser.RepeatableOption<string>("option");
CliRepeatableOption<T>
has almost the same API as ordinary CliOption<T>
.
Differencies are:
- It has no
Value
property but there is aValues
property instead. - It’s implicitly convertible to
T[]
, not toT
.