diff --git a/lib/vagrant/action/builder.rb b/lib/vagrant/action/builder.rb index 54f77a3e7..c467de445 100644 --- a/lib/vagrant/action/builder.rb +++ b/lib/vagrant/action/builder.rb @@ -31,15 +31,22 @@ module Vagrant @stack ||= [] end + # Returns a mergeable version of the builder. If `use` is called with + # the return value of this method, then the stack will merge, instead + # of being treated as a separate single middleware. + def mergeable + [:merge, self] + end + # Adds a middleware class to the middleware stack. Any additional # args and a block, if given, are saved and passed to the initializer # of the middleware. # # @param [Class] middleware The middleware class def use(middleware, *args, &block) - if middleware.kind_of?(Builder) + if middleware.kind_of?(Array) && middleware[0] == :merge # Merge in the other builder's stack into our own - self.stack.concat(middleware.stack) + self.stack.concat(middleware[1].stack) else self.stack << [middleware, args, block] end @@ -104,7 +111,23 @@ module Vagrant # middleware. items = items.collect do |item| klass, args, block = item - lambda { |app| klass.new(app, env, *args, &block) } + + lambda do |app| + if klass.is_a?(Class) + # A middleware klass which is to be instantiated with the + # app, env, and any arguments given + klass.new(app, env, *args, &block) + elsif klass.respond_to?(:call) + # Make it a lambda which calls the item then forwards + # up the chain + lambda do |e| + klass.call(e) + app.call(e) + end + else + raise "Invalid middleware: #{item.inspect}" + end + end end # Append the final step and convert into flattened call chain. diff --git a/test/vagrant/action/builder_test.rb b/test/vagrant/action/builder_test.rb index 5f71e7aac..ffac098fd 100644 --- a/test/vagrant/action/builder_test.rb +++ b/test/vagrant/action/builder_test.rb @@ -41,9 +41,26 @@ class ActionBuilderTest < Test::Unit::TestCase end @instance.use 1 - @instance.use other + @instance.use other.mergeable assert_equal 3, @instance.stack.length end + + should "not merge in another builder if not mergeable" do + other = @klass.new do + use 2 + use 3 + end + + @instance.use 1 + @instance.use other + assert_equal 2, @instance.stack.length + end + end + + context "mergeable" do + should "return the merge format with the builder" do + assert_equal [:merge, @instance], @instance.mergeable + end end context "inserting" do @@ -131,12 +148,29 @@ class ActionBuilderTest < Test::Unit::TestCase result = mock("result") env = {:a => :b} middleware = mock("middleware") + middleware.stubs(:is_a?).with(Class).returns(true) middleware.expects(:new).with(anything, env).returns(result) @instance.use middleware result = @instance.to_app(env) assert result.kind_of?(Vagrant::Action::ErrorHalt) end + should "make non-classes lambdas" do + env = Vagrant::Action::Environment.new(nil) + env.expects(:foo).once + + func = lambda { |x| x.foo } + @instance.use func + @instance.to_app(env).call(env) + end + + should "raise exception if given invalid middleware" do + @instance.use 7 + assert_raises(RuntimeError) { + @instance.to_app(nil) + } + end + # TODO: Better testing of this method end diff --git a/vagrant.gemspec b/vagrant.gemspec index 575dacca1..d0263a1f2 100644 --- a/vagrant.gemspec +++ b/vagrant.gemspec @@ -9,7 +9,7 @@ Gem::Specification.new do |s| s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= s.authors = ["Mitchell Hashimoto", "John Bender"] - s.date = %q{2010-07-05} + s.date = %q{2010-07-06} s.default_executable = %q{vagrant} s.description = %q{Vagrant is a tool for building and distributing virtualized development environments.} s.email = ["mitchell.hashimoto@gmail.com", "john.m.bender@gmail.com"] @@ -41,8 +41,10 @@ Gem::Specification.new do |s| "lib/vagrant/action/vm/boot.rb", "lib/vagrant/action/vm/check_guest_additions.rb", "lib/vagrant/action/vm/customize.rb", + "lib/vagrant/action/vm/destroy.rb", "lib/vagrant/action/vm/destroy_unused_network_interfaces.rb", "lib/vagrant/action/vm/forward_ports.rb", + "lib/vagrant/action/vm/halt.rb", "lib/vagrant/action/vm/import.rb", "lib/vagrant/action/vm/match_mac_address.rb", "lib/vagrant/action/vm/network.rb", @@ -135,8 +137,10 @@ Gem::Specification.new do |s| "test/vagrant/action/vm/boot_test.rb", "test/vagrant/action/vm/check_guest_additions_test.rb", "test/vagrant/action/vm/customize_test.rb", + "test/vagrant/action/vm/destroy_test.rb", "test/vagrant/action/vm/destroy_unused_network_interfaces_test.rb", "test/vagrant/action/vm/forward_ports_test.rb", + "test/vagrant/action/vm/halt_test.rb", "test/vagrant/action/vm/import_test.rb", "test/vagrant/action/vm/match_mac_address_test.rb", "test/vagrant/action/vm/network_test.rb", @@ -227,8 +231,10 @@ Gem::Specification.new do |s| "test/vagrant/action/vm/boot_test.rb", "test/vagrant/action/vm/check_guest_additions_test.rb", "test/vagrant/action/vm/customize_test.rb", + "test/vagrant/action/vm/destroy_test.rb", "test/vagrant/action/vm/destroy_unused_network_interfaces_test.rb", "test/vagrant/action/vm/forward_ports_test.rb", + "test/vagrant/action/vm/halt_test.rb", "test/vagrant/action/vm/import_test.rb", "test/vagrant/action/vm/match_mac_address_test.rb", "test/vagrant/action/vm/network_test.rb",