Commit 1abce18
Changed files (6)
spec
unit
lib/spank/container.rb
@@ -4,25 +4,31 @@ module Spank
@message = message
end
end
+
class Container
def initialize
@items = {}
register(:container) { self }
end
+
def register(key, &block)
component = Component.new(key, &block)
components_for(key).push(component)
component
end
+
def resolve(key)
instantiate(components_for(key).first, key)
end
+
def resolve_all(key)
components_for(key).map {|item| instantiate(item, key) }
end
+
def build(type)
try("I could not create: #{type}"){ build!(type) }
end
+
def build!(type)
constructor = type.instance_method('initialize')
parameters = constructor.parameters.map do |req, parameter|
@@ -37,10 +43,12 @@ module Spank
@items[key] = [] unless @items[key]
@items[key]
end
+
def instantiate(component, key)
raise ContainerError.new("#{key} is not a registered component.") unless component
component.create(self)
end
+
def try(error = nil, &lambda)
begin
lambda.call
lib/spank/interceptor_chain.rb
@@ -0,0 +1,13 @@
+ class InterceptorChain
+ def initialize(interceptors = [])
+ @interceptors = interceptors
+ end
+
+ def push(interceptor)
+ @interceptors.push(interceptor)
+ end
+
+ def each(&block)
+ @interceptors.each(&block)
+ end
+ end
lib/spank/interceptor_registration.rb
@@ -2,15 +2,23 @@ module Spank
class InterceptorRegistration
def initialize(method_symbol)
@method = method_symbol
+ @interceptors = []
end
def with(interceptor)
- @interceptor = interceptor
+ @interceptors.push(interceptor)
+ self
+ end
+
+ def and(interceptor)
+ with(interceptor)
end
def intercept(instance)
- proxy= Proxy.new(instance)
- proxy.add_interceptor(@method, @interceptor)
+ proxy = Proxy.new(instance)
+ @interceptors.each do |interceptor|
+ proxy.add_interceptor(@method, interceptor)
+ end
proxy
end
end
lib/spank/proxy.rb
@@ -1,11 +1,13 @@
module Spank
class Proxy
- def initialize(target)
+ def initialize(target, interceptor_chain = InterceptorChain.new)
@target = target
+ @interceptor_chain = interceptor_chain
end
def add_interceptor(method, interceptor)
- self.extend(create_module_for(method, interceptor))
+ @interceptor_chain.push(interceptor)
+ self.extend(create_module_for(method))
self
end
@@ -23,11 +25,13 @@ module Spank
end
end
- def create_module_for(method, interceptor)
+ def create_module_for(method)
Module.new do
define_method(method.to_sym) do |*args, &block|
invocation = create_invocation_for(method, args, block)
- interceptor.intercept(invocation)
+ @interceptor_chain.each do |interceptor|
+ interceptor.intercept(invocation)
+ end
invocation.result
end
end
lib/spank.rb
@@ -5,4 +5,5 @@ require 'spank/interceptor_registration.rb'
require 'spank/invocation.rb'
require 'spank/ioc.rb'
require 'spank/proxy.rb'
-require "spank/version"
+require 'spank/interceptor_chain'
+require 'spank/version'
spec/unit/container_spec.rb
@@ -108,9 +108,13 @@ module Spank
end
end
- context "when registering an interceptor" do
+ context "when registering interceptors" do
class TestInterceptor
- attr_reader :called
+ attr_reader :called, :name
+ def initialize(name)
+ @name = name
+ @called = false
+ end
def intercept(invocation)
@called = true
invocation.proceed
@@ -126,17 +130,23 @@ module Spank
end
let(:command) { TestCommand.new }
- let(:interceptor) { TestInterceptor.new }
+ let(:interceptor) { TestInterceptor.new("first") }
+ let(:other_interceptor) { TestInterceptor.new("second") }
before :each do
- sut.register(:command) { command }.intercept(:run).with(interceptor)
+ sut.register(:command) { command }.intercept(:run).with(interceptor).and(other_interceptor)
+ sut.register(:single_command) { command }.intercept(:run).with(interceptor)
sut.resolve(:command).run("hi")
end
- it "should allow the interceptor to intercept calls to the target" do
+ it "should allow the first interceptor to intercept calls to the target" do
interceptor.called.should be_true
end
+ it "should allow the second interceptor to intercept calls to the target" do
+ other_interceptor.called.should be_true
+ end
+
it "should forward the args to the command" do
command.called.should be_true
command.received.should == ['hi']