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 0This OCaml program uses the Cmdliner library to define and handle command-line subcommands. Here’s a breakdown of the code:
We define two subcommands:
fooandbar.For the
foosubcommand, we define two flags:--enable(a boolean flag) and--name(a string option).For the
barsubcommand, 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
Termmodule 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_choiceto 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.