adrianaisemberg/CLAP — pull request #25 by appakz (2013-08-29 02:17:26+00:00)
Title: Modifications for working with multiple targets

These commits contain a couple of changes aimed at making CLAP eaiser to work with if you want to use a large(ish) number of non-static target classes.

There are no breaking changes to external interface/API that CLAP exposes, but there are a couple of additional things are explicitly asserted internally that *could* cause some existing apps that use CLAP to start hitting runtime exceptions, but I think that these additional checks are valid and good.

All changes have at least some new unit test coverage as well, and obviously all existing tests in the suite still pass.

## Change 1 - Allow target construction to be deferred to run time

I've described the motivation behind this change in a blog post: http://geekswithblogs.net/GruffCode/archive/2013/08/28/extending-clap-for-larger-applications.aspx

Here's a quick summary:

* Currently, if you want to have a non-trivial number of targets that use instance methods, you need to construct each one and pass it in to this overload of the Run method: Run(string[] args, params object[] targets)
* In the end, only one of those targets will actually be used to run the provided command, and the rest of them were created and never used. If you have a single instance of each one globally available to your app this is probably OK, but if you're using CLAP in an environment that is "state less" (e.g. in a web application)
* But why would you use CLAP in a web application? That's crazy! Perhaps, but in some cases I think it makes a lot of sense, and I've blogged about my motivations for using it here: http://geekswithblogs.net/GruffCode/archive/2013/06.aspx (PS - I'm using CLAP as the back-end for an administrative "console" in an existing web app and it works GREAT)
* I've added a new type to CLAP called the 'TargetResolver' that can have 1 or more target types "registered" along with a callback to construct them. So you can wire up a TargetResolver instance to, say, an IoC container to defer construction of your targets until run time.
* Building the TargetResolver itself was fairly simple, but refactoring the CLAP internals to make it all work was a bit tricker. I actually ended up funneling a lot of the current functionality into using the new TargetResolver behind the scenes to promote some code re-use and simplify some things.

## Change 2 - Allow target classes to have an 'Alias' attribute

Again, this is a change made mostly to make it easier to work with a potentially large number of target classes. Currently if you start working with multiple targets, users need to prefix their commands with the full name of the target class. If you have descriptive names for your classes this can get cumbersome.

For example, if you have a class named 'UserManager' with a method called 'ResetPassword', you'd have to invoke it with a command like 'UserManager.ResetPassword'. You can alias the 'ResetPassword' method to shorten things up, but you can't get around using the full 'UserManager' prefix.

Now you can decorate the UserManager class definition with a 'TargetAliasAttribute' that lets you provide an alias and shorten the prefix that the end users need to provide in order to invoke a command.