diff --git a/.yardopts b/.yardopts new file mode 100644 index 00000000000..a4541bead9e --- /dev/null +++ b/.yardopts @@ -0,0 +1 @@ +-m markdown diff --git a/Gemfile b/Gemfile index 4da9e50bbca..a2fbe46a981 100644 --- a/Gemfile +++ b/Gemfile @@ -12,7 +12,10 @@ group :test do gem "rake" gem "contest", ">= 0.1.2" gem "mocha" - gem "yard" + + # For documentation + gem "yard", "~> 0.6.1" + gem "bluecloth" platforms :mri_18 do gem "ruby-debug" diff --git a/Gemfile.lock b/Gemfile.lock index 8dd69ba24f3..41a32beb87b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -24,6 +24,7 @@ GEM specs: abstract (1.0.0) archive-tar-minitar (0.5.2) + bluecloth (2.0.7) columnize (0.3.1) contest (0.1.2) erubis (2.6.6) @@ -64,6 +65,7 @@ PLATFORMS ruby DEPENDENCIES + bluecloth contest (>= 0.1.2) mocha rake @@ -71,4 +73,4 @@ DEPENDENCIES ruby-debug19 vagrant! virtualbox! - yard + yard (~> 0.6.1) diff --git a/lib/vagrant/box.rb b/lib/vagrant/box.rb index 437e05fc98b..af5d7591afa 100644 --- a/lib/vagrant/box.rb +++ b/lib/vagrant/box.rb @@ -4,7 +4,7 @@ module Vagrant # virtual machine, at the least. They are created with `vagrant package` # and may contain additional files if specified by the creator. This # class serves to help manage these boxes, although most of the logic - # is kicked out to actions. + # is kicked out to middlewares. class Box # The name of the box. attr_accessor :name @@ -46,6 +46,8 @@ def initialize(env=nil, name=nil) # virtual machine file which contains specifications of the exported # virtual machine this box contains. # + # This will only be valid once the box is imported. + # # @return [String] def ovf_file directory.join(env.config.vm.box_ovf) @@ -53,12 +55,12 @@ def ovf_file # Begins the process of adding a box to the vagrant installation. This # method requires that `name` and `uri` be set. The logic of this method - # is kicked out to the {Actions::Box::Add add box} action. + # is kicked out to the `box_add` registered middleware. def add env.actions.run(:box_add, { "box" => self }) end - # Begins the process of destroying this box. + # Begins the process of destroying this box. This cannot be undone! def destroy env.actions.run(:box_remove, { "box" => self }) end @@ -69,14 +71,16 @@ def repackage(options=nil) end # Returns the directory to the location of this boxes content in the local - # filesystem. + # filesystem. Note that if the box isn't imported yet, then the path may not + # yet exist, but still represents where the box will be imported to. # # @return [String] def directory env.boxes_path.join(name) end - # Implemented for comparison with other boxes. + # Implemented for comparison with other boxes. Comparison is implemented + # by simply comparing name. def <=>(other) return super if !other.is_a?(self.class) name <=> other.name diff --git a/lib/vagrant/cli.rb b/lib/vagrant/cli.rb index db0f4fec628..40decec4cb6 100644 --- a/lib/vagrant/cli.rb +++ b/lib/vagrant/cli.rb @@ -4,9 +4,32 @@ module Vagrant # Entrypoint for the Vagrant CLI. This class should never be # initialized directly (like a typical Thor class). Instead, # use {Environment#cli} to invoke the CLI. + # + # # Defining Custom CLI Commands + # + # If you're looking to define custom CLI commands, then look at + # one of the two following classes: + # + # * {Command::Base} - Implementing a single command such as `vagrant up`, e.g. + # one without subcommands. Also take a look at {Command::NamedBase}. + # * {Command::GroupBase} - Implementing a command with subcommands, such as + # `vagrant box`, which has the `list`, `add`, etc. subcommands. + # + # The above linked classes contain the main documentation for each + # type of command. class CLI < Thor # Registers the given class with the CLI so it can be accessed. - # The class must be a subclass of either {Command} or {GroupCommand}. + # The class must be a subclass of either {Command::Base} or {Command::GroupBase}. + # Don't call this method directly, instead call the {Command::Base.register} + # or {Command::GroupBase.register} methods. + # + # @param [Class] klass Command class + # @param [String] name Command name, accessed at `vagrant NAME` + # @param [String] usage Command usage, such as "vagrant NAME [--option]" + # @param [String] description Description of the command shown during the + # command listing. + # @param [Hash] opts Other options (not gone into detail here, look at + # the source instead). def self.register(klass, name, usage, description, opts=nil) opts ||= {} diff --git a/lib/vagrant/command/base.rb b/lib/vagrant/command/base.rb index 9ccf4c3d5c7..c2d8b44040d 100644 --- a/lib/vagrant/command/base.rb +++ b/lib/vagrant/command/base.rb @@ -3,7 +3,7 @@ module Vagrant module Command - # A CLI command is the subclass for all commands which are single + # A {Base} is the superclass for all commands which are single # commands, e.g. `vagrant init`, `vagrant up`. Not commands like # `vagrant box add`. For commands which have more subcommands, use # a {GroupBase}. @@ -15,7 +15,50 @@ module Command # the command is invoked, it must be made `protected` or `private`. # # The best way to get examples of how to create your own command is to - # view the various Vagrant commands, which are relatively simple. + # view the various Vagrant commands, which are relatively simple, and + # can be found in the Vagrant source tree at `lib/vagrant/command/`. + # + # # Defining a New Command + # + # To define a new single command, create a new class which inherits + # from this class, then call {register} to register the command. That's + # it! When the command is invoked, _all public methods_ will be called. + # Below is an example `SayHello` class: + # + # class SayHello < Vagrant::Command::Base + # register "hello", "Says hello" + # + # def hello + # env.ui.info "Hello" + # end + # end + # + # In this case, the above class is invokable via `vagrant hello`. To give + # this a try, just copy and paste the above into a Vagrantfile somewhere. + # The command will be available for that project! + # + # Also note that the above example uses `env.ui` to output. It is recommended + # you use this instead of raw "puts" since it is configurable and provides + # additional functionality, such as colors and asking for user input. See + # the {UI} class for more information. + # + # ## Defining Command-line Options + # + # Most command line actions won't be as simple as `vagrant hello`, and will + # probably require parameters or switches. Luckily, Thor makes adding these + # easy: + # + # class SayHello < Vagrant::Command::Base + # register "hello", "Says hello" + # argument :name, :type => :string + # + # def hello + # env.ui.info "Hello, #{name}" + # end + # end + # + # Then, the above can be invoked with `vagrant hello Mitchell` which would + # output "Hello, Mitchell" class Base < Thor::Group include Thor::Actions include Helpers diff --git a/lib/vagrant/config.rb b/lib/vagrant/config.rb index 54b76766c1b..a59402c14d5 100644 --- a/lib/vagrant/config.rb +++ b/lib/vagrant/config.rb @@ -2,8 +2,27 @@ require 'vagrant/config/error_recorder' module Vagrant - # The config class is responsible for loading Vagrant configurations - # (usually through Vagrantfiles). + # The config class is responsible for loading Vagrant configurations, which + # are usually found in Vagrantfiles but may also be procs. The loading is done + # by specifying a queue of files or procs that are for configuration, and then + # executing them. The config loader will run each item in the queue, so that + # configuration from later items overwrite that from earlier items. This is how + # Vagrant "scoping" of Vagranfiles is implemented. + # + # If you're looking to create your own configuration classes, see {Base}. + # + # # Loading Configuration Files + # + # If you are in fact looking to load configuration files, then this is the + # class you are looking for. Loading configuration is quite easy. The following + # example assumes `env` is already a loaded instance of {Environment}: + # + # config = Vagrant::Config.new(env) + # config.queue << "/path/to/some/Vagrantfile" + # result = config.load! + # + # p "Your box is: #{result.vm.box}" + # class Config extend Util::StackedProcRunner @@ -12,6 +31,12 @@ class Config attr_reader :queue class << self + # Resets the current loaded config object to the specified environment. + # This clears the proc stack and initializes a new {Top} for loading. + # This method shouldn't be called directly, instead use an instance of this + # class for config loading. + # + # @param [Environment] env def reset!(env=nil) @@config = nil proc_stack.clear @@ -20,14 +45,29 @@ def reset!(env=nil) config(env) end + # Returns the current {Top} configuration object. While this is still + # here for implementation purposes, it shouldn't be called directly. Instead, + # use an instance of this class. def config(env=nil) @@config ||= Config::Top.new(env) end + # Adds the given proc/block to the stack of config procs which are all + # run later on a single config object. This is the main way to configure + # Vagrant, and is how all Vagrantfiles are formatted: + # + # Vagrant::Config.run do |config| + # # ... + # end + # def run(&block) push_proc(&block) end + # Executes all the config procs onto the currently loaded {Top} object, + # and returns the final configured object. This also validates the + # configuration by calling {Top#validate!} on every configuration + # class. def execute!(config_object=nil) config_object ||= config @@ -37,6 +77,10 @@ def execute!(config_object=nil) end end + # Initialize a {Config} object for the given {Environment}. + # + # @param [Environment] env Environment which config object will be part + # of. def initialize(env) @env = env @queue = [] @@ -65,14 +109,24 @@ def load! end class Config + # This class is the "top" configure class, which handles registering + # other configuration classes as well as validation of all configured + # classes. This is the object which is returned by {Environment#config} + # and has accessors to all other configuration classes. + # + # If you're looking to create your own configuration class, see {Base}. class Top < Base @@configures = [] class << self + # The list of registered configuration classes as well as the key + # they're registered under. def configures_list @@configures ||= [] end + # Registers a configuration class with the given key. This method shouldn't + # be called. Instead, inherit from {Base} and call {Base.configures}. def configures(key, klass) configures_list << [key, klass] attr_reader key.to_sym @@ -90,7 +144,10 @@ def initialize(env=nil) end # Validates the configuration classes of this instance and raises an - # exception if they are invalid. + # exception if they are invalid. If you are implementing a custom configuration + # class, the method you want to implement is {Base#validate}. This is + # the method that checks all the validation, not one which defines + # validation rules. def validate! # Validate each of the configured classes and store the results into # a hash.