Base command now recursively dispatches, allowing for arbitrarily complex commands such as `vagrant a b c`

This commit is contained in:
Mitchell Hashimoto 2010-04-13 13:53:27 -07:00
parent aec05eff0d
commit bb0d3f7f93
3 changed files with 35 additions and 21 deletions

View File

@ -28,15 +28,21 @@ module Vagrant
# Dispatches a subcommand to the proper registered command. Otherwise, it # Dispatches a subcommand to the proper registered command. Otherwise, it
# prints a help message. # prints a help message.
def dispatch(env, name, *args) def dispatch(env, *args)
klass = subcommands[name] klass = subcommands[args[0]] unless args.empty?
if klass.nil? if klass.nil?
puts_help # Run _this_ command!
return # For tests command = self.new(env)
command.execute(args)
return
end end
command = klass.new(env) # Shift off the front arg, since we just consumed it in finding the
command.execute(args) # subcommand.
args.shift
# Dispatch to the next class
klass.dispatch(env, *args)
end end
# Prints out the list of supported commands and their descriptions (if # Prints out the list of supported commands and their descriptions (if
@ -71,7 +77,9 @@ module Vagrant
# executed. The `args` parameter is an array of parameters to the # executed. The `args` parameter is an array of parameters to the
# command (similar to ARGV) # command (similar to ARGV)
def execute(args) def execute(args)
raise "Subcommands should implement the execute method properly." # Just print out the help, since this top-level command does nothing
# on its own
self.class.puts_help
end end
# Parse options out of the command-line. This method uses `optparse` # Parse options out of the command-line. This method uses `optparse`
@ -90,10 +98,20 @@ module Vagrant
show_help show_help
end end
# Gets the description of the command. This is similar grabbed from the
# class level.
def description
self.class.description
end
# Prints the help for the given command. Prior to calling this method, # Prints the help for the given command. Prior to calling this method,
# {#parse_options} must be called or a nilerror will be raised. This # {#parse_options} must be called or a nilerror will be raised. This
# is by design. # is by design.
def show_help def show_help
if !description.empty?
puts "Description: #{description}"
end
puts @parser.help puts @parser.help
exit exit
end end

View File

@ -9,7 +9,7 @@ module Vagrant
opts.banner = "Usage: vagrant init [name]" opts.banner = "Usage: vagrant init [name]"
end end
puts "HEY" show_help
end end
end end
end end

View File

@ -15,6 +15,7 @@ class CommandsBastTest < Test::Unit::TestCase
context "class methods" do context "class methods" do
setup do setup do
@env = mock_environment
@klass.subcommands.clear @klass.subcommands.clear
end end
@ -35,17 +36,16 @@ class CommandsBastTest < Test::Unit::TestCase
@args = [1,2,3] @args = [1,2,3]
end end
should "instantiate and execute on registered subcommands" do should "call dispatch on child if subcommand is found" do
instance = mock("instance") @command_klass.expects(:dispatch).with(@env, *@args)
@command_klass.expects(:new).with(@env).returns(instance)
instance.expects(:execute).with(@args)
@klass.dispatch(@env, @name, *@args) @klass.dispatch(@env, @name, *@args)
end end
should "print help if command doesn't exist" do should "instantiate and execute when no subcommand is found" do
@klass.expects(:puts_help).once instance = mock("instance")
@klass.dispatch(@env, "#{@name}foo") @klass.expects(:new).with(@env).returns(instance)
instance.expects(:execute).with(@args)
@klass.dispatch(@env, *@args)
end end
end end
@ -65,11 +65,7 @@ class CommandsBastTest < Test::Unit::TestCase
end end
context "executing" do context "executing" do
should "raise an error if called (since not a subclass)" do # TODO
assert_raises(RuntimeError) {
@instance.execute([])
}
end
end end
context "parsing options" do context "parsing options" do