Core.Command
(and the closely-related Async.Command
) is an OCaml library for creating command line programs with nice interfaces (including help text and argument parsing). This article is an overview of Command.Param
, the newer interface for defining your command's arguments (replacing Command.Spec
).
This article is not exhaustive. For more information, refer to the official documentation:
Basic Param.t
functions
Command.Param
implements an applicative functor, which is just a monad with a both
function instead of a bind
function. The most important functions are:
return
takes any value and turns it into aCommand.Param.t
both
takes two params and turns them into one parammap
takes a param and a function that takes the param's value and returns a new value, returning a newCommand.Param.t
containing the function's return value-
anon
creates a param whose value comes an anonymous (or positional) argument.A basic
string
anonymous argument would be defined like:ocaml Command.(anon ("name_for_docs" %: string))
See
Command.Anons
for details. -
flag
creates a param whose value comes from a-
or--
named flag argument.A basic boolean flag would be defined like:
ocaml Command.(flag ~doc:"NAME_FOR_DOCS help text goes here" "--example" no_arg)
See
Command.Flag
for details.
Commands with no arguments
Command.basic
expects a (unit -> unit) Param.t
, so in the simplest case, you can use return
to wrap a unit -> unit
function:
open Core
let () =
Command.basic
~summary:"example command with no arguments"
(Command.Param.return (fun () ->
print_endline "running example"))
|> Command.run
Commands with one argument
A simple command taking one argument would use either flag
or anon
and then map
that param to a function (presumably using the value of the param in the function).
For example:
let () =
Command.basic
~summary:"example with one argument"
Command.Param.(
anon ("positional_arg" %: int)
|> map ~f:(fun positional_arg ->
fun () ->
printf "positional_arg is %d\n" positional_arg))
|> Command.run
Core's documentation recommends using ppx_let, which would look like this:
let () =
Command.basic
~summary:"example with one argument"
Command.Param.(
let%map.Command positional_arg = anon ("positional_arg" %: int) in
fun () ->
printf "positional_arg is %d\n" positional_arg)
|> Command.run
The recommended syntax goes one step further and uses [%map_open]
(also from ppx_let), which automatically puts the various helper functions in Command
into scope on the right hand side of your argument definitions (note how we don't need the local-open of Command.Param.(...)
anymore):
let () =
Command.basic
~summary:"example with one argument"
[%map_open.Command
let positional_arg = anon ("positional_arg" %: int) in
fun () ->
printf "positional_arg is %d\n" positional_arg]
|> Command.run
Commands with multiple arguments
To extend the above to multiple arguments, you just need to use ppx_let's and
syntax (which internally uses both
) to merge two params into one, then map
from that param to a unit -> unit
function like usual.
let () =
Command.basic
~summary:"two argument example"
[%map_open.Command
let optional = flag ~doc:"OPTIONAL an optional flag" "-o" no_arg
and positional = anon ("positional_arg" %: string) in
fun () ->
printf
"optional arg is %s and positional arg is %s\n"
(Bool.to_string optional)
positional]
|> Command.run
Without ppx_let
This code quickly becomes unreadable without ppx_let, but here's the same example without it in case that's helpful for understanding:
let () =
Command.basic
~summary:"two argument example"
Command.Param.(
both
(flag ~doc:"OPTIONAL an optional flag" "-o" no_arg)
(anon ("positional_arg" %: string))
|> map ~f:(fun (optional, positional) () ->
printf
"optional arg is %s and positional arg is %s\n"
(Bool.to_string optional)
positional))
|> Command.run
Commands with more arguments
To extend this to any number of arguments, just keeping adding and
's:
let () =
Command.basic
~summary:"two argument example"
[%map_open.Command
let first = anon ("first" %: string)
and second = anon ("second" %: string)
and third = anon ("third" %: string)
and fourth = anon ("fourth" %: string) in
fun () ->
printf "args are %s %s %s %s\n" first second third fourth]
|> Command.run