Command Line Subcommands in Elixir

Here’s the translation of the Go code example to Elixir, formatted in Markdown suitable for Hugo:

Our first program will demonstrate how to create command-line subcommands with their own set of flags. This is similar to tools like mix or git that have many subcommands, each with its own set of options.

defmodule CommandLineSubcommands do
  def main(args) do
    {subcommand, subcommand_args} = List.pop_at(args, 0)

    case subcommand do
      "foo" ->
        {parsed, remaining, _} = OptionParser.parse(subcommand_args,
          strict: [enable: :boolean, name: :string],
          aliases: [e: :enable, n: :name]
        )
        IO.puts("subcommand 'foo'")
        IO.puts("  enable: #{Keyword.get(parsed, :enable, false)}")
        IO.puts("  name: #{Keyword.get(parsed, :name, "")}")
        IO.puts("  tail: #{inspect(remaining)}")

      "bar" ->
        {parsed, remaining, _} = OptionParser.parse(subcommand_args,
          strict: [level: :integer],
          aliases: [l: :level]
        )
        IO.puts("subcommand 'bar'")
        IO.puts("  level: #{Keyword.get(parsed, :level, 0)}")
        IO.puts("  tail: #{inspect(remaining)}")

      _ ->
        IO.puts("expected 'foo' or 'bar' subcommands")
        System.halt(1)
    end
  end
end

In this Elixir version, we define a module CommandLineSubcommands with a main/1 function that will be our entry point. We use pattern matching to extract the subcommand and its arguments.

For each subcommand, we use OptionParser.parse/2 to handle the flags. This function returns a tuple with the parsed options, remaining arguments, and any errors (which we ignore in this example).

To run this program, you would typically create a mix project and set it up as an escript. Here’s how you might use it:

$ ./command_line_subcommands foo --enable --name=joe a1 a2
subcommand 'foo'
  enable: true
  name: joe
  tail: ["a1", "a2"]

$ ./command_line_subcommands bar --level 8 a1
subcommand 'bar'
  level: 8
  tail: ["a1"]

$ ./command_line_subcommands bar --enable a1
subcommand 'bar'
  level: 0
  tail: ["--enable", "a1"]

Note that in the last example, Elixir’s OptionParser doesn’t throw an error for undefined flags. Instead, it includes them in the remaining arguments.

This approach provides a flexible way to create command-line tools with subcommands in Elixir, each with their own set of options and arguments.