Command Line Subcommands in OCaml
Here’s the translation of the Go code to OCaml, formatted in Markdown suitable for Hugo:
Our program demonstrates how to implement command-line subcommands in OCaml. Each subcommand can have its own set of flags and arguments.
open Cmdliner
let foo_cmd =
let enable =
let doc = "Enable flag for foo command" in
Arg.(value & flag & info ["enable"] ~doc)
in
let name =
let doc = "Name for foo command" in
Arg.(value & opt string "" & info ["name"] ~doc)
in
let foo enable name args =
Printf.printf "subcommand 'foo'\n";
Printf.printf " enable: %b\n" enable;
Printf.printf " name: %s\n" name;
Printf.printf " tail: [%s]\n" (String.concat "; " args)
in
Term.(const foo $ enable $ name $ Arg.(value & pos_all string [] & info [] ~docv:"ARGS")),
Term.info "foo" ~doc:"Foo subcommand"
let bar_cmd =
let level =
let doc = "Level for bar command" in
Arg.(value & opt int 0 & info ["level"] ~doc)
in
let bar level args =
Printf.printf "subcommand 'bar'\n";
Printf.printf " level: %d\n" level;
Printf.printf " tail: [%s]\n" (String.concat "; " args)
in
Term.(const bar $ level $ Arg.(value & pos_all string [] & info [] ~docv:"ARGS")),
Term.info "bar" ~doc:"Bar subcommand"
let default_cmd =
let doc = "Command-line subcommands example" in
let sdocs = Manpage.s_common_options in
let man = [
`S Manpage.s_description;
`P "This program demonstrates command-line subcommands in OCaml.";
] in
Term.(ret (const (`Help (`Pager, None)))),
Term.info "cli_subcommands" ~version:"1.0.0" ~doc ~sdocs ~man
let () =
let cmds = [foo_cmd; bar_cmd] in
match Term.eval_choice default_cmd cmds with
| `Error _ -> exit 1
| _ -> exit 0
This OCaml program uses the Cmdliner library to define and handle command-line subcommands. Here’s a breakdown of the code:
We define two subcommands:
foo
andbar
.For the
foo
subcommand, we define two flags:--enable
(a boolean flag) and--name
(a string option).For the
bar
subcommand, we define one flag:--level
(an integer option).Each subcommand has its own handler function that prints out the values of its flags and any additional arguments.
We use Cmdliner’s
Term
module to define the command-line interface for each subcommand.A default command is defined to display help information if no subcommand is provided.
Finally, we use
Term.eval_choice
to parse the command-line arguments and execute the appropriate subcommand.
To run this program, you would compile it and then use it like this:
$ ocamlbuild -pkg cmdliner cli_subcommands.native
$ ./cli_subcommands.native foo --enable --name=joe a1 a2
subcommand 'foo'
enable: true
name: joe
tail: [a1; a2]
$ ./cli_subcommands.native bar --level 8 a1
subcommand 'bar'
level: 8
tail: [a1]
This OCaml implementation provides a more type-safe and declarative approach to handling command-line arguments compared to manually parsing them. The Cmdliner library handles much of the complexity of parsing and validating command-line inputs.