>Install-Package CLAP
Package Homepage:
Previous post introduced the Command-Line Auto Parser and provided examples for:
In this post, additional features will be introduced:
As seen in the base usage samples, each verb defines it’s own set of parameters.
Sometimes we need to handle some parameters which are not necessarily related to a specific verb.
In the following example, the “debug” parameter makes the application wait for a debugger to be attached:
[Global]
public static void Debug()
{
Debugger.Launch();
}
}
Notice the syntax of the Global parameter definition:
In the class that contain the verb(s), we add a new method and mark it with the [Global] attribute.
If the user provides the “-debug” switch, that method will be called.
In this example – the method doesn’t have any arguments. A method without arguments is a switch.
The parameter name can be overridden by specifying a name that will be used instead (not in-addition) to the method’s name.
In the following example, “break” is used instead of “debug”:
[Global("break")]
public static void Debug()
{
Debugger.Launch();
}
}
Global handlers can also handle user’s input.
In the following example, various handlers are defined for different argument types:
[Global("priority")]
public static void SetThreadPriority(ThreadPriority priority)
{
Thread.CurrentThread.Priority = priority;
}
[Global("number")]
public static void DoSomethingWithAnumber(int number)
{
Console.WriteLine("A number: {0}", number);
}
So we can run:
Global handlers’ parameters support Validation, such as verb parameters.
For example:
Global handlers can be registered via a delegate.
In the following example, the “debug” switch is registered as a delegate:
p.RegisterParameterHandler("debug", delegate
{
Debugger.Launch();
});
p.Run(args);
}
}
Additional parameter names can be registered with a comma-separated list of names:
p.RegisterParameterHandler("debug,d,break", delegate
{
Debugger.Launch();
});
p.Run(args);
}
}
In the following example, all the three previous samples are rewritten using lambda expressions:
p.RegisterParameterHandler<string>(
"thread",
name => Thread.CurrentThread.Name = name);
p.RegisterParameterHandler<ThreadPriority>(
"priority",
priority => Thread.CurrentThread.Priority = priority);
p.RegisterParameterHandler<int>(
"number",
number => Console.WriteLine("A number: {0}", number));
p.Run(args);
}
}
CLAP comes with the following built-in validators:
Additional validators can be easily implemented by deriving from ValidationAttribute and implementing IParameterValidator.
The following is an example of a validation attribute that validates that a string input has a length of at least a specified value:
public LengthValidationAttribute(int length)
: base(new LengthValidator(length))
{
Length = length;
}
public override string Description
{
get
{
return string.Format(
"Length is at least {0}", Length);
}
}
class LengthValidator : IParameterValidator
{
public int Length { get; private set; }
public LengthValidator(int length)
{
Length = length;
}
public void Validate(object value)
{
var str = (string)value;
if (str.Length < Length)
{
throw new ValidationException(
string.Format(
"Length should be at least {0}",
Length));
}
}
}
}
Notice the Description property. It is used when providing help to the user, as described in the next chapter.
Using the attribute:
Help can be automatically provided to the user when the user asks for it using a registered parameter.
In the following example, we register the “help” and “?” parameters to write the help string to the console:
p.RegisterHelpHandler("help,?", help => Console.WriteLine(help));
p.Run(args);
}
}
When the user enters either “help” or “?” as the first argument, the auto-generated help will be printed to the console.
The help contains a list of verbs, for each verb – a list of parameters, their types and additional properties, such as whether the argument is required and has validation.
The help can contain, in-addition to all the automatic generated information (types, required, validation, defaults) also a friendly description.
Verbs and Parameters can have a description defined using the Description property of each attribute.
This is true also for defined global arguments, for example:
In-order to provide a description for registered (vs. defined) global parameters handlers, use the overload that accepts a description string, for example:
p.RegisterParameterHandler(
"debug,d,break",
delegate { Debugger.Launch(); },
"Attach a debugger to the process");
p.Run(args);
}
}
An empty handler can be registered to be executed when no input has been entered.
In the following example, if no input is entered, a “What?” string will be printed to the console:
p.RegisterEmptyHandler(delegate
{
Console.WriteLine("What?");
});
p.Run(args);
}
}
We can also register a handler that will print the help string to the console, using the special RegisterEmptyHelpHandler method:
p.RegisterEmptyHelpHandler(help => Console.WriteLine(help));
p.Run(args);
}
}
The following is a recommended complete set of help handlers, both ?,help,h and an empty handler:
p.RegisterEmptyHelpHandler(help => Console.WriteLine(help));
p.RegisterHelpHandler("?,help,h", help => Console.WriteLine(help));
p.Run(args);
}
}
Previous post introduced the Command-Line Auto Parser and provided examples for:
This post introduced some additional features:
For additional information, sample usages and suggestions, please email me at: adrianaisemberg@gmail.com
Automatic command-line verb and argument parsing using smart reflection.
Inspired by the ASP.NET MVC Controller-Actions, finally – a kick-ass command-line parser. The last one you will ever need!
Consider the following method:
The Print method is marked with the [Verb] attribute which defines method as valid entry points for the application.
Each of the method’s arguments are automatically mapped to command-line input arguments, regardless of their order.
Notice that all names, both for verbs and parameter names are case-insensitive.
Let’s change our Main method to use the parser:
After successfully compiling, we can now run our application, providing a verb and arguments:
Which prints:
A class may contain more than one verb.
In the following example, “print” and “login” are two different entry-points for the application, each with a different set of arguments:
[Verb]
public static void Login(string userName, string password)
{
}
}
One of the verbs, or even the single one if no more than one are available, can be defined as the default verb using the [DefaultVerb] attribute above the class.
In the following example, “print” is the default verb, so if the user doesn’t provide a verb in the command-line, “print” will be called:
[Verb]
public static void Login(string userName, string password)
{
}
}
In that case, we can call:
A verb can have more than one name. The first name is the method’s name but additional names can be defined using the Aliases property.
In the following example, “p” is an additional name for the “print” verb and both “l” and “log” are additional names for the “login” verb:
[Verb(Aliases = "l,log")]
public static void Login(string userName, string password)
{
}
}
Parameters are automatically detected according to their names. Additional options can be defined for parameters using more attributes.
As a verb, parameters can also have additional names when marked with the [Parameter] attribute.
In the following example, both “name” and “n” are additional names for the “userName” parameter and both “pass” and “p” are for the “password” parameter:
A parameter can be omitted from the input. If a parameter is omitted, it’s value will have the type’s default (null for reference types, zero for value types).
A default value can be defined for a parameter to override the type’s default.
In the following example, “Hello” is the default for the prefix parameter and 5 for count:
Now we can run:
And get this result:
Boolean types are treated as switches.
A switch is an argument that doesn’t need a value. If the argument exists – the value is true, otherwise – it is false.
In the following example, the “upper” parameter is a boolean, and therefore – a switch. In-addition, it has an additional, shorter name: “u”:
for (int i = 0; i < count; i++)
{
Console.WriteLine("{0} {1}", prefix, name);
}
}
}
Now we can run:
HELLO WORLD
HELLO WORLD
HELLO WORLD
HELLO WORLD
HELLO WORLD
The supported parameter types are:
Arrays are called as comma-separated values. For example:
Hello Adrian
Hello Yoav
Hello Shlomo
A parameter can be marked as required. A missing argument will throw a MissingRequiredArgumentException.
In the following example, the “name” parameter is required:
Trying to run the program without providing a value for “name” will throw an exception.
In this example, the exception is not caught and therefore, the application crashes and the stack-trace is printed to the console:
Unhandled Exception: System.ArgumentException: Missing argument for 'name'
at …
Validation attributes can be specified for parameters.
Current available attributes are:
Providing a value that doesn’t pass validation will throw a ValidationException.
In the following example, “count” is validated to be more than 3:
Additional validation attributes can be defined for the same parameter. Validation passes only if all validators pass (AND).
In the following example, “count” is validated to be more than 3 and less-or-equal to 20:
The following is a list of all the exceptions that might be thrown when failing to parse the command-line.
Notice that all exception derive from the abstract CommandLineException.
This post introduced the Command-Line Auto Parser and provided examples for:
In the next post, additional features are introduced: