Thursday, October 15, 2009

Parsing command-line options - part 2

To set off with the further activities I have to capture the list of requirements first. This list will let me grasp the overall scope of work and possibly start with a set of unit-tests. Option processing should meet the following requirements:
  • opion can be mandatory meaning its value must always be specified in the command line;
  • option value type can be
    1. java.lang.String, or
    2. a Java primitive type:
      TypeDefault value
      booleanfalse
      byte0x00
      charCharacter.MIN_VALUE
      short0x0000
      int0
      long0L
      floatFloat.NaN
      doubleDouble.NaN
      , or
    3. a non-primitive Java wrapper for a primitive type : java.lang.Boolean, java.lang.Integer, java.lang.Double, etc; in this case default value would be null, or
    4. a Java array of a type from one of the categories defined above;
  • a boolean option has no argument; it is either present in the command line or not.
    any other type requires an argument in a form of non-whitespace character sequence;
    an argument of array type is a sequence of tokens separated by comma with no whitespace characters;
  • options must be recognized by either short one-letter code (POSIX style) or the long tag (GNU style). Example:
    (from gawk man page)
         -F fs                <- POSIX-style tag
         --field-separator=fs <- GNU-style tag
    
  • each option should be provided with a brief textual description to include into the usage information;
  • option expecting a value must have a short textual tag to denote the argument in the usage information output. In the example below it is the 'SIZE' word:
    (from man ls page):
    --block-size=SIZE
          use SIZE-byte blocks
    
  • the order in which options are enumerated by the application should be user-defined;
  • free list of command line arguments following the options should also be accessible from the same facility;
Lets capture these requirements in a Java annotation we want to mark our interface with:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Option {
   
boolean required() default false;
   
int id() default 0;
    String longOpt
() default StringUtils.EMPTY;
   
char opt();
    String description
() default StringUtils.EMPTY;
    String argumentTag
() default StringUtils.EMPTY;
    String defaultValue
() default StringUtils.EMPTY;
   
interface IUserArgumentSupport
   
{
       
String[] getUserArguments();
   
}
}

The required property indicates a mandatory option which must be specified in the command line.
The id property is auxiliary and can be used to indicate preferable ordering of options if all of them are to be returned as a list.
The longOpt property specifies the long form of the command line tag for the option, while the opt property is used for the short form.
The description property provides a textual explanation of the option which is typically included into the usage information.
The argumentTag property specifies, if applicable, a short textual identificator for the option argument which is also used as part of usage information.
The defaultValue property provides value for a non-required option which should be applied when no argument is given in the command line. This property will leave to us the choice of providing a particular value for a non-required option. Notice that the property type is String as we don't know beforehand the property type of the option. This approach is convenient but requires ablility to convert a string value into a value of a specific Java type.
The IUserArgumentSupport interface, if extended, would let us retrieve any extra arguments trailing the command-line after the options.

No comments:

Post a Comment