Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to suppress automatic creation of --no-boolean flags #733

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/thor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ def method_options(options = nil)
# :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
# :banner - String to show on usage notes.
# :hide - If you want to hide this option from the help.
# :inverse - false if you don't want an inverse option of your boolean type, String or Symbol
# if you want to override the inverse option name.
#
def method_option(name, options = {})
unless [ Symbol, String ].any? { |klass| name.is_a?(klass) }
Expand Down
33 changes: 22 additions & 11 deletions lib/thor/parser/option.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def initialize(name, options = {})
@group = options[:group].to_s.capitalize if options[:group]
@aliases = normalize_aliases(options[:aliases])
@hide = options[:hide]
@inverse = options[:inverse]
end

# This parse quick options given as method_options. It makes several
Expand Down Expand Up @@ -81,17 +82,7 @@ def human_name
end

def usage(padding = 0)
sample = if banner && !banner.to_s.empty?
"#{switch_name}=#{banner}".dup
else
switch_name
end

sample = "[#{sample}]".dup unless required?

if boolean?
sample << ", [#{dasherize('no-' + human_name)}]" unless (name == "force") || name.match(/\Ano[\-_]/)
end
sample = [ sample_banner, inverse_sample ].compact.join(", ")

aliases_for_usage.ljust(padding) + sample
end
Expand Down Expand Up @@ -123,6 +114,26 @@ def #{type}?

protected

def sample_banner
sample_banner = if banner && !banner.to_s.empty?
"#{switch_name}=#{banner}".dup
else
switch_name
end
required? ? sample_banner : "[#{sample_banner}]"
end

def inverse_sample
return if !boolean? || name =~ /^(force|\Ano[\-_])$/

case @inverse
when Symbol, String
"[#{dasherize(@inverse.to_s)}]"
when nil, true
"[#{dasherize('no-' + human_name)}]"
end
end

def validate!
raise ArgumentError, "An option cannot be boolean and required." if boolean? && required?
validate_default_type!
Expand Down
16 changes: 16 additions & 0 deletions spec/parser/option_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,22 @@ def option(name, options = {})
expect(option(:foo, required: false, type: :string, banner: "").usage).to eq("[--foo]")
end

it "suppresses the creation of a --no-option when explicitly requested" do
expect(option("bar", type: :boolean, :inverse => false).usage).to_not include("[--no-bar]")
end

it "allow to override the inverse option" do
expect(option("colorful", type: :boolean, :inverse => :monochromatic).usage).to include("[--monochromatic]")
end

it "creates the inversion flag by default" do
expect(option("bar", type: :boolean).usage).to include("[--no-bar]")
end

it "creates the inversion flag when requested" do
expect(option("bar", type: :boolean, :inverse => true).usage).to include("[--no-bar]")
end

describe "with required values" do
it "does not show the usage between brackets" do
expect(parse(:foo, :required).usage).to eq("--foo=FOO")
Expand Down
Loading