Skip to content

Conversation

@gustavothecoder
Copy link
Contributor

Resolve #128

This PR adds support to mutually exclusive options (i.e. options that cannot be used together). The implemented API is exemplified bellow. I'm not totally satisfied with the current API, so any suggestions will be appreciated.

require "dry/cli"

class Greetings < Dry::CLI::Command
  mutually_exclusive_options [
    [:english, {desc: "Chooses English", type: :flag}],
    [:spanish, {desc: "Chooses Spanish", type: :flag}],
    [:portuguese, {desc: "Chooses Portuguese", type: :flag}]
  ] 

  def call(options)
    if options.key?(:english)
      puts "Good morning"
    elsif options.key?(:spanish)
      puts "Buenos días"
    elsif options.key?(:portuguese)
      puts "Bom dia"
    end
  end
end

# $ foo greetings --english
# Good morning

# $ foo greetings --english --spanish
# ERROR: "foo greetings" was called with arguments "--english --spanish"

@katafrakt
Copy link
Contributor

I've been thinking about this for past few days and unfortunately I think this is not a right API for the solution. There are few issues, but I think the main is that is does not allow to cover this case from the linked issue:

Same for options, for example for git pull you can't have --ff-only and --no-ff or --ff-only and --rebase at the same time.

It's not very easy for me to come up with a sensible alternative, but after trying some option I think this could work better here:

option :ff_only, type: :boolean, excludes: [:no_ff, :rebase]
option :no_ff, type: :boolean, excludes: :ff_only
option :rebase, type: :boolean, excludes: :ff_only

It is quite verbose, I know. But it's explicit and verbosity might encourage users to reevaluate if the validation should lie within CLI handling, or rather inside the application code. The main downside is that it's easy to forget to forbid combining option in one direction (like: --ff-only excludes --ff, but --ff does not exclude --ff-only).

I would also allow adding requires option in the future, if one option caries the necessity to specify another one.

Possible alternative

There is kind of options that is strictly mutually exclusive almost on a syntactic level. Think --ff and --no-ff or --with-ssl and --without-ssl. Maybe there is an opportunity to define such inversion in a simpler way.

option :with_ssl`, type: :boolean, inverted_as: :without_ssl

This would only be allowed for boolean options and specifying what :without_ssl explicitly would not be needed.

Any thoughts @timriley @aaronmallen?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mutually-exclusive arguments or options

2 participants