Thursday, October 15, 2009

Parsing command-line options - part 1

I favor metaprogramming. Annotations in Java and Attributes in C# fit this technique very well, making your code concise and simple.

A good excerise where metaprogramming may help is mixed GNU/POSIX-style option processing for command-line utilities. A descriptive explanation for this use-case is given here.

We want to simplify accessing option values as mush as possible. I suggest the actual work required to use options must be limited to 1) declaration of a simple JavaBean-style interface, and 2) acquiring a reference to that type using the very same array of string arguments that is passed to the main(String[] args) method; and we need not bother coding the interface implementation ourselves - it should be done implicitly.
A sample interface should look like this:

    public interface ITestOptions
   
{
       
@Option(id = 0, required = true, opt = 'a', longOpt = "int-a", description = "a parameter", argumentTag = "valueOfA")
       
Integer getA();
       
@Option(id = 1, required = false, opt = 'b', longOpt = "int-b", description = "b parameter", argumentTag = "valueOfB")
       
Integer getB();
       
@Option(id = 2, required = false, opt = 'x', longOpt = "bool-x", description = "x parameter")
       
Boolean getX();
       
@Option(id = 3, required = false, opt = 'd', longOpt = "double-d", description = "d parameter", argumentTag = "amount")
       
Double getD();
       
@Option(id = 4, required = true, opt = 's', longOpt = "text-s", description = "s parameter", argumentTag = "brief")
       
String getS();
       
@Option(id = 5, required = false, opt = 'm', longOpt = "text-ms", description = "ms parameter", argumentTag = "patternList")
       
String[] getM();
       
@Option(id = 6, required = false, opt = 'z', description = "z parameter", argumentTag = "zet")
       
String[] getZ();
   
}

And here is how it is going to be used in our code:
        final String[] args =
           
{ "-a", "12", "-b", "23", "-x", "-d", "3.14159", "-s", "a string", "-m", "\"alpha\",\"beta\",\"gamma\"" };
       
final ITestOptions cfg = ConfigUtils.parseCommandLine(args, ITestOptions.class);
        assertEquals
(12, cfg.getA());
        assertEquals
(23, cfg.getB());
        assertEquals
(3.14159, cfg.getD());
        assertEquals
("a string", cfg.getS());
        assertEquals
(true, cfg.getX());
        assertArrayEquals
(new String[] { "alpha", "beta", "gamma" }, cfg.getM());

Well, it is not at all that difficult as it seems.
I'll show this in the next few posts.

No comments:

Post a Comment