# Module Command.Spec

    module Spec: sig .. end

# older interface for command-line specifications

# command parameters

    type 'a param = 'a Command.Param.t

specification of an individual parameter to the command's main function

    include Command.Param.S

    val const : 'a -> 'a param

Superceded by `return`, preserved for backwards compatibility

    val pair : 'a param ->
           'b param -> ('a * 'b) param

Superceded by `both`, preserved for backwards compatibility

# command specifications

    type ('main_in, 'main_out) t

composable command-line specifications

Ultimately one forms a basic command by combining a spec of type `('main, unit -> unit) t` with a main function of type `'main`; see the `basic` function below. Combinators in this library incrementally build up the type of main according to what command-line parameters it expects, so the resulting type of `main` is something like:

`arg1 -> ... -> argN -> unit -> unit`

It may help to think of `('a, 'b) t` as a function space `'a -> 'b` embellished with information about:

- how to parse command line
- what the command does and how to call it
- how to auto-complete a partial command line

One can view a value of type `('main_in, 'main_out) t` as function that transforms a main function from type `'main_in` to `'main_out`, typically by supplying some arguments. E.g. a value of type `Spec.t` might have type:

            (arg1 -> ... -> argN -> 'r, 'r) Spec.t

Such a value can transform a main function of type `arg1 -> ... -> argN -> 'r` by supplying it argument values of type `arg1`, ..., `argn`, leaving a main function whose type is `'r`. In the end, `Command.basic` takes a completed spec where `'r = unit -> unit`, and hence whose type looks like:

            (arg1 -> ... -> argN -> unit -> unit, unit -> unit) Spec.t

A value of this type can fully apply a main function of type `arg1 -> ... -> argN -> unit -> unit` to all its arguments.

The final unit argument allows the implementation to distinguish between the phases of (1) parsing the command line and (2) running the body of the command. Exceptions raised in phase (1) lead to a help message being displayed alongside the exception. Exceptions raised in phase (2) are displayed without any command line help.

The view of `('main_in, main_out) Spec.t` as a function from `'main_in` to `'main_out` is directly reflected by the `step` function, whose type is:

            val step : ('m1 -> 'm2) -> ('m1, 'm2) t

`spec1 ++ spec2 ++ ... ++ specN` composes spec1 through specN.

For example, if `spec_a` and `spec_b` have types:

            spec_a: (a1 -> ... -> aN -> 'ra, 'ra) Spec.t
            spec_b: (b1 -> ... -> bM -> 'rb, 'rb) Spec.t

then `spec_a ++ spec_b` has the following type:

            (a1 -> ... -> aN -> b1 -> ... -> bM -> 'rb, 'rb) Spec.t

So, `spec_a ++ spec_b` transforms a main function it by first supplying `spec_a`'s arguments of type `a1`, ..., `aN`, and then supplying `spec_b`'s arguments of type `b1`, ..., `bm`.

One can understand `++` as function composition by thinking of the type of specs as concrete function types, representing the transformation of a main function:

            spec_a: \/ra. (a1 -> ... -> aN -> 'ra) -> 'ra
            spec_b: \/rb. (b1 -> ... -> bM -> 'rb) -> 'rb

Under this interpretation, the composition of `spec_a` and `spec_b` has type:

            spec_a ++ spec_b : \/rc. (a1 -> ... -> aN -> b1 -> ... -> bM -> 'rc) -> 'rc

And the implementation is just function composition:

            sa ++ sb = fun main -> sb (sa main)

    val empty : ('m, 'm) t

the empty command-line spec

    val (++) : ('m1, 'm2) t ->
           ('m2, 'm3) t -> ('m1, 'm3) t

command-line spec composition

    val (+>) : ('m1, 'a -> 'm2) t ->
           'a param -> ('m1, 'm2) t

add a rightmost parameter onto the type of main

    val (+<) : ('m1, 'm2) t ->
           'a param -> ('a -> 'm1, 'm2) t

add a leftmost parameter onto the type of main

this function should only be used as a workaround in situations where the order of composition is at odds with the order of anonymous arguments due to factoring out some common spec

    val step : ('m1 -> 'm2) -> ('m1, 'm2) t

combinator for patching up how parameters are obtained or presented

Here are a couple examples of some of its many uses

- introducing labeled arguments

      step (fun m v -> m ~foo:v)
                     +> flag "-foo" no_arg : (foo:bool -> 'm, 'm) t

- prompting for missing values

      step (fun m user -> match user with
                       | Some user -> m user
                       | None -> print_string "enter username: "; m (read_line ()))
                     +> flag "-user" (optional string) ~doc:"USER to frobnicate"
                     : (string -> 'm, 'm) t

A use of `step` might look something like:

            step (fun main -> let ... in main x1 ... xN) : (arg1 -> ... -> argN -> 'r, 'r) t

Thus, `step` allows one to write arbitrary code to decide how to transform a main function. As a simple example:

            step (fun main -> main 13.) : (float -> 'r, 'r) t

This spec is identical to `const 13.`; it transforms a main function by supplying it with a single float argument, `13.`. As another example:

            step (fun m v -> m ~foo:v) : (foo:'foo -> 'r, 'foo -> 'r) t

This spec transforms a main function that requires a labeled argument into a main function that requires the argument unlabeled, making it easily composable with other spec combinators.

    val wrap : (run:('m1 -> 'r1) -> main:'m2 -> 'r2) ->
           ('m1, 'r1) t -> ('m2, 'r2) t

combinator for defining a class of commands with common behavior

Here are two examples of command classes defined using `wrap`

- print top-level exceptions to stderr

      wrap (fun ~run ~main ->
                       Exn.handle_uncaught ~exit:true (fun () -> run main)
                     ) : ('m, unit) t -> ('m, unit) t

- iterate over lines from stdin

      wrap (fun ~run ~main ->
                       In_channel.iter_lines stdin ~f:(fun line -> run (main line))
                     ) : ('m, unit) t -> (string -> 'm, unit) t

    val of_params : ('a, 'b) Command.Param.Args.t -> ('a, 'b) t

    module Arg_type: module type of Arg_type  with type 'a t = 'a Arg_type.t

    include Command.Spec.Arg_type.Export

    type 'a flag = 'a Command.Flag.t

a flag specification

    include Command.Flag

    val map_flag : 'a flag -> f:('a -> 'b) -> 'b flag

`map_flag flag ~f` transforms the parsed result of `flag` by applying `f`

    val flags_of_args_exn : Core_kernel.Std.Arg.t list -> ('a, 'a) t

`flags_of_args_exn args` creates a spec from `Caml.Arg.t`s, for compatibility with ocaml's base libraries. Fails if it encounters an arg that cannot be converted.

NOTE: There is a difference in side effect ordering between `Caml.Arg` and `Command`. In the `Arg` module, flag handling functions embedded in `Caml.Arg.t` values will be run in the order that flags are passed on the command line. In the `Command` module, using `flags_of_args_exn flags`, they are evaluated in the order that the `Caml.Arg.t` values appear in `flags`.

    type 'a anons = 'a Command.Anons.t

a specification of some number of anonymous arguments

    include Command.Anons

    val map_anons : 'a anons -> f:('a -> 'b) -> 'b anons

`map_anons anons ~f` transforms the parsed result of `anons` by applying `f`