Module Command.Spec
Command parameters
type 'a param
= 'a Core__Core_command.Param.t
Specification of an individual parameter to the command's main function.
include Core__Core_command.Param.S with type 'a t := 'a Core__Core_command.Param.t
Command.Param
is intended to be used with the [%map_open]
syntax defined in ppx_let
, like so:
let command =
Command.basic ~summary:"..."
[%map_open
let count = anon ("COUNT" %: int)
and port = flag "port" (optional int) ~doc:"N listen on this port"
and person = person_param
in
(* ... Command-line validation code, if any, goes here ... *)
fun () ->
(* The body of the command *)
do_stuff count port person
]
One can also use [%map_open]
to define composite command line parameters, like person_param
in the previous snippet:
type person = { name : string; age : int }
let person_param : person Command.Param.t =
[%map_open
let name = flag "name" (required string) ~doc:"X name of the person"
and age = flag "age" (required int) ~doc:"N how many years old"
in
{name; age}
]
The right-hand sides of [%map_open]
definitions have Command.Param
in scope.
Alternatively, you can say:
let open Foo.Let_syntax in
[%map_open
let x ...
]
if Foo
follows the same conventions as Command.Param
.
See example/command/main.ml for more examples.
include Core_kernel__.Import.Applicative.S with type 'a t := 'a t
val apply : ('a -> 'b) t -> 'a t -> 'b t
val map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t
val map3 : 'a t -> 'b t -> 'c t -> f:('a -> 'b -> 'c -> 'd) -> 'd t
val all : 'a t list -> 'a list t
val all_unit : unit t list -> unit t
module Applicative_infix : Base__.Applicative_intf.Applicative_infix with type 'a t := 'a t
Various internal values
val help : Core_kernel__.Import.string Core_kernel.Lazy.t t
The help text for the command.
val path : Core_kernel__.Import.string Core_kernel__.Import.list t
The subcommand path of the command.
val args : Core_kernel__.Import.string Core_kernel__.Import.list t
The arguments passed to the command.
val flag : ?aliases:Core_kernel__.Import.string Core_kernel__.Import.list -> ?full_flag_required:Core_kernel__.Import.unit -> Core_kernel__.Import.string -> 'a Core__Core_command.Flag.t -> doc:Core_kernel__.Import.string -> 'a t
flag name spec ~doc
specifies a command that, among other things, takes a flag namedname
on its command line.doc
indicates the meaning of the flag.All flags must have a dash at the beginning of the name. If
name
is not prefixed by "-", it will be normalized to"-" ^ name
.Unless
full_flag_required
is used, one doesn't have to passname
exactly on the command line, but only an unambiguous prefix ofname
(i.e., a prefix which is not a prefix of any other flag's name).NOTE: the
doc
for a flag which takes an argument should be of the formarg_name ^ " " ^ description
wherearg_name
describes the argument anddescription
describes the meaning of the flag.NOTE: flag names (including aliases) containing underscores will be rejected. Use dashes instead.
NOTE: "-" by itself is an invalid flag name and will be rejected.
val flag_optional_with_default_doc : ?aliases:Core_kernel__.Import.string Core_kernel__.Import.list -> ?full_flag_required:Core_kernel__.Import.unit -> Core_kernel__.Import.string -> 'a Core__Core_command.Arg_type.t -> ('a -> Core_kernel.Sexp.t) -> default:'a -> doc:Core_kernel__.Import.string -> 'a t
flag_optional_with_default_doc name arg_type sexp_of_default ~default ~doc
is a shortcut forflag
, where:- The
Flag.t
isoptional_with_default default arg_type
- The
doc
is passed through with an explanation of what the default value appended.
- The
val anon : 'a Core__Core_command.Anons.t -> 'a t
anon spec
specifies a command that, among other things, takes the anonymous arguments specified byspec
.
module If_nothing_chosen : sig ... end
val choose_one : 'a Core_kernel__.Import.option t Core_kernel__.Import.list -> if_nothing_chosen:('a, 'b) If_nothing_chosen.t -> 'b t
choose_one clauses ~if_nothing_chosen
expresses a sum type. It raises if more than one ofclauses
isSome _
. Whenif_nothing_chosen = `Raise
, it also raises if none ofclauses
isSome _
.
val and_arg_names : 'a t -> ('a * Core_kernel__.Import.string Core_kernel__.Import.list) t
and_arg_names t
returns both the value oft
and the names of the arguments that went intot
. Useful for errors that reference multiple params.
val and_arg_name : 'a t -> ('a * Core_kernel__.Import.string) t
Like
and_arg_names
, but asserts that there is exactly one name.
val const : 'a -> 'a Core__Core_command.Param.t
Superceded by
return
, preserved for backwards compatibility.
val pair : 'a Core__Core_command.Param.t -> 'b Core__Core_command.Param.t -> ('a * 'b) Core__Core_command.Param.t
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 thebasic
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 ofmain
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 the command line
- what the command does and how to call it
- how to autocomplete a partial command line
One can view a value of type
('main_in, 'main_out) t
as a function that transforms a main function from type'main_in
to'main_out
, typically by supplying some arguments. E.g., a value of typeSpec.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 typearg1
, ...,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 thestep
function, whose type is:val step : ('m1 -> 'm2) -> ('m1, 'm2) t
val empty : ('m, 'm) t
The empty command-line spec.
val (+>) : ('m1, 'a -> 'm2) t -> 'a Core__Core_command.Param.t -> ('m1, 'm2) t
Adds a rightmost parameter onto the type of main.
val (+<) : ('m1, 'm2) t -> 'a Core__Core_command.Param.t -> ('a -> 'm1, 'm2) t
Adds 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 because you're 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
module Arg_type : module type of Core__Core_command.Arg_type with type 'a Arg_type.t = 'a Core__Core_command.Arg_type.t
include module type of Arg_type.Export
val string : Core_kernel__.Import.string Arg_type.t
val int : Core_kernel__.Import.int Arg_type.t
Beware that an anonymous argument of type
int
cannot be specified as negative, as it is ambiguous whether -1 is a negative number or a flag. (The same applies tofloat
,time_span
, etc.) You can use the special built-in "-anon" flag to force a string starting with a hyphen to be interpreted as an anonymous argument rather than as a flag, or you can just make it a parameter to a flag to avoid the issue.
val char : Core_kernel__.Import.char Arg_type.t
val float : Core_kernel__.Import.float Arg_type.t
val bool : Core_kernel__.Import.bool Arg_type.t
val date : Core_kernel.Date.t Arg_type.t
val percent : Core_kernel.Percent.t Arg_type.t
val host_and_port : Core_kernel.Host_and_port.t Arg_type.t
val sexp : Core_kernel.Sexp.t Arg_type.t
val sexp_conv : (Core_kernel.Sexp.t -> 'a) -> 'a Arg_type.t
type 'a flag
= 'a Core__Core_command.Flag.t
A flag specification.
include module type of Core__Core_command.Flag with type 'a Flag.t := 'a flag
val required : 'a Core__Core_command.Arg_type.t -> 'a t
Required flags must be passed exactly once.
val optional : 'a Core__Core_command.Arg_type.t -> 'a Core_kernel__.Import.option t
Optional flags may be passed at most once.
val optional_with_default : 'a -> 'a Core__Core_command.Arg_type.t -> 'a t
optional_with_default
flags may be passed at most once, and default to a given value.
val listed : 'a Core__Core_command.Arg_type.t -> 'a Core_kernel__.Import.list t
listed
flags may be passed zero or more times.
val one_or_more : 'a Core__Core_command.Arg_type.t -> ('a * 'a Core_kernel__.Import.list) t
one_or_more
flags must be passed one or more times.
val no_arg : Core_kernel__.Import.bool t
no_arg
flags may be passed at most once. The boolean returned is true iff the flag is passed on the command line.
val no_arg_register : key:'a Core_kernel.Univ_map.With_default.Key.t -> value:'a -> Core_kernel__.Import.bool t
no_arg_register ~key ~value
is likeno_arg
, but associatesvalue
withkey
in the autocomplete environment.
val no_arg_some : 'a -> 'a Core_kernel__.Import.option t
no_arg_some value
is likeno_arg
, but will returnSome value
if the flag is passed on the command line, and returnNone
otherwise.
val no_arg_abort : exit:(Core_kernel__.Import.unit -> Core_kernel__.Std_internal.never_returns) -> Core_kernel__.Import.unit t
no_arg_abort ~exit
is likeno_arg
, but aborts command-line parsing by callingexit
. This flag type is useful for "help"-style flags that just print something and exit.
val escape : Core_kernel__.Import.string Core_kernel__.Import.list Core_kernel__.Import.option t
escape
flags may be passed at most once. They cause the command line parser to abort and pass through all remaining command line arguments as the value of the flag.A standard choice of flag name to use with
escape
is"--"
.
val flags_of_args_exn : Core_kernel.Arg.t Core_kernel__.Import.list -> ('a, 'a) t
flags_of_args_exn args
creates a spec fromCaml.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
andCommand
. In theArg
module, flag handling functions embedded inCaml.Arg.t
values will be run in the order that flags are passed on the command line. In theCommand
module, usingflags_of_args_exn flags
, they are evaluated in the order that theCaml.Arg.t
values appear inargs
.
type 'a anons
= 'a Core__Core_command.Anons.t
A specification of some number of anonymous arguments.
include module type of Core__Core_command.Anons with type 'a Anons.t := 'a anons
val (%:) : Core_kernel__.Import.string -> 'a Core__Core_command.Arg_type.t -> 'a t
(name %: typ)
specifies a required anonymous argument of typetyp
.The
name
must not be surrounded by whitespace; if it is, an exn will be raised.If the
name
is surrounded by a special character pair (<>, {}, [] or (),)name
will remain as-is, otherwise,name
will be uppercased.In the situation where
name
is only prefixed or only suffixed by one of the special character pairs, or different pairs are used (e.g., "<ARG]"), an exn will be raised.The (possibly transformed)
name
is mentioned in the generated help for the command.
val sequence : 'a t -> 'a Core_kernel__.Import.list t
sequence anons
specifies a sequence of anonymous arguments. An exception will be raised ifanons
matches anything other than a fixed number of anonymous arguments.
val non_empty_sequence_as_pair : 'a t -> ('a * 'a Core_kernel__.Import.list) t
non_empty_sequence_as_pair anons
andnon_empty_sequence_as_list anons
are likesequence anons
except that an exception will be raised if there is not at least one anonymous argument given.
val non_empty_sequence_as_list : 'a t -> 'a Core_kernel__.Import.list t
val maybe : 'a t -> 'a Core_kernel__.Import.option t
(maybe anons)
indicates that some anonymous arguments are optional.
val to_param : ('a, 'r) t -> 'a -> 'r Core__Core_command.Param.t
val of_param : 'r Core__Core_command.Param.t -> ('r -> 'm, 'm) t