Skip to content

Configuring Options

Jan Michelfeit edited this page Feb 2, 2016 · 2 revisions

Configuring Options

Program options are configured with three types of object — options, parameters and constraints.

Options

Each option is represented by an instance of generic class Option<T>. To create an instance of Option<T>, use factory methods provided by OptionFactory.

There are two basic types of options: with and without an option parameter.

To create an option without a parameter, you simply call OptionFactory.Create() with two arguments — the first one specifies whether the option is required (true) or optional (false), the second one contains option description for usage text. Example:

var verbose = OptionFactory.Create(false, "Be more verbose");

In order to create an option with a parameter, you need to create instance of class Parameter<T>. For example

var lineWidthParam = new IntParameter(true, "WIDTH", 80);

For more information see Parameters.

Option object with a parameter is created the same way as in case of an option without a parameter, but you pass Parameter<T> object as the third argument of OptionFactory.Create(). This method is generic, but thanks to type inference in C# you don't need to specify the type explicitly. Thus the following two lines of code are equivalent:

var lineWidth = OptionFactory.Create(false, "Wrap lines at WIDTH", lineWidthParam);
Option<int> lineWidth = OptionFactory.Create<int>(false, "Wrap lines at WIDTH", lineWidthParam);

Assigning option names

After you've created option object, register it to EasyOpt instance and assign it names with AddOption(). You can specify multiple names.

Names one character long are classified as short option names, longer names are classified as long option names. This means that it is not possible to create a long option with one character long name (e.g. --v).

There are several overloaded versions of AddOption():

 public void AddOption<T>(Option<T> option, params String[] names)
 public void AddOption<T>(Option<T> option, char shortName)
 public void AddOption<T>(Option<T> option, char shortName, String longName)

Overloaded versions accepting char are there just for convenience, the char is converted to string. The following three lines are equivalent:

parser.AddOption(verbose, 'v', "verbose");
parser.AddOption(verbose, "v", "verbose");
parser.AddOption(verbose, new string[] { "v", "verbose" } );

Option names must not be null, at least one option name must be listed and one name cannot be used more than once. Option names can contain any characters except for '=', '-' and whitespace characters. If option name is invalid, an exception of type InvalidNameException or DuplicateOptionNameException is thrown.

Option names are case-sensitive.

Parameters

Option parameters are represented by Parameter<T> instances. This is an abstract class and in practice you use derived concrete types. The main purpose of classes derived from Parameter<T> is to provide method for conversion from parameter value as string to the concrete type T. The converted typed value can be accessed with Parameter<T>.Value property.

EasyOpt provides derived classes for several concrete types:

  • StringParameter performs no conversion and returns the string as is.
  • IntParameter converts parameter to integer value.
  • FloatParameter converts parameter to float value. * EnumParameter<T> is generic class that converts parameter value to enum type T. If a parameter value matches one of the corresponding enum constants, it is converted to that enum constant. Otherwise an exception is thrown. The behaviour of conversion is different from Enum.Parse() because only single named constants are accepted; integer values or lists of named constants are not converted. Case-sensitivity of conversion can be set with EnumParameter<T>.IgnoreCase. If T is not an enum type, EnumParameterException is thrown.

All these classes accept three arguments in their constructors — whether the option is required (true) or optional (false), name displayed in the usage text and the third, optional, argument sets a default value.

When conversion fails ParameterConversionException is thrown, which is in turn wrapped by parser in OptionParameterException.

Example of usage:

var lineWidthParam = new IntParameter(true, "WIDTH", 80);
enum Color { Never, Always, Auto }
var colorParam = new EnumParameter<Color>(false, "WHEN", Color.Auto);

You can easily define your own parameter types by extending class Parameter<T> and implementing its abstract method T convert(String parameter). It is recommended that in case the conversion fails ParameterConversionException is thrown. For an example how a custom parameter can be implemented, see ls example.

Constraints

Constraints are used to restrict range of parameter values. For example you can define that an option parameter must be a number greater than zero or that a parameter value must be in a certain list of accepted values.

Constraints are classes implementing IConstraint<T> interface and its method bool IsValid(T parameter). As you can see, constraints are applied to parameters after conversion from string to the corresponding parameter type (T).

EasyOpt has several predefined constraints:

Constraint Type Description
LowerBoundConstraint int Parameter value must be grater or equal to the number passed as the only argument of the constructor.
UpperBoundConstraint int Parameter value must be less or equal to the number passed as the only argument of the constructor.
StringEnumerationConstraint string Parameter value must be in the specified list of values. This constraint has two overloaded constructors:
StringEnumerationConstraint(IEnumerable<String> acceptedValues, IEqualityComparer<String> comparer)
StringEnumerationConstraint(IEnumerable<String> acceptedValues, bool ignoreCase)
comparer and ignoreCase parameters can be used to specify the way parameter is compared to members of acceptedValues.
ExistingFileConstraint string Parameter must be a valid path (relative of absolute) to an existing file.

To apply a constraint to an option parameter, create its instance and register it to the parameter object. You can define multiple constraints for a single parameter.

lineWidthParam.AddConstraint( new LowerBoundConstraint(1) );
lineWidthParam.AddConstraint( new UpperBoundConstraint(100) );

Constraints do not apply to the default parameter value.

For an example how a custom constraint can be implemented, see touch example.

Clone this wiki locally