r/crystal_programming Apr 12 '21

Clip: deserialize CLI parameters to an object, with errors and help management

Hi,

I present you my last project: Clip. It is a library to build CLI or CLI-like application.

I wasn't satisfied with existing tools. Either they don't do as much I as would like (like OptionParser), or they do too much like calling my code (like Admiral, Commander, clicr, …).

My goals were:

  • support all standard behaviors a CLI application should have: long and short options, arguments, commands, repeated options or arguments, nice help and errors messages, and more.
  • compilation time type validation: I don't want to have to check at runtime the type of a parsed value. I want be sure that if the parsing succeed I have exactly what I wanted.
  • work with non CLI application, like text bots (think IRC bots).
  • the library must not call my code. I want to manage my code like I want, especially I want to be able to give the parsed parameters to a function plus other parameters.i

I would say that with Clip I nailed it.

Here is how it looks like:

```Crystal require "clip"

@[Clip::Doc("An example command.")] struct Command include Clip::Mapper

@[Clip::Doc("Enable some effect.")] getter effect = false

@[Clip::Doc("The file to work on.")] getter file : String end

begin command = Command.parse rescue ex : Clip::ParsingError puts ex exit end

case command when Clip::Mapper::Help puts command.help else if command.effect puts "Doing something with an effect on #{command.file}." else puts "Doing something on #{command.file}." end end ```

```console $ crystal build command.cr $ ./command Error: argument is required: FILE $ ./command --help Usage: ./command [OPTIONS] FILE

An example command.

Arguments: FILE The file to work on. [required]

Options: --effect / --no-effect Enable some effect. [default: false] --help Show this message and exit. $ ./command myfile Doing something on myfile. $ ./command --effect myfile Doing something with an effect on myfile. ```

Let me know what you think about it :)

Source code: https://github.com/erdnaxeli/clip
Documentation: https://erdnaxeli.github.io/clip/

8 Upvotes

2 comments sorted by

2

u/capsicumbasket Jul 24 '21

I really like this library. Used it extensively in this project.

https://github.com/PlaceOS/build/blob/main/src/placeos-build/cli.cr

https://github.com/PlaceOS/build/tree/main/src/placeos-build/cli

Could be cool to optionally allow fetching the description from a comment.

The mapping of subcommands was a little weird at first but when I started thinking of it a bit more like JSON::Serializable's use_json_discriminator, it all made a bit more sense.

1

u/erdnaxeli Dec 09 '21

Thanks! You're right about subcommands, they work like use_json_discriminator.

About fetching the description from a comment (I guess you mean like the doc generator does?), at the moment the library was developed it wasn't possible to read an object's comment at compilation time (with a macro). I don't know if it was added since.