Skip to content

Commit b7b1cf9

Browse files
committed
Allow command initializer to accept a block that can be run with #run, and refactor CLI to parse command line arguments/flags/switches into Command::Option
1 parent ca520d9 commit b7b1cf9

File tree

4 files changed

+67
-31
lines changed

4 files changed

+67
-31
lines changed

lib/git_commander/cli.rb

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ def say(message)
4444
#
4545
# @param command [Command] the git-cmd command to parse the arguments for
4646
# @param arguments [Array] the command line arguments
47+
# @return options [Array] the GitCommander::Command options with values
4748
def parse_command_options!(command, arguments)
48-
options = {}
4949
valid_arguments_for_command = command.arguments.map { |arg| "[#{arg.name}]" }.join(" ")
5050

5151
parser = OptionParser.new do |opts|
@@ -54,29 +54,25 @@ def parse_command_options!(command, arguments)
5454
opts.separator "COMMAND OPTIONS:" if command.flags.any? || command.switches.any?
5555

5656
command.flags.each do |flag|
57-
opts.on("-#{flag.name[0]}", "--#{underscore_to_kebab(flag.name)} #{flag.name.upcase}", flag.description.to_s) do |f|
58-
options[flag.name] = f || flag.default
57+
opts.on("-#{flag.name[0]}", command_line_flag_formatted_name(flag), flag.description.to_s) do |f|
58+
flag.value = f
5959
end
6060
end
6161

6262
command.switches.each do |switch|
6363
opts.on("-#{switch.name[0]}", "--[no-]#{switch.name}", switch.description) do |s|
64-
options[switch.name] = s || switch.default
64+
switch.value = s
6565
end
6666
end
6767
end
6868
parser.parse!(arguments)
6969

7070
# Add arguments to options to pass to defined commands
7171
command.arguments.each do |argument|
72-
options[argument.name] = arguments.shift || argument.default
73-
end
74-
# Add any defaults
75-
(command.flags + command.switches).each do |option|
76-
options[option.name] ||= option.default
72+
argument.value = arguments.shift
7773
end
7874

79-
options
75+
command.options
8076
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
8177
command.help
8278
GitCommander.logger.debug "[CLI] Failed to parse command line options – #{e.inspect}"
@@ -85,6 +81,10 @@ def parse_command_options!(command, arguments)
8581

8682
private
8783

84+
def command_line_flag_formatted_name(flag)
85+
"--#{underscore_to_kebab(flag.name)} #{flag.name.upcase}"
86+
end
87+
8888
def underscore_to_kebab(sym_or_string)
8989
sym_or_string.to_s.gsub("_", "-").to_sym
9090
end

lib/git_commander/command.rb

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,24 @@
33
module GitCommander
44
# @abstract Wraps domain logic for executing git-cmd commands
55
class Command
6-
attr_reader :arguments, :block, :description, :flags, :name, :summary, :switches
6+
attr_reader :arguments, :block, :description, :flags, :name, :options, :summary, :switches
77
attr_accessor :output
88

99
# @nodoc
1010
class Option
1111
attr_reader :default, :description, :name
12+
attr_writer :value
13+
1214
def initialize(name:, default: nil, description: nil)
1315
@name = name.to_sym
1416
@default = default
1517
@description = description
1618
end
1719

20+
def value
21+
@value || @default
22+
end
23+
1824
def ==(other)
1925
other.class == self.class &&
2026
other.name == name &&
@@ -24,19 +30,20 @@ def ==(other)
2430
alias eql? ==
2531
end
2632

27-
def initialize(name, registry: nil, **options)
33+
def initialize(name, registry: nil, **options, &block)
2834
@name = name
2935
@description = options[:description]
3036
@summary = options[:summary]
31-
@block = options[:block] || proc {}
37+
@block = block_given? ? block : proc {}
3238
@registry = registry || GitCommander::Registry.new
3339
@output = options[:output] || STDOUT
3440

35-
parse_options(options)
41+
define_command_options(options)
3642
end
3743

38-
def run(args = [])
39-
GitCommander.logger.info "Running '#{name}' with arguments: #{args.inspect}"
44+
def run(run_options = [])
45+
GitCommander.logger.info "Running '#{name}' with arguments: #{@options.inspect}"
46+
instance_exec(run_options, &@block)
4047
end
4148

4249
def say(message)
@@ -55,10 +62,15 @@ def help
5562

5663
private
5764

58-
def parse_options(options)
59-
@arguments = Array(options[:arguments]).map { |a| Option.new(**a) }
60-
@flags = Array(options[:flags]).map { |f| Option.new(**f) }
61-
@switches = Array(options[:switches]).map { |s| Option.new(**s) }
65+
def define_command_options(options)
66+
@arguments = options_from_hash(options[:arguments])
67+
@flags = options_from_hash(options[:flags])
68+
@switches = options_from_hash(options[:switches])
69+
@options = Set.new(@arguments + @flags + @switches)
70+
end
71+
72+
def options_from_hash(hash)
73+
Array(hash).map { |v| Option.new(**v) }
6274
end
6375

6476
def description_help

spec/lib/git_commander/cli_spec.rb

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,11 @@
4545
target_command = "wtf"
4646
arguments = ["What's up with that?", "And this?"]
4747
command = GitCommander::Command.new :zombie, arguments: [{ name: :this }, { name: :that }], output: output
48+
expected_comand_options = command.options.dup
49+
expected_comand_options.find { |o| o.name == :this }.value = arguments.first
50+
expected_comand_options.find { |o| o.name == :that }.value = arguments.last
4851
expect(registry).to receive(:find).with(target_command).and_return(command)
49-
expect(command).to receive(:run).with(this: arguments.first, that: arguments.last)
52+
expect(command).to receive(:run).with(expected_comand_options)
5053
expect(cli).to_not receive(:help)
5154

5255
cli.run [target_command, *arguments]
@@ -58,8 +61,10 @@
5861
flags: [{ name: :question, default: "What's up with that?" }],
5962
output: output
6063
)
64+
expected_comand_options = command.options.dup
65+
expected_comand_options.find { |o| o.name == :question }.value = "Yo dawg, zombies?"
6166
expect(registry).to receive(:find).with("zombie").and_return(command)
62-
expect(command).to receive(:run).with(question: "Yo dawg, zombies?")
67+
expect(command).to receive(:run).with(expected_comand_options)
6368
expect(cli).to_not receive(:help)
6469

6570
cli.run ["zombie", "--question", "Yo dawg, zombies?"]
@@ -71,8 +76,9 @@
7176
flags: [{ name: :question, default: "What's up with that?" }],
7277
output: output
7378
)
79+
expected_comand_options = command.options.dup
7480
expect(registry).to receive(:find).with("zombie").and_return(command)
75-
expect(command).to receive(:run).with(question: "What's up with that?")
81+
expect(command).to receive(:run).with(expected_comand_options)
7682
expect(cli).to_not receive(:help)
7783

7884
cli.run ["zombie"]
@@ -87,13 +93,13 @@
8793
switches: [{ name: :auto_answer, default: false }],
8894
output: output
8995
)
96+
expected_comand_options = command.options.dup
97+
expected_comand_options.find { |o| o.name == :this }.value = arguments.first
98+
expected_comand_options.find { |o| o.name == :that }.value = arguments.last
99+
expected_comand_options.find { |o| o.name == :question }.value = "Yo dawg, zombies?"
100+
expected_comand_options.find { |o| o.name == :auto_answer }.value = true
90101
expect(registry).to receive(:find).with("zombie").and_return(command)
91-
expect(command).to receive(:run).with(
92-
this: arguments.first,
93-
that: arguments.last,
94-
question: "Yo dawg, zombies?",
95-
auto_answer: true
96-
)
102+
expect(command).to receive(:run).with(expected_comand_options)
97103
expect(cli).to_not receive(:help)
98104

99105
cli.run ["zombie", "-q", "Yo dawg, zombies?", "--auto-answer", *arguments]

spec/lib/git_commander/command_spec.rb

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,36 @@
33
require "spec_helper"
44

55
describe GitCommander::Command do
6-
it "runs the block registered to it"
7-
it "runs the block registered to it passing arguments"
6+
it "runs the block registered to it" do
7+
output = spy("output")
8+
command = described_class.new(:wtf, output: output) do
9+
say "I'm on a boat!"
10+
end
11+
command.run
12+
expect(output).to have_received(:puts).with "I'm on a boat!"
13+
end
14+
15+
it "runs the block registered to it passing arguments" do
16+
output = spy("output")
17+
command = described_class.new(:wtf, output: output) do |vehicle:|
18+
say "I'm on a #{vehicle}!"
19+
end
20+
command.run vehicle: "T-Rex"
21+
expect(output).to have_received(:puts).with "I'm on a T-Rex!"
22+
end
823
it "runs the block registered to it passing options"
924
it "runs the block registered to it passing arguments and options"
1025
it "runs the block registered to it passing options with defaults"
26+
1127
it "can add output" do
1228
output = spy("output")
1329
command = described_class.new(:wtf, output: output)
1430
command.say "Ooh eeh what's up with that"
1531
expect(output).to have_received(:puts).with "Ooh eeh what's up with that"
1632
end
1733

34+
it "raises an error if no arguments, flags, or switches exist for the params passed"
35+
1836
it "can output a help message" do
1937
output = spy("output")
2038
full_command = described_class.new(

0 commit comments

Comments
 (0)