Module Kwapp

module Kwapp: sig .. end

Building a command-line application

Major modules:

  1. Kwapp.Valid: Validators for options and arguments.
  2. Kwapp.Option: Defining command-line options (switches).
  3. Kwapp.Argv: Defining command-line arguments.
  4. Kwapp.Env: Defining environment variables.
  5. Kwapp.Version: Defining and displaying version information.
  6. Kwapp.Help: Displaying help messages.
  7. Kwapp.Messages: Defining verbose, warning, and error messages.

See the Tutorial below.
Author(s): Keith Waclena


module Valid: Kwvalid
Validators

Exceptions

Exceptions raised by this module or any of its sub-modules.

See Kwapp.Messages.hdl for a top-level exception handler that converts all of these exceptions into fatal errors with reasonable error messages.

Programmer Errors

Exceptions raised when the programmer uses the module incorrectly.

For example, if you ask for the Kwapp.value of switch "-x", but have never defined a switch "-x", then the Kwapp.Undefined exception will be raised. Kwapp.Messages.hdl converts these exceptions into embarassing fatal "DRYROT" errors.

exception Nameless
Programmer defined a nameless switch.
exception BadSwitch of string * string
Programmer defined a bad switch. The first string is the switch name and the second is an explanation of the problem.
exception Dupe of string * string
Programmer defined a duplicated switch or argument name. The first string is the name, and the second is either "switch" or "arg".
exception Undefined of string
Programmer requested (from Kwapp.value) a string value for an undefined switch. The string is the switch name.
exception Noarg of string
Programmer requested (from Kwapp.value) a string value for a Boolean switch. The string is the switch name.
exception ReqAfter of string
Programmer defined a require command-line argument after an optional one.
exception BadArgv of string
Programmer requested a command-line argument by name that was never defined. The string is the name used.

User Errors

These exceptions are raised when the user invokes the program incorrectly. They are all caught by Kwapp.Messages.hdl, so if you wrap that around your main function, you will get a clean termination of your program with a nice error message. However, you may want to catch some of these manually in some cases.
exception Unknown of string
An unknown switch was found on the command line. The string is the switch name.
exception Arg of string
A switch that requires an argument was found on the command line without one. The string is the switch name.
exception Missing of string list
Required switches were not found on the command line. The string's are the required switch names.
exception Invalid of string * string * string * string
A parameter or switch's argument failed validation. The first string is the sort of thing that was invalid (probably either "switch" or "argument"), the second is the thing's name, the third is the expected "type" of the thing, and the fourth is the given bad value.
exception Mutual of string list list
Mutually exclusive options were given on the command line. Each string list is a class of options corresponding to the mex attribute of the switch.
exception TooMany of string
The option is not repeatable, but more than one was found on the command line.
exception WrongNumber of int
The wrong number of arguments were given on the command line. Negative int n means n too few were given; positive n means n too many.
exception NoArgv of string
A requested command-line argument was not provided.
exception NoAction of string list
Kwapp.dispatch invoked with no default and no dispatch switch or subcommand on command line

The parameter is a list of dispatchable switches and subcommands.

exception NYI of string * string option
An option that is not yet implemented was requested.

The first parameter is the option, the second some explanation.

module Parsedopt: sig .. end
Parsed options returned by Kwapp.getopt are parsedopts.
type parsedopts = string list Parsedopt.t 
The type of parsed options. Each option given on the command line (and all its synonyms) is a key in the Parsedopt map. Each key is mapped to a string option representing the value of the option's argument (if any).

Command Line Option Processing


module Option: sig .. end
Command Line Option Processing

Command-line Argument Definitions


module Argv: sig .. end
Command-line Argument Definitions

Environment Variables


module Env: sig .. end
Environment Variables

Interfaces and Parsing Command Lines



The type of application interfaces: command-line options, command-line arguments, and environment variables.
type interface = {
   opts : Option.switchset;
   argv : Argv.argv;
   envs : Env.env list;
}
val empty : interface
The empty interface.
val unmash : ?unmash_gnu:bool -> string list -> string list
unmash cmd line switches eg -abc becomes -a -b -c

E.g., ["-z";"foo";"-abc";"-x";"bar";"baz"] becomes ["-z";"foo";"-a";"-b";"-c";"-x";"bar";"baz"].
Returns list of unmashed switches

unmash_gnu : unmash GNU --style args too (default: false)
val ungnu : string list -> string list
ungnu cmd line switches eg ["--abc=12"] becomes ["--abc"; "12"]
Returns list of ungnu'd switches eg ["-z"; "--abc"; "69"; "--123"; "-x"]
switches : list of switches eg ["-z"; "--abc=69"; "--123"; "-x"]
val argvlist : unit -> string list
Return Sys.argv as a list, less Sys.argv.(0)
val getopt : ?opt:string list Parsedopt.t ->
?endopts:string option ->
interface -> string list -> parsedopts * string list
getopt ?opt interface argv: parse command line options in argv as per interface, extract command-line arguments, and return both.

Also checks the interface for programmer errors.

Typical usage is something like:

Kwapp.(argvlist () |> unmash |> ungnu |> getopt interface)

Raises
opt : initial parsed options (default: Parsedopt.empty)
endopts : option that ends options, if any (default: Some "--")
interface : option definitions

Testing and Extracting Command-line Options and Their Values


val has : string -> parsedopts -> bool
has sw m: return true if getopt-parsed map m has switch sw.
val value : ?def:string ->
?interface:interface -> string -> parsedopts -> string
value ?def ?interface sw m: return value of switch sw from the parsed options m or, if not given on command line, its default from interface.
Raises
def : default value for a switch not given on the command line, overriding any default in the interface
interface : the interface
val values : ?def:string list ->
?interface:interface -> string -> parsedopts -> string list
values ?def ?interface sw m: return all values of switch sw from the parsed options m or, if not given on command line, its default from interface.
Raises
def : default values for a switch not given on the command line, overriding any default in the interface
interface : the interface
val argument : ?def:string -> interface -> string -> string list -> string
argument ?def interface name argv: return value of a non-repeating command-line argument named name, as defined in interface, from argv.
Raises
def : default returned for a requested arg that wasn't provided on command line
interface : the interface
argv : the runtime argv, exclusive of options, e.g. as returned by Kwapp.getopt
val arguments : ?def:string list -> interface -> string -> string list -> string list
arguments ?def interface name argv: return value of the repeating command-line argument named name, as defined in interface, from argv, as a list.
Raises
def : default returned if the repeating arg wasn't provided on command line
interface : the interface
argv : the runtime argv, exclusive of options, e.g. as returned by Kwapp.getopt

Dispatching


type dispatchmode = 
| Switch of string
| Sub of string * interface option
| Default
The type of dispatch modes.

The Kwapp.dispatch function allows you to dispatch to an action based on either a command-line option (Switch) or a subcommand (Sub).

type ('a, 'b) action = 'a ->
interface option ->
interface -> dispatchmode -> parsedopts * string list -> 'b
The type of dispatchable actions.

Actions are functions that take:

  1. arbitrary data that can be computed by main (e.g. configuration data)
  2. an Kwapp.interface option, designating a subcommand interface specific to an action
  3. the global Kwapp.interface of the app
  4. a Kwapp.dispatch, the switch or subcommand that invoked the action
  5. a pair of (parsedopt * parsed argv), as returned by Kwapp.getopt

type ('a, 'b) dispatch = dispatchmode * ('a, 'b) action 
The type of dispatch-pairs.

Each dispatch-pair combines a mode and an action.

val dispatch : ?def:('a ->
'b option ->
interface ->
dispatchmode -> parsedopts * string list -> 'c) ->
'a ->
interface ->
(dispatchmode *
('a ->
interface option ->
interface ->
dispatchmode -> parsedopts * string list -> 'c))
list -> parsedopts * string list -> 'c
dispatch ?def ?data interface actions (m,argv): execute default function def unless one of the actions is requested, passing data to the action.

Actions are typically meta-functions of the application, e.g. help, version information, etc. Can be used to select amongst disjoint subcommands via distinguishing option or arg.
Raises

def : default action invoked if no matches in actions
data : arbitrary data
actions : list of dispatchable action's
(m,argv) : argv : parsed command line
m : parsed options

Action Combinators

If you write an action a, you can wrap it with one or both of these combinators to perform appropriate option and argv checks; e.g.

    with_check_global (with_check_sub a)

val with_check_global : ('a -> 'b -> interface -> 'c -> parsedopts * string list -> 'd) ->
'a -> 'b -> interface -> 'c -> parsedopts * string list -> 'd
with_check_global f interface global disp (m,argv): add a global option check to an action.

If you have an action a, then with_check_global a is that action preceded by a global option check, equivalent to starting your action with Option.check global.opts (m,argv).
Raises

f : the action
data : arbitrary data
interface : the dispatch-level interface
global : the global interface
disp : the dispatch mode
(m,argv) : argv : actual argv, typically from Kwapp.getopt
m : parsed options, typically from Kwapp.getopt
val with_check_sub : ('a ->
interface option ->
interface -> 'b -> parsedopts * string list -> unit) ->
'a ->
interface option ->
interface -> 'b -> parsedopts * string list -> unit
with_check_sub f interface global disp (m,argv): add a subcommand option and argv check to an action.

If you have an action a, then with_check_sub a is that action preceded by a subcommand option and argv check, equivalent to starting your action with:

    Option.check interface.opts (m,argv) |> ignore;
    Argv.check interface.argv (m,argv)]

Raises
f : the action
data : arbitrary data
interface : the dispatch-level interface
global : the global interface
disp : the dispatch mode
(m,argv) : argv : actual argv, typically from Kwapp.getopt
m : parsed options, typically from Kwapp.getopt

Version Information


module Version: sig .. end
Version Information

Help and Usage Messages


module Help: sig .. end
Help and Usage Messages

Messages

Functions for printing simple messages from command-line applications.

module type MYSELF = sig .. end
The type of program names for messages.
module type VERBOSITY = sig .. end
The type of verbosity state for messages.

Predefined MYSELF modules.


module Argv0: sig .. end
Get the program name from Sys.argv.(0).
module Anonymous: sig .. end
The program name is null, and thus never printed by the Kwapp.Messages functions.

Predefined VERBOSITY modules.

The verbosity level of your program is a global value and can be either mutable or immutable. An immutable VERBOSITY module raises a Failure exception if you call its set function.

module Ref: 
functor (R : sig
val r : int Pervasives.ref
end) -> sig .. end
VERBOSITY via a global ref.
module Environment: 
functor (E : sig
val var : string
end) -> sig .. end
VERBOSITY via an environment variable read when the program starts.
module Quiet: sig .. end
VERBOSITY is always 0.
module Verbose: sig .. end
VERBOSITY is always 1.
module type MESSAGES = sig .. end
The Messages functor.
module Messages: 
functor (M : MYSELF) ->
functor (V : VERBOSITY) -> sig .. end

Tutorial

      type opts = { c : int; m : string; z : bool }
      let _ = {
        x = value "-x" m |> int_of_string;
        y = value "-y" m |> String.uppercase;
        z = has   "-z" m;
      }