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:
returntakes any value and turns it into aCommand.Param.tbothtakes two params and turns them into one parammaptakes a param and a function that takes the param's value and returns a new value, returning a newCommand.Param.tcontaining the function's return valueanoncreates a param whose value comes an anonymous (or positional) argument.A basic
stringanonymous argument would be defined like:ocaml Command.(anon ("name_for_docs" %: string))See
Command.Anonsfor details.flagcreates 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.Flagfor 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