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

dev-cmd/extract: Improve the usage instructions #10400

Merged
merged 5 commits into from Jan 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
59 changes: 39 additions & 20 deletions Library/Homebrew/cli/parser.rb
Expand Up @@ -599,21 +599,19 @@ def check_constraint_violations
end

def check_named_args(args)
exception = if @min_named_args && args.size < @min_named_args
if @named_args_type.present?
types = Array(@named_args_type)
if types.any? { |arg| arg.is_a? String }
MinNamedArgumentsError.new(@min_named_args)
else
list = types.map { |type| type.to_s.tr("_", " ") }
list = list.to_sentence two_words_connector: " or ", last_word_connector: " or "
UsageError.new("this command requires a #{list} argument")
end
else
MinNamedArgumentsError.new(@min_named_args)
end
types = Array(@named_args_type).map do |type|
next type if type.is_a? Symbol

:subcommand
end.compact.uniq

exception = if @min_named_args && @max_named_args && @min_named_args == @max_named_args &&
args.size != @max_named_args
NumberOfNamedArgumentsError.new(@min_named_args, types: types)
elsif @min_named_args && args.size < @min_named_args
MinNamedArgumentsError.new(@min_named_args, types: types)
elsif @max_named_args && args.size > @max_named_args
MaxNamedArgumentsError.new(@max_named_args)
MaxNamedArgumentsError.new(@max_named_args, types: types)
end

raise exception if exception
Expand Down Expand Up @@ -688,23 +686,44 @@ def initialize(arg1, arg2)
class MaxNamedArgumentsError < UsageError
extend T::Sig

sig { params(maximum: Integer).void }
def initialize(maximum)
sig { params(maximum: Integer, types: T::Array[Symbol]).void }
def initialize(maximum, types: [])
super case maximum
when 0
"This command does not take named arguments."
else
"This command does not take more than #{maximum} named #{"argument".pluralize(maximum)}"
types << :named if types.empty?
arg_types = types.map { |type| type.to_s.tr("_", " ") }
.to_sentence two_words_connector: " or ", last_word_connector: " or "

"This command does not take more than #{maximum} #{arg_types} #{"argument".pluralize(maximum)}."
end
end
end

class MinNamedArgumentsError < UsageError
extend T::Sig

sig { params(minimum: Integer).void }
def initialize(minimum)
super "This command requires at least #{minimum} named #{"argument".pluralize(minimum)}."
sig { params(minimum: Integer, types: T::Array[Symbol]).void }
def initialize(minimum, types: [])
types << :named if types.empty?
arg_types = types.map { |type| type.to_s.tr("_", " ") }
.to_sentence two_words_connector: " or ", last_word_connector: " or "

super "This command requires at least #{minimum} #{arg_types} #{"argument".pluralize(minimum)}."
end
end

class NumberOfNamedArgumentsError < UsageError
extend T::Sig

sig { params(minimum: Integer, types: T::Array[Symbol]).void }
def initialize(minimum, types: [])
types << :named if types.empty?
arg_types = types.map { |type| type.to_s.tr("_", " ") }
.to_sentence two_words_connector: " or ", last_word_connector: " or "

super "This command requires exactly #{minimum} #{arg_types} #{"argument".pluralize(minimum)}."
end
end
end
Expand Down
3 changes: 2 additions & 1 deletion Library/Homebrew/dev-cmd/extract.rb
Expand Up @@ -83,6 +83,7 @@ module Homebrew
sig { returns(CLI::Parser) }
def extract_args
Homebrew::CLI::Parser.new do
usage_banner "`extract` [<--version>`=`] [<--force>] <formula> <tap>"
description <<~EOS
Look through repository history to find the most recent version of <formula> and
create a copy in <tap>`/Formula/`<formula>`@`<version>`.rb`. If the tap is not
Expand All @@ -95,7 +96,7 @@ def extract_args
switch "-f", "--force",
description: "Overwrite the destination formula if it already exists."

named_args :formula, number: 2
named_args [:formula, :tap], number: 2
end
end

Expand Down
2 changes: 1 addition & 1 deletion Library/Homebrew/test/cask/cmd/create_spec.rb
Expand Up @@ -47,7 +47,7 @@
it "raises an exception when more than one Cask is given" do
expect {
described_class.run("additional-cask", "another-cask")
}.to raise_error(UsageError, /Only one cask can be created at a time\./)
}.to raise_error(Homebrew::CLI::NumberOfNamedArgumentsError)
end

it "raises an exception when the Cask already exists" do
Expand Down
2 changes: 1 addition & 1 deletion Library/Homebrew/test/cask/cmd/edit_spec.rb
Expand Up @@ -21,7 +21,7 @@
it "raises an error when given more than one argument" do
expect {
described_class.new("local-caffeine", "local-transmission")
}.to raise_error(UsageError, /Only one cask can be edited at a time\./)
}.to raise_error(Homebrew::CLI::NumberOfNamedArgumentsError)
end

it "raises an exception when the Cask doesn't exist" do
Expand Down
Expand Up @@ -6,7 +6,7 @@
it "raises an exception " do
expect {
described_class.run
}.to raise_error(UsageError, /this command requires a .*cask.* argument/)
}.to raise_error(UsageError, /This command requires .*cask.* argument/)
end
end
end
58 changes: 50 additions & 8 deletions Library/Homebrew/test/cli/parser_spec.rb
Expand Up @@ -455,11 +455,11 @@
end

it "doesn't accept fewer than the passed number of arguments" do
expect { parser_number.parse([]) }.to raise_error(Homebrew::CLI::MinNamedArgumentsError)
expect { parser_number.parse([]) }.to raise_error(Homebrew::CLI::NumberOfNamedArgumentsError)
end

it "doesn't accept more than the passed number of arguments" do
expect { parser_number.parse(["foo", "bar"]) }.to raise_error(Homebrew::CLI::MaxNamedArgumentsError)
expect { parser_number.parse(["foo", "bar"]) }.to raise_error(Homebrew::CLI::NumberOfNamedArgumentsError)
end

it "accepts the passed number of arguments" do
Expand All @@ -475,18 +475,58 @@
expect { parser_none.parse([]) }.not_to raise_error
end

it "displays the correct error message with no arg types and min" do
parser = described_class.new do
named_args min: 2
end
expect { parser.parse([]) }.to raise_error(
Homebrew::CLI::MinNamedArgumentsError, /This command requires at least 2 named arguments/
)
end

it "displays the correct error message with no arg types and number" do
parser = described_class.new do
named_args number: 2
end
expect { parser.parse([]) }.to raise_error(
Homebrew::CLI::NumberOfNamedArgumentsError, /This command requires exactly 2 named arguments/
)
end

it "displays the correct error message with no arg types and max" do
parser = described_class.new do
named_args max: 1
end
expect { parser.parse(%w[foo bar]) }.to raise_error(
Homebrew::CLI::MaxNamedArgumentsError, /This command does not take more than 1 named argument/
)
end

it "displays the correct error message with an array of strings" do
parser = described_class.new do
named_args %w[on off], min: 1
named_args %w[on off], number: 1
end
expect { parser.parse([]) }.to raise_error(Homebrew::CLI::MinNamedArgumentsError)
expect { parser.parse([]) }.to raise_error(
Homebrew::CLI::NumberOfNamedArgumentsError, /This command requires exactly 1 subcommand/
)
end

it "displays the correct error message with an array of symbols" do
parser = described_class.new do
named_args [:formula, :cask], min: 1
end
expect { parser.parse([]) }.to raise_error(UsageError, /this command requires a formula or cask argument/)
expect { parser.parse([]) }.to raise_error(
Homebrew::CLI::MinNamedArgumentsError, /This command requires at least 1 formula or cask argument/
)
end

it "displays the correct error message with an array of symbols and max" do
parser = described_class.new do
named_args [:formula, :cask], max: 1
end
expect { parser.parse(%w[foo bar]) }.to raise_error(
Homebrew::CLI::MaxNamedArgumentsError, /This command does not take more than 1 formula or cask argument/
)
end
end

Expand All @@ -502,18 +542,20 @@
end

it "doesn't allow less than the specified number of arguments" do
expect { parser.parse([]) }.to raise_error(Homebrew::CLI::MinNamedArgumentsError)
expect { parser.parse([]) }.to raise_error(Homebrew::CLI::NumberOfNamedArgumentsError)
end

it "treats a symbol as a single argument of the specified type" do
formula_parser = described_class.new do
named :formula
end
expect { formula_parser.parse([]) }.to raise_error(UsageError, /this command requires a formula argument/)
expect { formula_parser.parse([]) }.to raise_error(
Homebrew::CLI::NumberOfNamedArgumentsError, /This command requires exactly 1 formula argument/
)
end

it "doesn't allow more than the specified number of arguments" do
expect { parser.parse(["foo", "bar"]) }.to raise_error(Homebrew::CLI::MaxNamedArgumentsError)
expect { parser.parse(["foo", "bar"]) }.to raise_error(Homebrew::CLI::NumberOfNamedArgumentsError)
end
end

Expand Down
1 change: 1 addition & 0 deletions completions/bash/brew
Expand Up @@ -899,6 +899,7 @@ _brew_extract() {
;;
esac
__brew_complete_formulae
__brew_complete_tapped
}

_brew_fetch() {
Expand Down
2 changes: 1 addition & 1 deletion docs/Manpage.md
Expand Up @@ -1019,7 +1019,7 @@ or open the Homebrew repository for editing if no formula is provided.
* `--cask`:
Treat all named arguments as casks.

### `extract` [*`--version`*`=`] [*`--force`*] *`formula`* ...
### `extract` [*`--version`*`=`] [*`--force`*] *`formula`* *`tap`*

Look through repository history to find the most recent version of *`formula`* and
create a copy in *`tap`*`/Formula/`*`formula`*`@`*`version`*`.rb`. If the tap is not
Expand Down
2 changes: 1 addition & 1 deletion manpages/brew.1
Expand Up @@ -1417,7 +1417,7 @@ Treat all named arguments as formulae\.
\fB\-\-cask\fR
Treat all named arguments as casks\.
.
.SS "\fBextract\fR [\fI\-\-version\fR\fB=\fR] [\fI\-\-force\fR] \fIformula\fR \.\.\."
.SS "\fBextract\fR [\fI\-\-version\fR\fB=\fR] [\fI\-\-force\fR] \fIformula\fR \fItap\fR"
Look through repository history to find the most recent version of \fIformula\fR and create a copy in \fItap\fR\fB/Formula/\fR\fIformula\fR\fB@\fR\fIversion\fR\fB\.rb\fR\. If the tap is not installed yet, attempt to install/clone the tap before continuing\. To extract a formula from a tap that is not \fBhomebrew/core\fR use its fully\-qualified form of \fIuser\fR\fB/\fR\fIrepo\fR\fB/\fR\fIformula\fR\.
.
.TP
Expand Down