dry-rb / dry-cli

General purpose Command Line Interface (CLI) framework for Ruby
https://dry-rb.org/gems/dry-cli
MIT License
328 stars 41 forks source link

More powerful options #129

Open noraj opened 1 year ago

noraj commented 1 year ago

Flags

options are always considered having a value --mode=http2 or --mode http2.

E.g. just having --color, having the flag equals options.fetch(:color) returning true, not having the flag equals options.fetch(:color) returning false. It's better than having --color true and --color false with values: %w[true false] and casting the string to a boolean.

Aliases

It would be nice to have has many aliases as we want for an option.

E.g. -c, --color or --color, --colour.

It's often handy to have long flags that are mnemotechnic and short flags for those familiar with the tool that want to type faster.

Mutually exclusive

Sometimes it is required to have mutually exclusive options, see #128.

Casting type

As passed from the CLI, all values are strings, so it would be handy to have cast types for options.

E.g. --age 21 or --advanced true. It's allows to cast type in the definition of the option, avoiding forgetting to cast it when the value is retrieved or to cast it several times if the option is used at multiple places.

MadBomber commented 1 year ago

I think a few of these have already been put in place. For example I'm using ...

option :debug,
  aliases:  %w[ -d --debug],
  type:  :boolean,
  default:  false

amd the same structure for verbose in a Base command which defines all blobal options for all toerh commands.

edited ... I when back and looked at my code where I am using a type: :integer and darn it, the value is coming in as a string not the Integer that I was expecting. It was very clear when I setup a values: )0..255).to_a element in the option. My cli failed but did not tell me why.

MadBomber commented 1 year ago

One of the things that I found myself wishing for is some kind of action that gets executed when the option is present. As is, those kinds of things have to be build as a command. I'd much rather put a simple Proc or Lambda in the option definition that have to layout a small command class. For example consider a version option.

option :version,
  aliases:  %w[ --version ],
  action: -> { puts VERSION; exit(0) }

... of course you'd going to ask where does that version constant come from? I'm assuming it comes from the command class. If I wanted it to come from the ProgramName I would have coded it with that name space.

As is, I had to create a Version command class and then for all my commands which have versions I had to register both the command and the command with a version sub-command.

register "my_command", self
register "my_command version', Command::PrintVersion.new(VERSION), aliases: %w[-v --version]

I've been experimenting in https://github.com/MadBomber/experiments/tree/master/cli_options/dry-cli

I have a monkey-patch in that repo that implements global_header, global_footer, header and footer to wrap the existing help text is what I want... like copyrights, contact info, etc.