polydocopt

A subcommand-oriented version of docopt.

Modern command line tools often have totally different subcommands that have different options and arguments.

This is a library to make it easier to write such tools while keeping with the spirit of docopt.

NOTE: This builds on the excellent docopt.cr!

Installation

  1. Add the dependency to your shard.yml:

    dependencies:
      polydocopt:
        github: ralsina/polydocopt
  2. Run shards install

Usage

You can see an example in the example directory, but this is the gist of it:

To build it: shards build and then you can run ./bin/say to see the help.

> ./bin/say
Help about the say command.

Usage:
  say help [COMMAND]

Commands:
  hello       Says hello to the world
  bye         Says bye to the world

> ./bin/say help hello
Says hello to the world

Usage:
  say hello [-u] [-p PLANET]

Options:
  -h --help     Show this screen
  -u --upper    Uppercase the output
  -p PLANET     Greet a planet [default: world]

> ./bin/say helo
say: 'helo' is not a say command. See 'say help'.

The most similar command is
	hello

As you can see, it has totally different helps for each subcommand, which is not trivial using many other libraries. It also suggests similar commands when you mistype one, just like git does.

Also, the definition of each command is simple:

require "polydocopt"

struct Hello < Polydocopt::Command
  @@name = "hello"
  @@doc = <<-HELP
    Says hello to the world

    Usage:
      say hello [-u] [-p PLANET]

    Options:
      -h --help     Show this screen
      -u --upper    Uppercase the output
      -p PLANET     Greet a planet [default: world]
    HELP

  def run : Int32
    greeting = "hello #{options["-p"]}"
    greeting = greeting.upcase if options["--upper"]
    puts greeting
    0
  end
end

Hello.register

And you can run your command with all its subcommands like this:

exit(Polydocopt.main("say", ARGV))

Polydocopt.main returns the exit code of the executed command, so wrapping it in exit gives your tool correct exit codes:

| Situation | Exit code | |---------------------------------------------|-----------| | Command ran | whatever run returned | | No arguments, help, -h, --help | 0 | | Unknown or misspelled command | 1 | | Invalid arguments for a command | 1 |

The rules for a command's documentation are:

If you want to test your own commands, Polydocopt.main accepts optional stdout and stderr arguments so you can capture output without touching the real streams:

code = Polydocopt.main("say", ["hello"], stdout: io, stderr: err_io)

Contributing

  1. Fork it (https://github.com/ralsina/polydocopt/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors