I've had a little look into implementing Commands as I described but wasn't sure how
I'd get them in without adding spaghetti to the
code. While looking around I was reminded of a few things that feel slightly wrong
and began to wonder whether the model might be
wrong. I'll outline the problems and then a solution below that seems pretty clean to
me. The pure text UML could be prettier but
I think you'll get the idea if you use a fixed size font. (I hope you don't regret the
"bouncing the ideas around" comment too much
John :o) )
OptionImpl vs. CommandImpl. Although these two types of object share the common
feature of appearing on a command line and having a
group of child options, I'm not convinced that one is an extension of the other. As a
result I've struggled to fit Command into the
hierarchy.
Option vs. Argument. It might be just me but in the command "ant -f file" I've always
regarded it as an option -f with an argument
file, whereas the current model would have an argument "-f file". This has caused me
occasional confusion and it seems that it
would sit easier if Argument were able to deal purely with the "file" section and not
have to deal with the option's properties. If
the Argument were able to drop the option properties then it might also be possible to
mix Arguments and Commands together.
AnonymousArgument and UnsupportedMethodException. Again it might be a personal thing
but I've always thought of UME as being a bit
of a code smell - to me it says "the object isn't really a subtype of the specifying
class but we've put it here anyway, so there".
I think this strengthens the case against Argument implementing Option.
CommandLineParser knows an awful lot. I've commented before that the internal
handling of -D and -- should be optional but the
knowledge of how all the other options behave seems to be encoded in this class too.
There's nothing inherently wrong with that but
it left me thinking it odd that the Option implementations didn't control the
behaviour themselves. It also struck me that the same
would be true of any HelpFormatter built for the current model.
Without boring you with the route my thoughts took, here's the model I came to with a
bit of explanation afterwards.
Class Diagram (Inheritance):
Option <-----------+-- Options <---------------+-- ExclusiveOptions
getDescription() | parse(...) |
isRequired() | +-- InclusiveOptions
appendUsage(...) |
validate(...) +-- ParentOption <----------+-- DefaultOption
process(...) | processParent(...) |
canProcess(...) | processChildren(...) +-- CommandOption
getPrefixes() |
+-- Argument
|
+-- PropertyOption
| getInstance()
|
+-- IgnoreOption
getInstance()
Class Diagram (Composition):
Argument --------1 ParentOption --------1 Options --------* Option
The first thing to note is that I've separated out the Option interface from the
DefaultOption class. The Option interface has lost
most of its structure enforcing role and gained behaviour specifying instead. Some
new OptionBuilder would build DefaultOption
instances with all the longName / shortName and other properties of the current
OptionImpl class. Similarly a CommandBuilder would
allow CommandOption instances to be built up with preferredName / aliases properties.
Another important point is that Argument is no longer directly related to the
DefaultOption. Instead it is composed of either a
DefaultOption or CommandOption and concentrates purely on the details of the argument.
Options just becomes a generic object for storing a set of options, the Exclusive /
Inclusive just specify more restrictive
behaviour as they do presently.
The idea of PropertyOption (-D) and IgnoreOption (--) just dropped out of the
structure and means that this standard behaviour can
be treated as any other option and if people have their own plan for a -D option then
they simply don't put a PropertyOption
instance in their Options.
After a little experimentation the sensible methods for Option to specify seem to be
the following:
getDescription() - used to allow a HelpFormatter to describe any given Option.
appendUsage(...) - allow the option itself to append a usage string to a StringBuffer
validate(...) - validates a CommandLine's use of this Option
isRequired() - presumably used by validate() and appendUsage()
process(...) - takes a ListIterator of arguments and deals with some/all of them.
canProcess(...) - checks that a call to process(...) will succeed.
getPrefixes() - returns the argument prefixes that could indicate this Option can
process a given argument.
One of the nice things about this structure is that when somebody wants to extend the
system to cope with windows style "/?"
options, or case insensitive commands, they should only need to add a single Option
implementation and any Parser and Formatter will
automatically cope.
I've not yet figured out whether a separate AnonymousArgument is needed or if an
Argument could exist without a ParentOption but I'm
sure that the UnsupportedMethodException methods would be gone completely whichever
route was taken.
So, thoughts? I'm happy to answer questions and help with implementation as time
permits but I'll be on holiday from Friday for 10
days so will be offline for a while.
Rob
----- Original Message -----
From: "John Keyes" <[EMAIL PROTECTED]>
To: "Jakarta Commons Developers List" <[EMAIL PROTECTED]>
Sent: Thursday, June 12, 2003 10:18 AM
Subject: Re: [CLI] Support for CVS style command line
> > The "setDisplayCommandAlias(boolean)" is purely hypothetical at the moment, it
> > illustrates
> > the level of control I was planning on offering but is beyond the implementation
> > so far.
> > I haven't tackled Commands and aliases at all but I guess should put my code
> > where my mouth is. I'll keep you posted on progress.
> Keep bouncing the ideas around anyway. If you don't get around to implementing it
> at least the knowledge will be archived.
>
> Thanks,
> -John K
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
>
>
>
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]