Commands can now be registered as subcommands (similar to how config works)
This commit is contained in:
parent
83da66ee91
commit
aec05eff0d
|
@ -21,18 +21,7 @@ module Vagrant
|
||||||
# Execute a subcommand with the given name and args. This method properly
|
# Execute a subcommand with the given name and args. This method properly
|
||||||
# finds the subcommand, instantiates it, and executes.
|
# finds the subcommand, instantiates it, and executes.
|
||||||
def subcommand(name, *args)
|
def subcommand(name, *args)
|
||||||
command_klass = Commands.const_get(camelize(name))
|
Commands::Base.dispatch(env, name, *args)
|
||||||
command = command_klass.new(env)
|
|
||||||
command.execute(args)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Camel-case a string.
|
|
||||||
def camelize(string)
|
|
||||||
parts = string.to_s.split(/[^a-z0-9]/).collect do |part|
|
|
||||||
part.capitalize
|
|
||||||
end
|
|
||||||
|
|
||||||
parts.join("")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -7,6 +7,61 @@ module Vagrant
|
||||||
class Base
|
class Base
|
||||||
attr_reader :env
|
attr_reader :env
|
||||||
|
|
||||||
|
class <<self
|
||||||
|
# Contains the list of registered subcommands. The registered commands are
|
||||||
|
# stored in a hash table and are therefore unordered.
|
||||||
|
#
|
||||||
|
# @return [Hash]
|
||||||
|
def subcommands
|
||||||
|
@subcommands ||= {}
|
||||||
|
end
|
||||||
|
|
||||||
|
# Registers a command with `vagrant`. This method allows 3rd parties to
|
||||||
|
# dynamically add new commands to the `vagrant` command, allowing plugins
|
||||||
|
# to act as 1st class citizens within vagrant.
|
||||||
|
#
|
||||||
|
# @param [String] key The subcommand which will invoke the registered command.
|
||||||
|
# @param [Class] klass. The subcommand class (a subclass of {Base})
|
||||||
|
def subcommand(key, klass)
|
||||||
|
subcommands[key] = klass
|
||||||
|
end
|
||||||
|
|
||||||
|
# Dispatches a subcommand to the proper registered command. Otherwise, it
|
||||||
|
# prints a help message.
|
||||||
|
def dispatch(env, name, *args)
|
||||||
|
klass = subcommands[name]
|
||||||
|
if klass.nil?
|
||||||
|
puts_help
|
||||||
|
return # For tests
|
||||||
|
end
|
||||||
|
|
||||||
|
command = klass.new(env)
|
||||||
|
command.execute(args)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Prints out the list of supported commands and their descriptions (if
|
||||||
|
# available) then exits.
|
||||||
|
def puts_help
|
||||||
|
puts "Usage: vagrant SUBCOMMAND ...\n\n"
|
||||||
|
|
||||||
|
puts "Supported commands:"
|
||||||
|
subcommands.each do |key, klass|
|
||||||
|
puts "#{' ' * 4}#{key.ljust(20)}#{klass.description}"
|
||||||
|
end
|
||||||
|
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
|
||||||
|
# Sets or reads the description, depending on if the value is set in the
|
||||||
|
# parameter.
|
||||||
|
def description(value=nil)
|
||||||
|
@description ||= ''
|
||||||
|
|
||||||
|
return @description if value.nil?
|
||||||
|
@description = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def initialize(env)
|
def initialize(env)
|
||||||
@env = env
|
@env = env
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
module Vagrant
|
module Vagrant
|
||||||
class Commands
|
class Commands
|
||||||
class Init < Base
|
class Init < Base
|
||||||
|
Base.subcommand "init", self
|
||||||
|
description "Initializes current folder for Vagrant usage"
|
||||||
|
|
||||||
def execute(args)
|
def execute(args)
|
||||||
parse_options(args) do |opts, options|
|
parse_options(args) do |opts, options|
|
||||||
opts.banner = "Usage: vagrant init [name]"
|
opts.banner = "Usage: vagrant init [name]"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
puts "HEY"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -43,28 +43,10 @@ class CommandTest < Test::Unit::TestCase
|
||||||
@instance.stubs(:camelize).with(@raw_name).returns(@name)
|
@instance.stubs(:camelize).with(@raw_name).returns(@name)
|
||||||
end
|
end
|
||||||
|
|
||||||
should "send the command to the proper class" do
|
should "send the env, name, and args to the base class" do
|
||||||
klass = mock("klass")
|
|
||||||
instance = mock("instance")
|
|
||||||
args = [1,2,3]
|
args = [1,2,3]
|
||||||
Vagrant::Commands.expects(:const_get).with(@name).returns(klass)
|
Vagrant::Commands::Base.expects(:dispatch).with(@env, @name, *args)
|
||||||
klass.expects(:new).with(@env).returns(instance)
|
@instance.subcommand(@name, *args)
|
||||||
instance.expects(:execute).with(args)
|
|
||||||
|
|
||||||
@instance.subcommand(@raw_name, *args)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "camelizing" do
|
|
||||||
should "camel case a string" do
|
|
||||||
tests = {
|
|
||||||
"foo_bar_baz" => "FooBarBaz",
|
|
||||||
"ssh-config" => "SshConfig"
|
|
||||||
}
|
|
||||||
|
|
||||||
tests.each do |test, expected|
|
|
||||||
assert_equal expected, @instance.camelize(test)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,6 +13,51 @@ class CommandsBastTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "class methods" do
|
||||||
|
setup do
|
||||||
|
@klass.subcommands.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
context "registering commands" do
|
||||||
|
should "register commands" do
|
||||||
|
klass = mock("klass")
|
||||||
|
@klass.subcommand("init", klass)
|
||||||
|
assert_equal klass, @klass.subcommands["init"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "dispatching to subcommands" do
|
||||||
|
setup do
|
||||||
|
@command_klass = mock("klass")
|
||||||
|
@name = "init"
|
||||||
|
@klass.subcommand(@name, @command_klass)
|
||||||
|
|
||||||
|
@args = [1,2,3]
|
||||||
|
end
|
||||||
|
|
||||||
|
should "instantiate and execute on registered subcommands" do
|
||||||
|
instance = mock("instance")
|
||||||
|
@command_klass.expects(:new).with(@env).returns(instance)
|
||||||
|
instance.expects(:execute).with(@args)
|
||||||
|
|
||||||
|
@klass.dispatch(@env, @name, *@args)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "print help if command doesn't exist" do
|
||||||
|
@klass.expects(:puts_help).once
|
||||||
|
@klass.dispatch(@env, "#{@name}foo")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "descriptions" do
|
||||||
|
should "be able to set description" do
|
||||||
|
description = "The lazy fox yada yada"
|
||||||
|
@klass.description(description)
|
||||||
|
assert_equal description, @klass.description
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "instance methods" do
|
context "instance methods" do
|
||||||
setup do
|
setup do
|
||||||
@env = mock_environment
|
@env = mock_environment
|
||||||
|
|
Loading…
Reference in New Issue