Skip to main content

Usage Styles

This section demonstrates how to use the helper modules available in cmdlang and how to add them to the scope using different styles commonly used in the OCaml community.

Depending on your preference and the conventions of your project, you can choose from various styles to incorporate cmdlang into your code. The Command.Std module provides a convenient way to access all the standard components of cmdlang, while directly using Cmdlang, local open statements, or aliases can offer more explicit control over the scope.

Introducing Command to the scope

To define commands, you need to import the cmdlang package. This packages defines an OCaml library named Cmdlang, which exports a single module named Command. There are several ways Command may be brought to scope.

Import via flags

The approach recommended by the cmdlang authors is to avoid mentioning the name cmdlang directly in your OCaml files. Instead, configure the project dependencies to open Cmdlang via flags in your dune file:

(library
(name my_library)
(flags :standard -open Cmdlang)
(libraries cmdlang))

However, other options are possible. For example, you can use an import file to specify module aliases:

Import file

A common practice consists in having an import.ml file per directory, where you can specify module aliases.

module Command = Cmdlang.Command

Then, each other file in the directory starts with:

open! Import

Setup that way, the module Command is effectively bound to Cmdlang.Command in all the files.

Local aliases

If your project doesn't use import files, you can always move this alias near the parts where the command are defined.

module Command = Cmdlang.Command

(* Define your commands below. *)

In the rest of the guide, we'll assume that the module is available as Command.

Declarative styles

Using let+ and let open

In this style, the applicative syntax part is implemented via the use of let+ and and+ binding operators.

They are introduced to the scope, alongside the common modules Arg and Param via a local open of Command.Std.

let _ : unit Command.t =
Command.make
~summary:"A command skeleton"
(let open Command.Std in
let+ (_ : int) = Arg.named [ "n" ] Param.int ~doc:"A value for n"
and+ () = Arg.return () in
())
;;

This is the main style recommended by the cmdlang authors.

No Indentation Tweak with @@

Some people prefer limiting the indentation of large blocks with the help of the infix operator @@. In this context, this may look like this:

let _ : unit Command.t =
Command.make ~summary:"A command skeleton"
@@
let open Command.Std in
let+ (_ : int) = Arg.named [ "n" ] Param.int ~doc:"A value for n"
and+ () = Arg.return () in
()
;;

The cmdlang authors do not have much experience with this style at the time of writing.

Using let-syntax and map_open

An alternative based on the let%map_open operator of ppx_let is also supported.

let _ : unit Command.t =
Command.make
~summary:"A command skeleton"
(let%map_open.Command () = Arg.return ()
and () = Arg.return () in
())
;;

Other styles

cmdlang aims to be flexible and accommodate various coding styles. If you have a specific style or use case that is not covered here, please reach out to us. We are open to feedback and can make adjustments to the interface to better support your needs.

Conclusion

This guide has shown you different ways to use the helper modules in cmdlang, including a standard recommended by the authors. Feel free to experiment with these styles and choose the one that best suits your project.