Argument parsing for CLI module

I am writing a CLI utility/framework as an Umbrella app. The concept is to have a main command, we. I would like the we command to take some core arguments, e.g.:

Available subcommands are:
we -h Display this help message
we -v Display version
we config Writes user profile ~/.weconf
-l Displays user profile
we update Updates we
we uninstall Remove we

Any other argument list that is given I’d like to hand off to other apps in the umbrella. e.g.:
./we tag foo -a bar
internally would parse out tag foo -a bar and hand off foo -a bar to the Tag app.

I am having difficulty understanding the OptionParser. I have 2 parts to the question I guess.

  1. How best to separate in a dynamic function the first argument if it doesn’t match in a case as the “subcommand”

  2. Is it possible to “Constantize” (Like in Rails) a the string that is parsed out and execute it as an app call? e.g.: Tag.run(remaining_args_from_parse)

    defmodule We.CLI do
    @moduledoc “”"
    Main we cli tool

    usage: we [ | -hv]

    Available subcommands are:
    we -h Display this help message
    we -v Display version
    we config Writes user profile ~/.wetools
    -l Displays user profile
    we update Updates WeTools
    we uninstall Remove WeTools
    “”"
    import Loki.Shell
    @version “1.0.0”

    def main(argv) do
    argv
    |> parse_args
    |> process
    end

    def parse_args(argv) do
    switches = [help: :boolean, version: :boolean]
    aliases = [h: :help, v: :version]

     parse = OptionParser.parse(argv, switches: switches,
                                      aliases: aliases)
     case parse do
       {[help: true], _, _}          -> :help
       {[version: true], _, _}       -> :version
       {[update: true], _, _}        -> :update
       {_,["config"], _}             -> :config
       {_,["update"], _}             -> :update
       {_,["uninstall"], _}          -> :uninstall
       _                             -> :help
     end
    

    end

    def process(:uninstall) do
    say “execute uninstall function”
    System.halt(0)
    end

    def process(:update) do
    say “execute update function”
    System.halt(0)
    end

    def process(:config) do
    say “execute config function”
    System.halt(0)
    end

    def process(:version) do
    say “Version: #{@version}”
    System.halt(0)
    end

    def process(:help) do
    say @moduledoc
    System.halt(0)
    end
    end

Also, this is the first thing I’ve done in Elixir so forgive me if I am not following the correct patterns.
Thank you in advanced.

1 Like

I did something similar to allow custom args for plugins. My apologies for the weird formatting.

2 Likes

**exilgrep** [string] [files and/or directories] at http://bbense.github.io/elixgrep/Elixgrep.html

Spelling mistake?

That makes sense.

How about taking a string and dynamically calling a module with the same name?

One of the arguments is tag and I have another app module in my deps from umbrella.

defp deps do
    [
     {:tag, in_umbrella: true}
    ]
end

I was trying something like this, where subcommand is tag from the parsed args

module = subcommand |> String.capitalize |> String.to_atom
apply(module, :hello, [])

** (UndefinedFunctionError) function :Tag.hello/0 is undefined (module :Tag is not available)
:Tag.hello()
(we) lib/we/cli.ex:47: We.CLI.parse_args/1
(we) lib/we/cli.ex:22: We.CLI.main/1
(elixir) lib/kernel/cli.ex:76: anonymous fn/3 in Kernel.CLI.exec_fun/2

however if Execute Tag.hello([]) instead I can execute it.

$ ./we tag foo --a bar
Subcommand: tag
[“foo”]
[a: “bar”]
[“tag”, “foo”]
[]
In Tag Module

Not sure what you mean here?

thanks, T

The command in the docs says exilgrep instead of elixgrep. The x and l are transposed.

1 Like

10-4 thanks :thumbsup:

@bbense @vonH

This appears to work:

submodule = "tag" # parsed from OptionParser
submodule = subcommand |> String.capitalize
apply(Module.concat([submodule]), :hello, [])