in reply to deriving usage from Getopts::Long

What I've done, and I really need to find a way to get it opened, is write my very own wrapper around GetOpt::Long. What it does is multi-step:

  1. It accepts parameters from the rest of the code - these parameters do not need to be passed in all at once, but the "accept parameter" function can be called multiple times. This allows me to load all my modules, and each module can register what options it wants to accept with the global wrapper.
  2. It then takes the parameters, puts them together in a way that GetOpt::Long will like, and calls GetOpt::Long to do the actual option parsing.
  3. It then calls any call-backs that were initially registered for extra validation. Sure, you can tell GetOpt that you want an integer. But this allows you to put in a CODE ref that then checks that the value is really between 1 and 12, for example, if you're validating months. The parameter is also passed in such that if the validation assigns back to $_[0], it changes the value which is useful when you want to be able to have a parameter that is something like --smtp_server AUTO and let the validation code figure out the automatic value. (Not that I have any idea how to do that for an smtp server, but maybe you do have such an idea.)
  4. It then checks if the -? or --help parm was passed in. If so, it generates the help based on what was given to it. It also will print out the default values as it knows them, prints out all the variations (e.g., a parameter of 'v|verbose!' would have -v, --verbose, --noverbose as valid options - this would automatically be part of the help), and then exits.
The parameters are just a list of hashes which have keys for name, default, validate, help, and maybe others I don't recall. Except for name, the rest can be code refs or strings.

This setup has saved us countless weeks of development time over the last 4 years or so. I am positive that it has saved us multiple weeks of development time just in the last 6 months.

Replies are listed 'Best First'.
Re^2: deriving usage from Getopts::Long
by QM (Parson) on Jul 29, 2005 at 18:53 UTC
    What you describe is easily done with Getopt::Declare. I haven't had the multiple module situation, so I haven't had to use an "accept parameter" function, but that could easily be done.

    The parameter description is just a string passed to G::D. The string can be built up piecemeal by modules as they load (or perhaps each module adds a key to a hash, and after all modules are loaded, the hash is processed into a string).

    The code callbacks are called "actions" in the G::D documentation. Parameter checking syntax, either by fundamental type (e.g., integer), regex, or code block, is already provided.

    Perhaps I should develop a helper module for G::D to do what you suggest?

    -QM
    --
    Quantum Mechanics: The dreams stuff is made of

      I actually doubt it would be that easy to do with Getopt::Declare. The reason is that the actions are done in the caller's namespace - and G::D is not going to know which namespace is which. Worse, it looks like these actions will affect only package variables. They aren't proper closures, and I need closures to affect the proper private variables. I'm sure it could still be faked somehow, but it would not be the straight-forward method you may think it is.

      Besides, once you have a wrapper, it really doesn't matter which one it wraps, as long as the caller(s) don't need to change. ;-)

      (Also, it's imperative for my app, anyway, that all parms are parsed in a certain order, irrespective of the order on the commandline, which is also contrary to G::D's method. So my wrapper just gets G::L to parse the whole thing, and then we validate in order.)