Builder fully tested
This commit is contained in:
parent
6eefc8e874
commit
c88adbc0f7
|
@ -1,26 +1,50 @@
|
||||||
module Vagrant
|
module Vagrant
|
||||||
class Action
|
class Action
|
||||||
|
# Action builder which provides a nice DSL for building up
|
||||||
|
# a middleware sequence for Vagrant actions. This code is based
|
||||||
|
# heavily off of `Rack::Builder` and `ActionDispatch::MiddlewareStack`
|
||||||
|
# in Rack and Rails, respectively.
|
||||||
class Builder
|
class Builder
|
||||||
|
# Initializes the builder. An optional block can be passed which
|
||||||
|
# will be evaluated in the context of the instance.
|
||||||
def initialize(&block)
|
def initialize(&block)
|
||||||
instance_eval(&block) if block_given?
|
instance_eval(&block) if block_given?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns the current stack of middlewares. You probably won't
|
||||||
|
# need to use this directly, and its recommended that you don't.
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
def stack
|
def stack
|
||||||
@stack ||= []
|
@stack ||= []
|
||||||
end
|
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)
|
def use(middleware, *args, &block)
|
||||||
stack << [middleware, args, block]
|
stack << [middleware, args, block]
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_app
|
# Converts the builder stack to a runnable action sequence.
|
||||||
inner = @ins.last
|
#
|
||||||
|
# @param [Vagrant::Action::Environment] env The action environment
|
||||||
|
# @return [Object] A callable object
|
||||||
|
def to_app(env)
|
||||||
|
items = stack.collect do |item|
|
||||||
|
klass, args, block = item
|
||||||
|
lambda { |app| klass.new(app, env, *args, &block) }
|
||||||
|
end
|
||||||
|
|
||||||
@ins[0...-1].reverse.inject(inner) { |a,e| e.call(a) }
|
items << lambda { |env| } # The final step, which simply returns
|
||||||
|
items[0...-1].reverse.inject(items.last) { |a,e| e.call(a) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Runs the builder stack with the given environment.
|
||||||
def call(env)
|
def call(env)
|
||||||
to_app.call(env)
|
to_app(env).call(env)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
module Vagrant
|
||||||
|
class Action
|
||||||
|
# Represents an action environment which is what is passed
|
||||||
|
# to the `call` method of each action. This environment contains
|
||||||
|
# some helper methods for accessing the environment as well
|
||||||
|
# as being a hash, to store any additional options.
|
||||||
|
class Environment < Hash
|
||||||
|
# The {Vagrant::Environment} object represented by this
|
||||||
|
# action environment.
|
||||||
|
attr_reader :env
|
||||||
|
|
||||||
|
def new(env)
|
||||||
|
@env = env
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,22 +0,0 @@
|
||||||
module Vagrant
|
|
||||||
module Actions
|
|
||||||
# Represents a middleware stack for Vagrant actions. Vagrant
|
|
||||||
# actions are created and can be extended with middlewares.
|
|
||||||
#
|
|
||||||
# The exact nature of how this will work is not set in stone.
|
|
||||||
class MiddlewareStack
|
|
||||||
# Initializes the middleware stack with the given name.
|
|
||||||
def initialize(key)
|
|
||||||
@stack = []
|
|
||||||
end
|
|
||||||
|
|
||||||
def use(klass)
|
|
||||||
@stack << klass
|
|
||||||
end
|
|
||||||
|
|
||||||
def run(endpoint)
|
|
||||||
@stack << endpoint
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -36,7 +36,41 @@ class ActionBuilderTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
context "converting to an app" do
|
context "converting to an app" do
|
||||||
|
should "initialize each middleware with app and env" do
|
||||||
|
# TODO: better testing of this method... somehow
|
||||||
|
|
||||||
|
result = mock("result")
|
||||||
|
env = {:a => :b}
|
||||||
|
middleware = mock("middleware")
|
||||||
|
middleware.expects(:new).with(anything, env).returns(result)
|
||||||
|
@instance.use middleware
|
||||||
|
assert_equal result, @instance.to_app(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "calling" do
|
||||||
|
def mock_middleware
|
||||||
|
middleware = Class.new do
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "convert to an app then call with the env" do
|
||||||
|
mw = mock_middleware
|
||||||
|
mw.any_instance.expects(:call).with() do |env|
|
||||||
|
assert env.has_key?(:key)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
@instance.use(mw)
|
||||||
|
@instance.call(:key => :value)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||||
|
|
||||||
|
class ActionEnvironmentTest < Test::Unit::TestCase
|
||||||
|
setup do
|
||||||
|
@klass = Vagrant::Action::Environment
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in New Issue