What would be the most idiomatic way to declare CLI cmds using a library?

If you were using a CLI library in elixir, do you prefer to use the module and then each function defined generates a CLI cmd or do you prefer to have define macros cmds and handle events for each cmd? examples below

option 1, with using macro and “native” definition using only module attributes:

option 2, with “define” macros and events

I didn’t find any decent library to build CLI commands and options ala rust clap or clojure clapps, so I would like to build my own to Elixir. It will probably leverage the owl package “components” in the future, but firstly I would like to see opinions of the usage proposals!

While I will not address your questions directly, I just want to make sure you’re aware of Owl - A toolkit for writing command-line user interfaces by @fuelen.

3 Likes

yes i’m aware of this library and i would like to leverage those components. But it doesn’t handle self documented commands and options do it doesn’t build a CLI it self, but utilities to be used while run a command.

With my library you can define which commands your CLI would have and process them the way you like, even using own features (:

My recommendation is to start with an option 3: pure data description and manual composition/function calls with no magic. You can add a convenience layer on top after you have a very clear idea of how things should compose and be organized.

Edit: I’d look at NimbleOptions for API inspiration.

6 Likes

I see. To be fair Rust’s clap has quite a lot of magic. Try something more manual and explicit for the first iteration IMO.

1 Like

I built this for myself : GitHub - lud/cli_mate: Another command line parser for Elixir

The goal is to have an embeddable library that can be used as a dependency for mix tasks installed by mix archive install hex my_lib, because in that way, the dependencies are not installed.

It is a work in progress, there is no real documentation. But there are other packages as well on hex.pm for that. Plus, it is not (yet) intended to define multiple commands in one file, as I use it in mix tasks, so the command dispatch is directly done by the user when they call mix stuff.command_one vs. mix stuff.command_two.

I like more your second option : define the data in one place, then handle it in one place.

I was looking for something similar and ended up building my own command parser as well. Take a look at Prompt.Router — prompt v0.8.1 and see if it meets your needs. I’m very open to input and would welcome contributions.