chickadee 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/chickadee.gemspec +2 -2
- data/lib/chickadee/dispatcher.rb +32 -0
- data/lib/chickadee/dispatchers/command_dispatcher.rb +19 -0
- data/lib/chickadee/dispatchers/dispatcher_manager.rb +47 -0
- data/lib/chickadee/dispatchers/event_dispatcher.rb +22 -0
- data/lib/chickadee/dispatchers/handler_chain_struct.rb +17 -0
- data/lib/chickadee/dispatchers/message_bus.rb +65 -0
- data/lib/chickadee/dispatchers/query_dispatcher.rb +18 -0
- data/lib/chickadee/dispatchers/request_dispatcher.rb +21 -0
- data/lib/chickadee/exceptions.rb +2 -1
- data/lib/chickadee/requests/command.rb +4 -0
- data/lib/chickadee/requests/event.rb +4 -0
- data/lib/chickadee/requests/query.rb +4 -0
- data/lib/chickadee/{request.rb → requests/request.rb} +5 -1
- data/lib/chickadee/version.rb +1 -1
- data/lib/chickadee.rb +12 -7
- data/spec/dispatchers/command_dispatcher_spec.rb +55 -0
- data/spec/dispatchers/event_dispatcher_spec.rb +70 -0
- data/spec/dispatchers/handler_chain_struct_spec.rb +30 -0
- data/spec/dispatchers/message_bus_spec.rb +73 -0
- data/spec/dispatchers/query_dispatcher_spec.rb +57 -0
- data/spec/{command_spec.rb → requests/command_spec.rb} +1 -0
- data/spec/requests/event_spec.rb +12 -0
- data/spec/{query_spec.rb → requests/query_spec.rb} +1 -0
- metadata +32 -21
- data/lib/chickadee/application.rb +0 -27
- data/lib/chickadee/command.rb +0 -10
- data/lib/chickadee/handler.rb +0 -7
- data/lib/chickadee/query.rb +0 -10
- data/lib/chickadee/registry.rb +0 -19
- data/lib/chickadee/router.rb +0 -78
- data/spec/chickadee_spec.rb +0 -128
- data/spec/registry_spec.rb +0 -37
- data/spec/router_spec.rb +0 -89
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c94ac31b90bdc338d7fde56dcc3197cd5cc3dda
|
4
|
+
data.tar.gz: 0114a62df6b8770ed3e43422ad77aef00f48ba64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad5ee648a68d9274a1dbab7ca17208c266787f2e3eef24fba786ab3837ad7670555deabd2d4cfd39e05ff6a452fb47769e613d9f98f8deeb5e05604a489aa814
|
7
|
+
data.tar.gz: 2d3b5eaa405012bc49a44f2ac29a309cbecbf8ed7c52318dd7e3c22b50a0c94b5504893a8150c15b4a8e72bf08cbf22cad56e1159b558470169be58dd6391340
|
data/chickadee.gemspec
CHANGED
@@ -18,9 +18,9 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "ioc", "~>
|
21
|
+
spec.add_dependency "ioc", "~> 2.1.0"
|
22
22
|
|
23
23
|
spec.add_development_dependency "bundler", "~> 1.3"
|
24
24
|
spec.add_development_dependency "rake"
|
25
25
|
spec.add_development_dependency "mocha", "~> 0.14.0"
|
26
|
-
end
|
26
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Chickadee
|
2
|
+
class Dispatcher
|
3
|
+
def self.install(*installers)
|
4
|
+
[*installers].inject(new) do |d, installer|
|
5
|
+
installer.install(d)
|
6
|
+
d
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@container = Container.new
|
12
|
+
@dispatcher_manager = DispatcherManager.new(
|
13
|
+
CommandDispatcher.new(@container),
|
14
|
+
QueryDispatcher.new(@container),
|
15
|
+
EventDispatcher.new(@container),
|
16
|
+
)
|
17
|
+
@container.register(:event_dispatcher, @dispatcher_manager.event_dispatcher, :as => :instance)
|
18
|
+
end
|
19
|
+
|
20
|
+
def register(*args)
|
21
|
+
@container.register(*args)
|
22
|
+
end
|
23
|
+
|
24
|
+
def map(*args)
|
25
|
+
@dispatcher_manager.map(*args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def dispatch(*args)
|
29
|
+
@dispatcher_manager.dispatch(*args)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Chickadee
|
2
|
+
class CommandDispatcher < RequestDispatcher
|
3
|
+
def map(request_key, *handlers)
|
4
|
+
raise(DispatcherError, "Command already mapped: #{request_key}") if bus.topic_exists?(request_key)
|
5
|
+
bus.subscribe(request_key) {|req| resolve_handler_chain(*handlers).handle(req)}
|
6
|
+
end
|
7
|
+
|
8
|
+
def dispatch(request)
|
9
|
+
bus.publish(request.class, request)
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def bus
|
16
|
+
@bus ||= MessageBus.new
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Chickadee
|
2
|
+
class DispatcherManager
|
3
|
+
|
4
|
+
attr_reader :command_dispatcher, :query_dispatcher, :event_dispatcher
|
5
|
+
|
6
|
+
def initialize(container, command_dispatcher, query_dispatcher, event_dispatcher)
|
7
|
+
@container = container
|
8
|
+
@command_dispatcher = command_dispatcher
|
9
|
+
@event_dispatcher = event_dispatcher
|
10
|
+
@query_dispatcher = query_dispatcher
|
11
|
+
end
|
12
|
+
|
13
|
+
def map(request_key, *handlers)
|
14
|
+
send("map_#{request_key.type}", request_key, *handlers)
|
15
|
+
end
|
16
|
+
|
17
|
+
def dispatch(request)
|
18
|
+
send("dispatch_#{request.class.type}", request)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def map_command(*args)
|
24
|
+
@command_dispatcher.map(*args)
|
25
|
+
end
|
26
|
+
|
27
|
+
def map_query(*args)
|
28
|
+
@query_dispatcher.map(*args)
|
29
|
+
end
|
30
|
+
|
31
|
+
def map_event(*args)
|
32
|
+
@event_dispatcher.map(*args)
|
33
|
+
end
|
34
|
+
|
35
|
+
def dispatch_command(*args)
|
36
|
+
@command_dispatcher.dispatch(*args)
|
37
|
+
end
|
38
|
+
|
39
|
+
def dispatch_query(*args)
|
40
|
+
@query_dispatcher.dispatch(*args)
|
41
|
+
end
|
42
|
+
|
43
|
+
def dispatch_event(*args)
|
44
|
+
@event_dispatcher.dispatch(*args)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Chickadee
|
2
|
+
class EventDispatcher < RequestDispatcher
|
3
|
+
def map(request_key, *handlers)
|
4
|
+
bus.subscribe(request_key) {|req| resolve_handler_chain(*handlers).handle(req)}
|
5
|
+
end
|
6
|
+
|
7
|
+
def dispatch(request)
|
8
|
+
bus.publish(request.class, request)
|
9
|
+
nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def raise(*args)
|
13
|
+
dispatch(*args)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def bus
|
19
|
+
@bus ||= MessageBus.new
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Chickadee
|
2
|
+
class HandlerChainStruct
|
3
|
+
def self.new(*parameter_names, &block)
|
4
|
+
klass = Class.new(&block)
|
5
|
+
klass.class_eval <<-EOT, __FILE__, __LINE__ + 1
|
6
|
+
def initialize(#{parameter_names.map(&:to_s).join(", ")}) # def initialize(user_repo, session_repo)
|
7
|
+
@handlers = [#{parameter_names.map(&:to_s).join(", ")}] # @handlers = [user_repo, session_repo]
|
8
|
+
end # end
|
9
|
+
|
10
|
+
def handle(request)
|
11
|
+
@handlers.map {|h| h.handle(request)}.last
|
12
|
+
end
|
13
|
+
EOT
|
14
|
+
klass
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Chickadee
|
2
|
+
class MessageBus
|
3
|
+
class Topic
|
4
|
+
attr_reader :subscribers
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@subscribers = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def subscribe(obj)
|
11
|
+
@subscribers << obj
|
12
|
+
end
|
13
|
+
|
14
|
+
def unsubscribe(subscriber_id)
|
15
|
+
@subscribers.delete_if{|subscriber| subscriber.id == subscriber_id}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Subscriber
|
20
|
+
attr_reader :id
|
21
|
+
|
22
|
+
def initialize(id, &block)
|
23
|
+
@id = id
|
24
|
+
@block = block
|
25
|
+
end
|
26
|
+
|
27
|
+
def call(*args)
|
28
|
+
@block.call(*args)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@topics = {}
|
34
|
+
@subscriber_id = -1
|
35
|
+
end
|
36
|
+
|
37
|
+
def subscribe(topic_key, &block)
|
38
|
+
subscriber = Subscriber.new(next_subscriber_id, &block)
|
39
|
+
get_topic(topic_key).subscribe(subscriber)
|
40
|
+
subscriber.id
|
41
|
+
end
|
42
|
+
|
43
|
+
def unsubscribe(subscriber_id)
|
44
|
+
@topics.each {|topic_key, topic| topic.unsubscribe(subscriber_id)}
|
45
|
+
end
|
46
|
+
|
47
|
+
def publish(topic_key, *args)
|
48
|
+
get_topic(topic_key).subscribers.each {|s| s.call(*args)}
|
49
|
+
end
|
50
|
+
|
51
|
+
def topic_exists?(key)
|
52
|
+
@topics.keys.include?(key)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def get_topic(topic_key)
|
58
|
+
@topics[topic_key] ||= Topic.new
|
59
|
+
end
|
60
|
+
|
61
|
+
def next_subscriber_id
|
62
|
+
@subscriber_id = @subscriber_id + 1
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Chickadee
|
2
|
+
class QueryDispatcher < RequestDispatcher
|
3
|
+
def map(request_key, *handlers)
|
4
|
+
raise(DispatcherError, "Query already mapped: #{request_key}") if cache.key?(request_key)
|
5
|
+
cache[request_key] = Proc.new{|req| resolve_handler_chain(*handlers).handle(req)}
|
6
|
+
end
|
7
|
+
|
8
|
+
def dispatch(request)
|
9
|
+
cache[request.class].call(request)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def cache
|
15
|
+
@cache ||= {}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Chickadee
|
2
|
+
class RequestDispatcher
|
3
|
+
def initialize(container)
|
4
|
+
@container = container
|
5
|
+
end
|
6
|
+
|
7
|
+
def map(request_key, *handlers)
|
8
|
+
raise(NotImplementedError)
|
9
|
+
end
|
10
|
+
|
11
|
+
def dispatch(request)
|
12
|
+
raise(NotImplementedError)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def resolve_handler_chain(*handlers)
|
18
|
+
@container.resolve_anonymous(HandlerChainStruct.new(*handlers))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/chickadee/exceptions.rb
CHANGED
data/lib/chickadee/version.rb
CHANGED
data/lib/chickadee.rb
CHANGED
@@ -2,13 +2,18 @@ require 'ioc'
|
|
2
2
|
require 'chickadee/version'
|
3
3
|
require 'chickadee/exceptions'
|
4
4
|
require 'chickadee/container'
|
5
|
-
require 'chickadee/
|
6
|
-
require 'chickadee/
|
7
|
-
require 'chickadee/query'
|
8
|
-
require 'chickadee/
|
9
|
-
require 'chickadee/
|
10
|
-
require 'chickadee/
|
11
|
-
require 'chickadee/
|
5
|
+
require 'chickadee/requests/request'
|
6
|
+
require 'chickadee/requests/command'
|
7
|
+
require 'chickadee/requests/query'
|
8
|
+
require 'chickadee/requests/event'
|
9
|
+
require 'chickadee/dispatchers/handler_chain_struct'
|
10
|
+
require 'chickadee/dispatchers/message_bus'
|
11
|
+
require 'chickadee/dispatchers/request_dispatcher'
|
12
|
+
require 'chickadee/dispatchers/event_dispatcher'
|
13
|
+
require 'chickadee/dispatchers/command_dispatcher'
|
14
|
+
require 'chickadee/dispatchers/query_dispatcher'
|
15
|
+
require 'chickadee/dispatchers/dispatcher_manager'
|
16
|
+
require 'chickadee/dispatcher'
|
12
17
|
|
13
18
|
module Chickadee
|
14
19
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'chickadee'
|
3
|
+
|
4
|
+
describe Chickadee::CommandDispatcher do
|
5
|
+
it 'can map handler chain to request' do
|
6
|
+
container = define_container
|
7
|
+
dispatcher = define_dispatcher(container)
|
8
|
+
command = Chickadee::Command.new
|
9
|
+
handler1 = stub(:handle => 'handler1_response')
|
10
|
+
handler2 = stub(:handle => 'handler2_response')
|
11
|
+
|
12
|
+
container.register(:myhandler1, handler1, :as => :instance)
|
13
|
+
container.register(:myhandler2, handler2, :as => :instance)
|
14
|
+
|
15
|
+
dispatcher.map(Chickadee::Command, :myhandler1, :myhandler2)
|
16
|
+
|
17
|
+
handler1.expects(:handle).once
|
18
|
+
handler2.expects(:handle).once
|
19
|
+
dispatcher.dispatch(command)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'complains if same command mapped twice' do
|
23
|
+
container = define_container
|
24
|
+
dispatcher = define_dispatcher(container)
|
25
|
+
command = Chickadee::Command.new
|
26
|
+
|
27
|
+
dispatcher.map(Chickadee::Command, stub)
|
28
|
+
proc{ dispatcher.map(Chickadee::Command, stub) }.must_raise(Chickadee::DispatcherError)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns nothing' do
|
32
|
+
container = define_container
|
33
|
+
dispatcher = define_dispatcher(container)
|
34
|
+
command = Chickadee::Command.new
|
35
|
+
handler1 = stub(:handle => 'handler1_response')
|
36
|
+
|
37
|
+
container.register(:myhandler1, handler1, :as => :instance)
|
38
|
+
|
39
|
+
dispatcher.map(Chickadee::Command, :myhandler1)
|
40
|
+
dispatcher.dispatch(command).must_be_nil
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def define_container
|
45
|
+
Chickadee::Container.new
|
46
|
+
end
|
47
|
+
|
48
|
+
def define_dispatcher(*args)
|
49
|
+
Chickadee::CommandDispatcher.new(*args)
|
50
|
+
end
|
51
|
+
|
52
|
+
def define_command
|
53
|
+
Chickadee::Command.new
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'chickadee'
|
3
|
+
|
4
|
+
describe Chickadee::EventDispatcher do
|
5
|
+
it 'can map handler chain to request' do
|
6
|
+
container = define_container
|
7
|
+
dispatcher = define_dispatcher(container)
|
8
|
+
event = Chickadee::Event.new
|
9
|
+
handler1 = stub(:handle => 'handler1_response')
|
10
|
+
handler2 = stub(:handle => 'handler2_response')
|
11
|
+
|
12
|
+
container.register(:myhandler1, handler1, :as => :instance)
|
13
|
+
container.register(:myhandler2, handler2, :as => :instance)
|
14
|
+
|
15
|
+
dispatcher.map(Chickadee::Event, :myhandler1, :myhandler2)
|
16
|
+
|
17
|
+
handler1.expects(:handle).once
|
18
|
+
handler2.expects(:handle).once
|
19
|
+
dispatcher.dispatch(event)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'can map multiple handler chains to request' do
|
23
|
+
container = define_container
|
24
|
+
dispatcher = define_dispatcher(container)
|
25
|
+
event = Chickadee::Event.new
|
26
|
+
handler1 = stub(:handle => 'handler1_response')
|
27
|
+
handler2 = stub(:handle => 'handler2_response')
|
28
|
+
handler3 = stub(:handle => 'handler3_response')
|
29
|
+
handler4 = stub(:handle => 'handler4_response')
|
30
|
+
|
31
|
+
container.register(:myhandler1, handler1, :as => :instance)
|
32
|
+
container.register(:myhandler2, handler2, :as => :instance)
|
33
|
+
container.register(:myhandler3, handler3, :as => :instance)
|
34
|
+
container.register(:myhandler4, handler4, :as => :instance)
|
35
|
+
|
36
|
+
dispatcher.map(Chickadee::Event, :myhandler1, :myhandler2)
|
37
|
+
dispatcher.map(Chickadee::Event, :myhandler3, :myhandler4)
|
38
|
+
|
39
|
+
handler1.expects(:handle).once
|
40
|
+
handler2.expects(:handle).once
|
41
|
+
handler3.expects(:handle).once
|
42
|
+
handler4.expects(:handle).once
|
43
|
+
dispatcher.dispatch(event)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'returns nothing' do
|
47
|
+
container = define_container
|
48
|
+
dispatcher = define_dispatcher(container)
|
49
|
+
event = Chickadee::Event.new
|
50
|
+
handler1 = stub(:handle => 'handler1_response')
|
51
|
+
|
52
|
+
container.register(:myhandler1, handler1, :as => :instance)
|
53
|
+
|
54
|
+
dispatcher.map(Chickadee::Event, :myhandler1)
|
55
|
+
dispatcher.dispatch(event).must_be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def define_container
|
60
|
+
Chickadee::Container.new
|
61
|
+
end
|
62
|
+
|
63
|
+
def define_dispatcher(*args)
|
64
|
+
Chickadee::EventDispatcher.new(*args)
|
65
|
+
end
|
66
|
+
|
67
|
+
def define_event
|
68
|
+
Chickadee::Event.new
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'chickadee'
|
3
|
+
|
4
|
+
describe Chickadee::HandlerChainStruct do
|
5
|
+
it 'generates handler class' do
|
6
|
+
person_class1 = struct_class.new(:first_name, :last_name)
|
7
|
+
person_class2 = struct_class.new(:first_name, :last_name)
|
8
|
+
person_class1.wont_equal(person_class2)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'instance' do
|
12
|
+
describe '#handle' do
|
13
|
+
it 'delegates handle method to handlers in chain' do
|
14
|
+
request = stub
|
15
|
+
handler1 = stub
|
16
|
+
handler2 = stub
|
17
|
+
handler_chain_class = struct_class.new(:handler1, :handler2)
|
18
|
+
handler_chain = handler_chain_class.new(handler1, handler2)
|
19
|
+
|
20
|
+
handler1.expects(:handle).with(request)
|
21
|
+
handler2.expects(:handle).with(request)
|
22
|
+
handler_chain.handle(request)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def struct_class
|
28
|
+
Chickadee::HandlerChainStruct
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'chickadee'
|
3
|
+
|
4
|
+
describe Chickadee::MessageBus do
|
5
|
+
it 'can register block with bus topic' do
|
6
|
+
bus = new_bus
|
7
|
+
|
8
|
+
output = nil
|
9
|
+
|
10
|
+
bus.subscribe("topic") do |msg|
|
11
|
+
output = msg
|
12
|
+
end
|
13
|
+
|
14
|
+
output.must_be_nil
|
15
|
+
bus.publish("topic", 'the proc was called')
|
16
|
+
output.must_equal('the proc was called')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'can pubish a message for a given topic' do
|
20
|
+
bus = new_bus
|
21
|
+
|
22
|
+
output1 = nil
|
23
|
+
output2 = nil
|
24
|
+
|
25
|
+
bus.subscribe("topic1") { |msg| output1 = msg }
|
26
|
+
bus.subscribe("topic2") { |msg| output2 = msg }
|
27
|
+
|
28
|
+
bus.publish("topic1", 'message for topic1')
|
29
|
+
bus.publish("topic2", 'message for topic2')
|
30
|
+
|
31
|
+
output1.must_equal('message for topic1')
|
32
|
+
output2.must_equal('message for topic2')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'can unsubscribe a listener' do
|
36
|
+
bus = new_bus
|
37
|
+
|
38
|
+
output = nil
|
39
|
+
subscriber_id = bus.subscribe("topic") { |msg| output = msg }
|
40
|
+
|
41
|
+
bus.publish("topic", 'i received the message')
|
42
|
+
output.must_equal('i received the message')
|
43
|
+
|
44
|
+
bus.publish("topic", 'i received the message a second time')
|
45
|
+
output.must_equal('i received the message a second time')
|
46
|
+
|
47
|
+
bus.unsubscribe(subscriber_id)
|
48
|
+
|
49
|
+
bus.publish("topic", 'i received the message a third time')
|
50
|
+
output.must_equal('i received the message a second time')
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'can publish any number of arguments' do
|
54
|
+
bus = new_bus
|
55
|
+
|
56
|
+
output1 = nil
|
57
|
+
output2 = nil
|
58
|
+
|
59
|
+
bus.subscribe("topic") do |arg1, arg2|
|
60
|
+
output1 = arg1
|
61
|
+
output2 = arg2
|
62
|
+
end
|
63
|
+
|
64
|
+
bus.publish("topic", 'myarg1', 'myarg2')
|
65
|
+
|
66
|
+
output1.must_equal('myarg1')
|
67
|
+
output2.must_equal('myarg2')
|
68
|
+
end
|
69
|
+
|
70
|
+
def new_bus
|
71
|
+
Chickadee::MessageBus.new
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'chickadee'
|
3
|
+
|
4
|
+
describe Chickadee::QueryDispatcher do
|
5
|
+
it 'can map handler chain to request' do
|
6
|
+
container = define_container
|
7
|
+
dispatcher = define_dispatcher(container)
|
8
|
+
query = Chickadee::Query.new
|
9
|
+
handler1 = stub(:handle => 'handler1_response')
|
10
|
+
handler2 = stub(:handle => 'handler2_response')
|
11
|
+
|
12
|
+
container.register(:myhandler1, handler1, :as => :instance)
|
13
|
+
container.register(:myhandler2, handler2, :as => :instance)
|
14
|
+
|
15
|
+
dispatcher.map(Chickadee::Query, :myhandler1, :myhandler2)
|
16
|
+
|
17
|
+
handler1.expects(:handle).once
|
18
|
+
handler2.expects(:handle).once
|
19
|
+
dispatcher.dispatch(query)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'complains if same query mapped twice' do
|
23
|
+
container = define_container
|
24
|
+
dispatcher = define_dispatcher(container)
|
25
|
+
query = Chickadee::Query.new
|
26
|
+
|
27
|
+
dispatcher.map(Chickadee::Query, stub)
|
28
|
+
proc{ dispatcher.map(Chickadee::Query, stub) }.must_raise(Chickadee::DispatcherError)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns output from last handler in chain' do
|
32
|
+
container = define_container
|
33
|
+
dispatcher = define_dispatcher(container)
|
34
|
+
query = Chickadee::Query.new
|
35
|
+
handler1 = stub(:handle => 'handler1_response')
|
36
|
+
handler2 = stub(:handle => 'handler2_response')
|
37
|
+
|
38
|
+
container.register(:myhandler1, handler1, :as => :instance)
|
39
|
+
container.register(:myhandler2, handler2, :as => :instance)
|
40
|
+
|
41
|
+
dispatcher.map(Chickadee::Query, :myhandler1, :myhandler2)
|
42
|
+
dispatcher.dispatch(query).must_equal('handler2_response')
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def define_container
|
47
|
+
Chickadee::Container.new
|
48
|
+
end
|
49
|
+
|
50
|
+
def define_dispatcher(*args)
|
51
|
+
Chickadee::QueryDispatcher.new(*args)
|
52
|
+
end
|
53
|
+
|
54
|
+
def define_query
|
55
|
+
Chickadee::Query.new
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'chickadee'
|
3
|
+
|
4
|
+
describe Chickadee::Event do
|
5
|
+
it { new_query.query?.must_equal(false) }
|
6
|
+
it { new_query.command?.must_equal(false) }
|
7
|
+
it { new_query.event?.must_equal(true) }
|
8
|
+
|
9
|
+
def new_query
|
10
|
+
Chickadee::Event.new
|
11
|
+
end
|
12
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chickadee
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Erik Lott
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
11
|
+
date: 2014-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ioc
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 2.1.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 2.1.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,21 +81,29 @@ files:
|
|
81
81
|
- Rakefile
|
82
82
|
- chickadee.gemspec
|
83
83
|
- lib/chickadee.rb
|
84
|
-
- lib/chickadee/application.rb
|
85
|
-
- lib/chickadee/command.rb
|
86
84
|
- lib/chickadee/container.rb
|
85
|
+
- lib/chickadee/dispatcher.rb
|
86
|
+
- lib/chickadee/dispatchers/command_dispatcher.rb
|
87
|
+
- lib/chickadee/dispatchers/dispatcher_manager.rb
|
88
|
+
- lib/chickadee/dispatchers/event_dispatcher.rb
|
89
|
+
- lib/chickadee/dispatchers/handler_chain_struct.rb
|
90
|
+
- lib/chickadee/dispatchers/message_bus.rb
|
91
|
+
- lib/chickadee/dispatchers/query_dispatcher.rb
|
92
|
+
- lib/chickadee/dispatchers/request_dispatcher.rb
|
87
93
|
- lib/chickadee/exceptions.rb
|
88
|
-
- lib/chickadee/
|
89
|
-
- lib/chickadee/
|
90
|
-
- lib/chickadee/
|
91
|
-
- lib/chickadee/request.rb
|
92
|
-
- lib/chickadee/router.rb
|
94
|
+
- lib/chickadee/requests/command.rb
|
95
|
+
- lib/chickadee/requests/event.rb
|
96
|
+
- lib/chickadee/requests/query.rb
|
97
|
+
- lib/chickadee/requests/request.rb
|
93
98
|
- lib/chickadee/version.rb
|
94
|
-
- spec/
|
95
|
-
- spec/
|
96
|
-
- spec/
|
97
|
-
- spec/
|
98
|
-
- spec/
|
99
|
+
- spec/dispatchers/command_dispatcher_spec.rb
|
100
|
+
- spec/dispatchers/event_dispatcher_spec.rb
|
101
|
+
- spec/dispatchers/handler_chain_struct_spec.rb
|
102
|
+
- spec/dispatchers/message_bus_spec.rb
|
103
|
+
- spec/dispatchers/query_dispatcher_spec.rb
|
104
|
+
- spec/requests/command_spec.rb
|
105
|
+
- spec/requests/event_spec.rb
|
106
|
+
- spec/requests/query_spec.rb
|
99
107
|
- spec/spec_helper.rb
|
100
108
|
homepage: ''
|
101
109
|
licenses:
|
@@ -122,9 +130,12 @@ signing_key:
|
|
122
130
|
specification_version: 4
|
123
131
|
summary: Lightweight domain driven design library
|
124
132
|
test_files:
|
125
|
-
- spec/
|
126
|
-
- spec/
|
127
|
-
- spec/
|
128
|
-
- spec/
|
129
|
-
- spec/
|
133
|
+
- spec/dispatchers/command_dispatcher_spec.rb
|
134
|
+
- spec/dispatchers/event_dispatcher_spec.rb
|
135
|
+
- spec/dispatchers/handler_chain_struct_spec.rb
|
136
|
+
- spec/dispatchers/message_bus_spec.rb
|
137
|
+
- spec/dispatchers/query_dispatcher_spec.rb
|
138
|
+
- spec/requests/command_spec.rb
|
139
|
+
- spec/requests/event_spec.rb
|
140
|
+
- spec/requests/query_spec.rb
|
130
141
|
- spec/spec_helper.rb
|
@@ -1,27 +0,0 @@
|
|
1
|
-
module Chickadee
|
2
|
-
class Application
|
3
|
-
def self.routes
|
4
|
-
@router ||= Router.new
|
5
|
-
end
|
6
|
-
|
7
|
-
def self.registry
|
8
|
-
@internal_registry ||= Registry.new
|
9
|
-
end
|
10
|
-
|
11
|
-
def initialize
|
12
|
-
@external_registry = Registry.new
|
13
|
-
end
|
14
|
-
|
15
|
-
def call(request)
|
16
|
-
container = Container.new
|
17
|
-
self.class.registry.update_container(container)
|
18
|
-
@external_registry.update_container(container)
|
19
|
-
output = self.class.routes.call(request.class).map{|handler| container[handler].handle(request)}.last
|
20
|
-
output if request.query?
|
21
|
-
end
|
22
|
-
|
23
|
-
def register(name, service)
|
24
|
-
@external_registry.register(name, service, :as => :instance)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/lib/chickadee/command.rb
DELETED
data/lib/chickadee/handler.rb
DELETED
data/lib/chickadee/query.rb
DELETED
data/lib/chickadee/registry.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
module Chickadee
|
2
|
-
class Registry
|
3
|
-
def initialize
|
4
|
-
@registrants = []
|
5
|
-
end
|
6
|
-
|
7
|
-
def draw(&block)
|
8
|
-
instance_eval(&block) if block_given?
|
9
|
-
end
|
10
|
-
|
11
|
-
def register(*args)
|
12
|
-
@registrants << args
|
13
|
-
end
|
14
|
-
|
15
|
-
def update_container(container)
|
16
|
-
@registrants.each{|args| container.register(*args)}
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/lib/chickadee/router.rb
DELETED
@@ -1,78 +0,0 @@
|
|
1
|
-
module Chickadee
|
2
|
-
class Router
|
3
|
-
class RequestMap
|
4
|
-
def initialize(map = {})
|
5
|
-
@map = map
|
6
|
-
end
|
7
|
-
|
8
|
-
def call(request)
|
9
|
-
if @map.key?(request)
|
10
|
-
@map.fetch(request).call(request)
|
11
|
-
else
|
12
|
-
app = @map[:app]
|
13
|
-
raise(RoutingError, 'missing run statement') unless app
|
14
|
-
app.call(request)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
class Middleware
|
20
|
-
def initialize(app, handler)
|
21
|
-
@app = app
|
22
|
-
@handler = handler
|
23
|
-
end
|
24
|
-
|
25
|
-
def call(request)
|
26
|
-
@app.call(request).unshift(@handler)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def initialize(default_app = nil, &block)
|
31
|
-
@run = default_app
|
32
|
-
@use = []
|
33
|
-
@map = nil
|
34
|
-
instance_eval(&block) if block_given?
|
35
|
-
end
|
36
|
-
|
37
|
-
def draw(&block)
|
38
|
-
instance_eval(&block) if block_given?
|
39
|
-
end
|
40
|
-
|
41
|
-
def use(handler, &block)
|
42
|
-
if @map
|
43
|
-
mapping = @map
|
44
|
-
@map = nil
|
45
|
-
@use << proc { |app| generate_map(app, mapping) }
|
46
|
-
end
|
47
|
-
@use << proc { |app| Middleware.new(app, handler, &block) }
|
48
|
-
end
|
49
|
-
|
50
|
-
def run(handler)
|
51
|
-
@run = proc{|request| [handler]}
|
52
|
-
end
|
53
|
-
|
54
|
-
def map(method_name, &block)
|
55
|
-
@map ||= {}
|
56
|
-
@map[method_name] = block
|
57
|
-
end
|
58
|
-
|
59
|
-
def to_app
|
60
|
-
app = @map ? generate_map(@run, @map) : @run
|
61
|
-
raise(RoutingError, 'missing run or map statement') unless app
|
62
|
-
app = @use.reverse.inject(app) { |a,e| e[a] }
|
63
|
-
app
|
64
|
-
end
|
65
|
-
|
66
|
-
def call(request)
|
67
|
-
to_app.call(request)
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def generate_map(default_app, mapping)
|
73
|
-
mapped = default_app ? {:app => default_app} : {}
|
74
|
-
mapping.each { |r,b| mapped[r] = self.class.new(default_app, &b) }
|
75
|
-
RequestMap.new(mapped)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
data/spec/chickadee_spec.rb
DELETED
@@ -1,128 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'chickadee'
|
3
|
-
|
4
|
-
describe Chickadee do
|
5
|
-
|
6
|
-
class TestCommand1 < Chickadee::Command
|
7
|
-
attr_accessor :name
|
8
|
-
end
|
9
|
-
|
10
|
-
class TestQuery1 < Chickadee::Query
|
11
|
-
attr_accessor :name
|
12
|
-
end
|
13
|
-
|
14
|
-
class TestHandler1 < Chickadee::Handler
|
15
|
-
def handle(command)
|
16
|
-
"hander1 says: #{command.name}"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class TestHandler2 < Chickadee::Handler
|
21
|
-
def handle(command)
|
22
|
-
"hander2 says: #{command.name}"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
context 'when command request' do
|
27
|
-
it 'returns nil from command' do
|
28
|
-
app_class = new_app_class
|
29
|
-
app_class.routes.draw do
|
30
|
-
map(TestCommand1) do
|
31
|
-
run :handler1
|
32
|
-
end
|
33
|
-
end
|
34
|
-
app_class.registry.draw do
|
35
|
-
register(:handler1, TestHandler1)
|
36
|
-
end
|
37
|
-
|
38
|
-
app = app_class.new
|
39
|
-
command = TestCommand1.new
|
40
|
-
command.name = 'Chuck Norris'
|
41
|
-
app.call(command).must_be_nil
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'executes handler chain' do
|
45
|
-
app_class = new_app_class
|
46
|
-
|
47
|
-
handler1 = TestHandler1.new
|
48
|
-
handler2 = TestHandler2.new
|
49
|
-
|
50
|
-
app_class.routes.draw do
|
51
|
-
map(TestCommand1) do
|
52
|
-
use :handler1
|
53
|
-
run :handler2
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
app_class.registry.draw do
|
58
|
-
register(:handler1, handler1, :as => :instance)
|
59
|
-
register(:handler2, handler2, :as => :instance)
|
60
|
-
end
|
61
|
-
|
62
|
-
app = app_class.new
|
63
|
-
command = TestCommand1.new
|
64
|
-
|
65
|
-
handler1.expects(:handle).with(command)
|
66
|
-
handler2.expects(:handle).with(command)
|
67
|
-
|
68
|
-
app.call(command)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
context 'when query request' do
|
73
|
-
it 'returns output from last handler in handler chain' do
|
74
|
-
app_class = new_app_class
|
75
|
-
|
76
|
-
handler1 = TestHandler1.new
|
77
|
-
handler2 = TestHandler2.new
|
78
|
-
|
79
|
-
app_class.routes.draw do
|
80
|
-
map(TestQuery1) do
|
81
|
-
use :handler1
|
82
|
-
run :handler2
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
app_class.registry.draw do
|
87
|
-
register(:handler1, handler1, :as => :instance)
|
88
|
-
register(:handler2, handler2, :as => :instance)
|
89
|
-
end
|
90
|
-
|
91
|
-
app = app_class.new
|
92
|
-
query = TestQuery1.new
|
93
|
-
query.name = 'Chuck Norris'
|
94
|
-
app.call(query).must_equal('hander2 says: Chuck Norris')
|
95
|
-
end
|
96
|
-
|
97
|
-
it 'executes handler chain' do
|
98
|
-
app_class = new_app_class
|
99
|
-
|
100
|
-
handler1 = TestHandler1.new
|
101
|
-
handler2 = TestHandler2.new
|
102
|
-
|
103
|
-
app_class.routes.draw do
|
104
|
-
map(TestQuery1) do
|
105
|
-
use :handler1
|
106
|
-
run :handler2
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
app_class.registry.draw do
|
111
|
-
register(:handler1, handler1, :as => :instance)
|
112
|
-
register(:handler2, handler2, :as => :instance)
|
113
|
-
end
|
114
|
-
|
115
|
-
app = app_class.new
|
116
|
-
query = TestQuery1.new
|
117
|
-
|
118
|
-
handler1.expects(:handle).with(query)
|
119
|
-
handler2.expects(:handle).with(query)
|
120
|
-
|
121
|
-
app.call(query)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def new_app_class
|
126
|
-
Class.new(Chickadee::Application)
|
127
|
-
end
|
128
|
-
end
|
data/spec/registry_spec.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'chickadee'
|
3
|
-
|
4
|
-
describe Chickadee::Registry do
|
5
|
-
describe '#update_container' do
|
6
|
-
it 'updates container with registered services' do
|
7
|
-
registry = new_registry
|
8
|
-
service = stub
|
9
|
-
container = new_container
|
10
|
-
|
11
|
-
registry.register(:myservice, service, :as => :instance)
|
12
|
-
registry.update_container(container)
|
13
|
-
container.resolve(:myservice).must_equal(service)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
describe '#draw' do
|
18
|
-
it 'can register with block' do
|
19
|
-
registry = new_registry
|
20
|
-
service = stub
|
21
|
-
|
22
|
-
registry.draw do
|
23
|
-
register(:service, service)
|
24
|
-
end
|
25
|
-
|
26
|
-
registry.instance_variable_get(:@registrants).must_equal([[:service, service]])
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def new_registry
|
31
|
-
Chickadee::Registry.new
|
32
|
-
end
|
33
|
-
|
34
|
-
def new_container
|
35
|
-
Chickadee::Container.new
|
36
|
-
end
|
37
|
-
end
|
data/spec/router_spec.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'chickadee'
|
3
|
-
|
4
|
-
describe Chickadee::Router do
|
5
|
-
it 'chains handlers' do
|
6
|
-
request = stub
|
7
|
-
|
8
|
-
app = builder do
|
9
|
-
use :handler1
|
10
|
-
run :handler2
|
11
|
-
end
|
12
|
-
|
13
|
-
app.call(request).must_equal([:handler1, :handler2])
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'supports use after run' do
|
17
|
-
request = stub
|
18
|
-
app = builder do
|
19
|
-
use :handler1
|
20
|
-
run :handler2
|
21
|
-
use :handler3
|
22
|
-
end
|
23
|
-
|
24
|
-
app.call(request).must_equal([:handler1, :handler3, :handler2])
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'complains when there is no run' do
|
28
|
-
request = stub
|
29
|
-
app = builder do
|
30
|
-
use :handler1
|
31
|
-
end
|
32
|
-
|
33
|
-
proc { app.call(request) }.must_raise(Chickadee::RoutingError)
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'supports mapping' do
|
37
|
-
request = stub
|
38
|
-
app = builder do
|
39
|
-
map(request) do
|
40
|
-
use :handler1
|
41
|
-
run :handler2
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
app.call(request).must_equal([:handler1, :handler2])
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'complains when there is no run with mapping' do
|
49
|
-
request = stub
|
50
|
-
app = builder do
|
51
|
-
use :handler1
|
52
|
-
map(request) do
|
53
|
-
use :handler2
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
proc { app.call(request) }.must_raise(Chickadee::RoutingError)
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'correctly maps complex senario' do
|
61
|
-
request1 = stub
|
62
|
-
request2 = stub
|
63
|
-
|
64
|
-
app = builder do
|
65
|
-
use :handler1
|
66
|
-
|
67
|
-
map(request1) do
|
68
|
-
use :handler2
|
69
|
-
run :handler3
|
70
|
-
end
|
71
|
-
|
72
|
-
use :handler4
|
73
|
-
|
74
|
-
map(request2) do
|
75
|
-
use :handler5
|
76
|
-
end
|
77
|
-
|
78
|
-
run :handler6
|
79
|
-
end
|
80
|
-
|
81
|
-
app.call(request1).must_equal([:handler1, :handler2, :handler3])
|
82
|
-
app.call(request2).must_equal([:handler1, :handler4, :handler5, :handler6])
|
83
|
-
app.call(nil).must_equal([:handler1, :handler4, :handler6])
|
84
|
-
end
|
85
|
-
|
86
|
-
def builder(&block)
|
87
|
-
Chickadee::Router.new(&block)
|
88
|
-
end
|
89
|
-
end
|