Not the last console application. PowerArgs

 
event

They keep coming... Let's have a look at PowerArgs.
With its NuGet package and sane, useful documentation both in the README and in the WIKI.

Conventional Attribution

PowerArgs relies heavily on attributes. Whereas some other frameworks use a single attribute with multiple properties to drive behavior, PowerArgs uses multiple attributes. It is true that some of those attributes have multiple properties themselves, so it is not just waste of keystrokes.
I have to admit that this multiple argument path and the usage of Arg- prefixes is not much of my liking; but, in the end, it is just a matter of taste, as the framework works very well and offers a lot of power and unique features.

The "conventional" part of the title comes from the way different commands are implemented: modelling them as methods that take an Arg-decorated object as argument.

Implementing our example

Implementing our example was pretty simple:

Some clarifications:

  • decorate the argument object with [ArgExceptionBehavior(ArgExceptionPolicy.StandardExceptionHandling)] for the framework handling parsing exceptions such as missing mandatory arguments or type problems so that friendly-er messages are printed instead of daunting exceptions.
  • the Action property, mandatory and positioned as first argument is a requirement of the ActionFramework for multiple commands to be dispatched to the correct method.
  • the Help property, decorated with HelpHook allows getting global and command-specific help messages.

Dispatching is also simple: translate one argument object into another (redundant if we embraced the framework), instantiate and call the method.

Being attribute-driven, we would face the same challenges for localization of messages.

The Challenges

Mandatory Arguments

Mandatory arguments are not the default, but decorating a property with [ArgRequired] enables easy reporting of missing mandatory arguments:

Extra, unmapped arguments will make an error appear, but that behavior is customizable.

Non-Textual arguments

Declaring the right type for the property works fine including flags (boolean properties).
Failures to do so will reported back to the user:

Default values are provided as objects, instead of strings.

Furthermore, there is support for custom argument types via custom revivers that turn on string/s into objects. Very nice to have.

Multi-arguments

Collection arguments are supported by declaring the type as such with no extra decoration required.

Again, there is no help hint in regards of what that separator character might be when displaying help to the user (as it happens with default values).
We could use [ArgExample] on the top- level argument object to help the user out with collection semantics, but an out-of-the-box solution might be desirable.

Showing Help

Running the program with the -help argument provides a very nice and colorful auto-generated list of supported actions and arguments:

powerargs_help

And using the -help argument with a action, drills down to the action-level documentation, equally colorful:

powerargs_command_help

Furthermore, there seems to be support for generating usage documentation, not only for the command line user, but also in HTML. Nice, indeed, but not so well-documented... yet.

Command Dispatching

As mentioned previously, commands are executed (in its simplest form) by providing a method that takes the argument object and invoking Args.InvokeAction(args).
We can further detach actions from the argument definition by using [ArgActionType].

There seems to be a way to tap into the action dispatching method, by using [ArgActionResolver], but I am not sure how to use it and could not find much documentation to help me. This could be a place to use an IOC container if we had the use for it.

Conclusion

PowerArgs surprised me. And it is a very positive surprise. I was put off at first by the usage of multiple, prefixed attributes, but as I worked with it, I found out that there is a lot of power in this framework. It can do everything to be done in the sample application and way more.

One thing I am really thrilled about is the support for tab completion, interactive console applications and secure parameters. I goes way beyond my sample, but it is a feature that can save a lot of time if the requirement arises. Heres is a simple image on how tab completion works with the simple addition of a [TabCompletion] attribute on our argument object.

powerargs_tab_completion

I will certainly keep an eye on this one in case I do not feel like going out the PS way of things.

Last Console Series

  1. The beginning
  2. GoCommando
  3. CommandLineParser
  4. PowerArgs (this)
  5. LBi.Cli.Arguments
  6. Command Line Utils
  7. CLAP
  8. Wrap-up