From da6f727765a53e282f0eda685bcd994abe7c09ed Mon Sep 17 00:00:00 2001 From: Andre Ambrosio Boechat Date: Wed, 26 Mar 2025 13:59:00 -0300 Subject: [PATCH 1/3] Cookbook recipe to parse command-line arguments with stdlib only --- .../parse-command-line-arguments/00-stdlib.ml | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 data/cookbook/parse-command-line-arguments/00-stdlib.ml diff --git a/data/cookbook/parse-command-line-arguments/00-stdlib.ml b/data/cookbook/parse-command-line-arguments/00-stdlib.ml new file mode 100644 index 0000000000..cecfc717d5 --- /dev/null +++ b/data/cookbook/parse-command-line-arguments/00-stdlib.ml @@ -0,0 +1,65 @@ +--- +packages: [] +--- +(* `Sys.argv` is the command-line arguments as an array of strings + ([standard library documentation](https://ocaml.org/manual/5.3/api/Sys.html#VALargv)). + Here we print each argument with its corresponding index in the array. *) +let simplest_parser () = + Sys.argv + |> Array.to_list + |> List.iteri (Printf.printf "argument %d: %s\n") + + +(* `Arg` is a module for parsing command-line arguments, and it is part of + OCaml's standard library + ([documentation](https://ocaml.org/manual/5.3/api/Arg.html)). + In this function we define the structure of the command-line arguments we + expect, the argument types types and their documentation. This is basically + the same function defined in the module's documentation. + + *) +let arg_module_parser () = + let usage_msg = + "mycmd [--verbose] [] ... -o " + and verbose = ref false + and input_files = ref [] + and output_file = ref "" in + (* This function is called once for each anonymous argument. *) + let anonymous_args_f filename = + input_files := filename :: !input_files + (* The spec list defines argument keywords, "setter" functions to handle the + values, and their corresponding documentation. *) + and spec_list = + [("--verbose", Arg.Set verbose, "Output debug information"); + ("-o", Arg.Set_string output_file, "Set output file name")] + in + Arg.parse spec_list anonymous_args_f usage_msg; + Printf.printf "verbose: %b\n" !verbose; + Printf.printf "input files: %s\n" + (!input_files |> String.concat ", "); + Printf.printf "output file: %s\n" !output_file + +(* Given a command-line like `mycmd --verbose file1 -o /tmp/out`, we should + expect the following output: + + ``` + === Simplest parser === + argument 0: mycmd + argument 1: --verbose + argument 2: file1 + argument 3: -o + argument 4: /tmp/out + + === Arg.parse === + verbose: true + input files: file1 + output file: /tmp/out + ``` *) +let () = + print_endline "=== Simplest parser ==="; + simplest_parser (); + + Printf.printf "\n%!"; + + print_endline "=== Arg.parse ==="; + arg_module_parser () From f37cc9e64749daddbfcb3e55eff4fea09c2a5e77 Mon Sep 17 00:00:00 2001 From: Andre Ambrosio Boechat Date: Fri, 28 Mar 2025 09:26:59 -0300 Subject: [PATCH 2/3] Cookbook recipe to parse command-line arguments with Cmdliner --- .../01-cmdliner.ml | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 data/cookbook/parse-command-line-arguments/01-cmdliner.ml diff --git a/data/cookbook/parse-command-line-arguments/01-cmdliner.ml b/data/cookbook/parse-command-line-arguments/01-cmdliner.ml new file mode 100644 index 0000000000..a59faa1ed4 --- /dev/null +++ b/data/cookbook/parse-command-line-arguments/01-cmdliner.ml @@ -0,0 +1,78 @@ +--- +packages: +- name: cmdliner + tested_version: "1.3.0" + used_libraries: + - cmdliner +--- +(* In this example, we define a parser for a command-line like this: + + ``` + mycmd --verbose input_file -o output_file + ``` + + `--verbose` and `-o` are optional, and the command should accept multiple + input files. + + We can find more examples on + [this page](https://erratique.ch/software/cmdliner/doc/examples.html). + *) +let cmdliner_parser () = + (* `Cmdliner` is a library that allows the declarative definition of + command-line interfaces + ([documentation page](https://erratique.ch/software/cmdliner/doc/index.html)). + *) + let open Cmdliner in + (* First we declare the expected arguments of our command-line, and how + `Cmdliner` should parse them. *) + let verbose = + let doc = "Output debug information" in + (* `&` is a right associative composition operator + ([documentation](https://erratique.ch/software/cmdliner/doc/Cmdliner/Arg/index.html#val-(&))). + *) + Arg.(value & flag & info ["v" ; "verbose"] ~doc) + and input_files = + let doc = "Input file(s)" in + Arg.(non_empty & pos_all file [] + & info [] ~docv:"INPUT" ~doc) + and output_file = + let doc = "Output file" + and docv = "OUTPUT" in + Arg.(value & opt (some string) None + & info ["o"] ~docv ~doc) + (* `mycmd` is the function that the program will apply to the parsed + arguments. *) + and mycmd verbose input_files output_file = + Printf.printf "verbose: %b\n" verbose; + Printf.printf "input files: %s\n" + (input_files |> String.concat ", "); + Printf.printf "output file: %s\n" + (Option.value ~default:"" output_file) + in + (* Declaration of the complete command, including its man-like + documentation. *) + let cmd = + let doc = "An example command" + and man = [ + `S Manpage.s_description; + `P "A command that can take multiple files + and outputs a file (optional)." + ] + in + Cmd.v (Cmd.info "mycmd" ~doc ~man) + Term.(const mycmd $ verbose $ input_files $ output_file) + in + Cmd.eval cmd + + +(* Given a command-line like + `mycmd --verbose -o somefile ./dune-project ./cmd_cookbook.opam`, we should + expect the following output: + + ``` + verbose: true + input files: ./dune-project, ./cmd_cookbook.opam + output file: somefile + ``` *) +let () = + exit @@ cmdliner_parser () From 5c4d80d5e7e062eb6c71163f6e4a0bd667f91343 Mon Sep 17 00:00:00 2001 From: Andre Ambrosio Boechat Date: Fri, 28 Mar 2025 12:00:09 -0300 Subject: [PATCH 3/3] Remove indentation from code comments "ood-gen" uses a regex pattern that expects comments starting only at the beginning of lines. --- .../parse-command-line-arguments/00-stdlib.ml | 11 +++----- .../01-cmdliner.ml | 26 +++++++++---------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/data/cookbook/parse-command-line-arguments/00-stdlib.ml b/data/cookbook/parse-command-line-arguments/00-stdlib.ml index cecfc717d5..a2abed7b36 100644 --- a/data/cookbook/parse-command-line-arguments/00-stdlib.ml +++ b/data/cookbook/parse-command-line-arguments/00-stdlib.ml @@ -9,26 +9,23 @@ let simplest_parser () = |> Array.to_list |> List.iteri (Printf.printf "argument %d: %s\n") - (* `Arg` is a module for parsing command-line arguments, and it is part of OCaml's standard library ([documentation](https://ocaml.org/manual/5.3/api/Arg.html)). In this function we define the structure of the command-line arguments we expect, the argument types types and their documentation. This is basically - the same function defined in the module's documentation. - - *) + the same function defined in the module's documentation. *) let arg_module_parser () = let usage_msg = "mycmd [--verbose] [] ... -o " and verbose = ref false and input_files = ref [] and output_file = ref "" in - (* This function is called once for each anonymous argument. *) +(* This function is called once for each anonymous argument. *) let anonymous_args_f filename = input_files := filename :: !input_files - (* The spec list defines argument keywords, "setter" functions to handle the - values, and their corresponding documentation. *) +(* The spec list defines argument keywords, "setter" functions to handle the + values, and their corresponding documentation. *) and spec_list = [("--verbose", Arg.Set verbose, "Output debug information"); ("-o", Arg.Set_string output_file, "Set output file name")] diff --git a/data/cookbook/parse-command-line-arguments/01-cmdliner.ml b/data/cookbook/parse-command-line-arguments/01-cmdliner.ml index a59faa1ed4..f2c1f45706 100644 --- a/data/cookbook/parse-command-line-arguments/01-cmdliner.ml +++ b/data/cookbook/parse-command-line-arguments/01-cmdliner.ml @@ -18,18 +18,18 @@ packages: [this page](https://erratique.ch/software/cmdliner/doc/examples.html). *) let cmdliner_parser () = - (* `Cmdliner` is a library that allows the declarative definition of - command-line interfaces - ([documentation page](https://erratique.ch/software/cmdliner/doc/index.html)). - *) +(* `Cmdliner` is a library that allows the declarative definition of + command-line interfaces + ([documentation page](https://erratique.ch/software/cmdliner/doc/index.html)). + *) let open Cmdliner in - (* First we declare the expected arguments of our command-line, and how - `Cmdliner` should parse them. *) +(* First we declare the expected arguments of our command-line, and how + `Cmdliner` should parse them. *) let verbose = let doc = "Output debug information" in - (* `&` is a right associative composition operator - ([documentation](https://erratique.ch/software/cmdliner/doc/Cmdliner/Arg/index.html#val-(&))). - *) +(* `&` is a right associative composition operator + ([documentation](https://erratique.ch/software/cmdliner/doc/Cmdliner/Arg/index.html#val-(&))). + *) Arg.(value & flag & info ["v" ; "verbose"] ~doc) and input_files = let doc = "Input file(s)" in @@ -40,8 +40,8 @@ let cmdliner_parser () = and docv = "OUTPUT" in Arg.(value & opt (some string) None & info ["o"] ~docv ~doc) - (* `mycmd` is the function that the program will apply to the parsed - arguments. *) +(* `mycmd` is the function that the program will apply to the parsed + arguments. *) and mycmd verbose input_files output_file = Printf.printf "verbose: %b\n" verbose; Printf.printf "input files: %s\n" @@ -49,8 +49,8 @@ let cmdliner_parser () = Printf.printf "output file: %s\n" (Option.value ~default:"" output_file) in - (* Declaration of the complete command, including its man-like - documentation. *) +(* Declaration of the complete command, including its man-like + documentation. *) let cmd = let doc = "An example command" and man = [