synapse-core 0.1.2
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.
- data/lib/synapse.rb +351 -0
- data/lib/synapse/command/command_bus.rb +45 -0
- data/lib/synapse/command/command_callback.rb +18 -0
- data/lib/synapse/command/command_filter.rb +17 -0
- data/lib/synapse/command/command_handler.rb +13 -0
- data/lib/synapse/command/dispatch_interceptor.rb +16 -0
- data/lib/synapse/command/duplication.rb +43 -0
- data/lib/synapse/command/errors.rb +27 -0
- data/lib/synapse/command/filters/validation.rb +32 -0
- data/lib/synapse/command/gateway.rb +34 -0
- data/lib/synapse/command/interceptor_chain.rb +31 -0
- data/lib/synapse/command/interceptors/serialization.rb +35 -0
- data/lib/synapse/command/message.rb +19 -0
- data/lib/synapse/command/rollback_policy.rb +22 -0
- data/lib/synapse/command/simple_command_bus.rb +138 -0
- data/lib/synapse/command/wiring.rb +47 -0
- data/lib/synapse/domain/aggregate_root.rb +121 -0
- data/lib/synapse/domain/event_container.rb +127 -0
- data/lib/synapse/domain/message.rb +82 -0
- data/lib/synapse/domain/message_builder.rb +34 -0
- data/lib/synapse/domain/stream.rb +108 -0
- data/lib/synapse/duplication.rb +60 -0
- data/lib/synapse/errors.rb +13 -0
- data/lib/synapse/event_bus/event_bus.rb +40 -0
- data/lib/synapse/event_bus/event_listener.rb +16 -0
- data/lib/synapse/event_bus/event_listener_proxy.rb +12 -0
- data/lib/synapse/event_bus/simple_event_bus.rb +69 -0
- data/lib/synapse/event_bus/wiring.rb +23 -0
- data/lib/synapse/event_sourcing/aggregate_factory.rb +69 -0
- data/lib/synapse/event_sourcing/aggregate_root.rb +104 -0
- data/lib/synapse/event_sourcing/conflict_resolver.rb +80 -0
- data/lib/synapse/event_sourcing/entity.rb +64 -0
- data/lib/synapse/event_sourcing/member.rb +72 -0
- data/lib/synapse/event_sourcing/repository.rb +119 -0
- data/lib/synapse/event_sourcing/snapshot/count_stream.rb +86 -0
- data/lib/synapse/event_sourcing/snapshot/count_trigger.rb +91 -0
- data/lib/synapse/event_sourcing/snapshot/taker.rb +73 -0
- data/lib/synapse/event_sourcing/storage_listener.rb +34 -0
- data/lib/synapse/event_sourcing/stream_decorator.rb +25 -0
- data/lib/synapse/event_store/errors.rb +16 -0
- data/lib/synapse/event_store/event_store.rb +43 -0
- data/lib/synapse/event_store/in_memory.rb +59 -0
- data/lib/synapse/event_store/mongo/cursor_event_stream.rb +63 -0
- data/lib/synapse/event_store/mongo/event_store.rb +86 -0
- data/lib/synapse/event_store/mongo/per_commit_strategy.rb +253 -0
- data/lib/synapse/event_store/mongo/per_event_strategy.rb +143 -0
- data/lib/synapse/event_store/mongo/storage_strategy.rb +113 -0
- data/lib/synapse/event_store/mongo/template.rb +73 -0
- data/lib/synapse/identifier.rb +23 -0
- data/lib/synapse/message.rb +101 -0
- data/lib/synapse/message_builder.rb +38 -0
- data/lib/synapse/process_manager/correlation.rb +32 -0
- data/lib/synapse/process_manager/correlation_resolver.rb +14 -0
- data/lib/synapse/process_manager/correlation_set.rb +58 -0
- data/lib/synapse/process_manager/process.rb +71 -0
- data/lib/synapse/repository/errors.rb +26 -0
- data/lib/synapse/repository/lock_manager.rb +40 -0
- data/lib/synapse/repository/locking.rb +97 -0
- data/lib/synapse/repository/pessimistic_lock_manager.rb +61 -0
- data/lib/synapse/repository/repository.rb +109 -0
- data/lib/synapse/serialization/converter.rb +39 -0
- data/lib/synapse/serialization/converter/chain.rb +45 -0
- data/lib/synapse/serialization/converter/factory.rb +68 -0
- data/lib/synapse/serialization/converter/identity.rb +29 -0
- data/lib/synapse/serialization/converter/json.rb +31 -0
- data/lib/synapse/serialization/converter/ox.rb +31 -0
- data/lib/synapse/serialization/errors.rb +12 -0
- data/lib/synapse/serialization/lazy_object.rb +61 -0
- data/lib/synapse/serialization/message/data.rb +25 -0
- data/lib/synapse/serialization/message/metadata.rb +13 -0
- data/lib/synapse/serialization/message/serialization_aware.rb +17 -0
- data/lib/synapse/serialization/message/serialization_aware_message.rb +66 -0
- data/lib/synapse/serialization/message/serialized_message.rb +201 -0
- data/lib/synapse/serialization/message/serialized_message_builder.rb +64 -0
- data/lib/synapse/serialization/message/serialized_object_cache.rb +50 -0
- data/lib/synapse/serialization/message/serializer.rb +47 -0
- data/lib/synapse/serialization/revision_resolver.rb +30 -0
- data/lib/synapse/serialization/serialized_object.rb +37 -0
- data/lib/synapse/serialization/serialized_type.rb +31 -0
- data/lib/synapse/serialization/serializer.rb +98 -0
- data/lib/synapse/serialization/serializer/marshal.rb +32 -0
- data/lib/synapse/serialization/serializer/oj.rb +34 -0
- data/lib/synapse/serialization/serializer/ox.rb +31 -0
- data/lib/synapse/uow/factory.rb +28 -0
- data/lib/synapse/uow/listener.rb +79 -0
- data/lib/synapse/uow/listener_collection.rb +93 -0
- data/lib/synapse/uow/nesting.rb +262 -0
- data/lib/synapse/uow/provider.rb +71 -0
- data/lib/synapse/uow/storage_listener.rb +14 -0
- data/lib/synapse/uow/transaction_manager.rb +27 -0
- data/lib/synapse/uow/uow.rb +178 -0
- data/lib/synapse/upcasting/chain.rb +78 -0
- data/lib/synapse/upcasting/context.rb +58 -0
- data/lib/synapse/upcasting/data.rb +30 -0
- data/lib/synapse/upcasting/single_upcaster.rb +57 -0
- data/lib/synapse/upcasting/upcaster.rb +55 -0
- data/lib/synapse/version.rb +3 -0
- data/lib/synapse/wiring/message_wiring.rb +41 -0
- data/lib/synapse/wiring/wire.rb +55 -0
- data/lib/synapse/wiring/wire_registry.rb +61 -0
- data/test/command/duplication_test.rb +54 -0
- data/test/command/gateway_test.rb +25 -0
- data/test/command/interceptor_chain_test.rb +26 -0
- data/test/command/serialization_test.rb +37 -0
- data/test/command/simple_command_bus_test.rb +141 -0
- data/test/command/validation_test.rb +42 -0
- data/test/command/wiring_test.rb +73 -0
- data/test/domain/aggregate_root_test.rb +57 -0
- data/test/domain/fixtures.rb +31 -0
- data/test/domain/message_test.rb +61 -0
- data/test/domain/stream_test.rb +35 -0
- data/test/duplication_test.rb +40 -0
- data/test/event_bus/wiring_test.rb +46 -0
- data/test/event_sourcing/aggregate_factory_test.rb +28 -0
- data/test/event_sourcing/aggregate_root_test.rb +76 -0
- data/test/event_sourcing/entity_test.rb +34 -0
- data/test/event_sourcing/fixtures.rb +85 -0
- data/test/event_sourcing/repository_test.rb +102 -0
- data/test/event_sourcing/snapshot/aggregate_taker_test.rb +39 -0
- data/test/event_sourcing/snapshot/deferred_taker_test.rb +19 -0
- data/test/event_sourcing/snapshot/integration_test.rb +65 -0
- data/test/event_sourcing/storage_listener_test.rb +77 -0
- data/test/event_store/in_memory_test.rb +47 -0
- data/test/process_manager/correlation_set_test.rb +49 -0
- data/test/process_manager/correlation_test.rb +24 -0
- data/test/process_manager/process_test.rb +52 -0
- data/test/repository/locking_test.rb +101 -0
- data/test/serialization/converter/factory_test.rb +33 -0
- data/test/serialization/converter/identity_test.rb +17 -0
- data/test/serialization/converter/json_test.rb +31 -0
- data/test/serialization/converter/ox_test.rb +40 -0
- data/test/serialization/fixtures.rb +17 -0
- data/test/serialization/lazy_object_test.rb +32 -0
- data/test/serialization/message/metadata_test.rb +19 -0
- data/test/serialization/message/serialization_aware_message_test.rb +88 -0
- data/test/serialization/message/serialized_message_builder_test.rb +41 -0
- data/test/serialization/message/serialized_message_test.rb +140 -0
- data/test/serialization/message/serializer_test.rb +50 -0
- data/test/serialization/revision_resolver_test.rb +12 -0
- data/test/serialization/serialized_object_test.rb +36 -0
- data/test/serialization/serialized_type_test.rb +27 -0
- data/test/serialization/serializer/marshal_test.rb +22 -0
- data/test/serialization/serializer/oj_test.rb +24 -0
- data/test/serialization/serializer/ox_test.rb +36 -0
- data/test/serialization/serializer_test.rb +20 -0
- data/test/test_helper.rb +19 -0
- data/test/uow/factory_test.rb +23 -0
- data/test/uow/outer_commit_listener_test.rb +50 -0
- data/test/uow/provider_test.rb +70 -0
- data/test/uow/uow_test.rb +337 -0
- data/test/upcasting/chain_test.rb +29 -0
- data/test/upcasting/fixtures.rb +66 -0
- data/test/wiring/wire_registry_test.rb +60 -0
- data/test/wiring/wire_test.rb +51 -0
- metadata +263 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module Upcasting
|
|
3
|
+
class UpcasterChain
|
|
4
|
+
# @return [ConverterFactory]
|
|
5
|
+
attr_accessor :converter_factory
|
|
6
|
+
|
|
7
|
+
# @return [Array<Upcaster>]
|
|
8
|
+
attr_accessor :upcasters
|
|
9
|
+
|
|
10
|
+
# @param [ConverterFactory] converter_factory
|
|
11
|
+
# @return [undefined]
|
|
12
|
+
def initialize(converter_factory)
|
|
13
|
+
@converter_factory = converter_factory
|
|
14
|
+
@upcasters = Array.new
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Pushes the given upcaster onto the end of this upcaster chain
|
|
18
|
+
#
|
|
19
|
+
# @param [Upcaster] upcaster
|
|
20
|
+
# @return [undefined]
|
|
21
|
+
def push(upcaster)
|
|
22
|
+
@upcasters.push upcaster
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
alias << push
|
|
26
|
+
|
|
27
|
+
# @param [SerializedObject] serialized_object
|
|
28
|
+
# @param [UpcastingContext] upcast_context
|
|
29
|
+
# @return [Array<SerializedObject>]
|
|
30
|
+
def upcast(serialized_object, upcast_context)
|
|
31
|
+
serialized_objects = Array.new
|
|
32
|
+
serialized_objects.push serialized_object
|
|
33
|
+
|
|
34
|
+
@upcasters.each do |upcaster|
|
|
35
|
+
serialized_objects = upcast_objects(upcaster, serialized_objects, upcast_context)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
serialized_objects
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
protected
|
|
42
|
+
|
|
43
|
+
# @param [Upcaster] upcaster
|
|
44
|
+
# @param [SerializedObject] representation
|
|
45
|
+
# @param [Array<SerializedType>] expected_types
|
|
46
|
+
# @param [UpcastingContent] upcast_context
|
|
47
|
+
# @return [Array<SerializedObject>]
|
|
48
|
+
def perform_upcast(upcaster, representation, expected_types, upcast_context)
|
|
49
|
+
upcaster.upcast(representation, expected_types, upcast_context)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
# @param [Upcaster] upcaster
|
|
55
|
+
# @param [Array<SerializedObject>] serialized_objects
|
|
56
|
+
# @param [UpcastingContext] upcast_context
|
|
57
|
+
# @return [Array<SerializedObject>]
|
|
58
|
+
def upcast_objects(upcaster, serialized_objects, upcast_context)
|
|
59
|
+
upcast_objects = Array.new
|
|
60
|
+
|
|
61
|
+
serialized_objects.each do |serialized_object|
|
|
62
|
+
serialized_type = serialized_object.type
|
|
63
|
+
|
|
64
|
+
if upcaster.can_upcast? serialized_type
|
|
65
|
+
serialized_object = converter_factory.convert serialized_object, upcaster.expected_content_type
|
|
66
|
+
expected_types = upcaster.upcast_type(serialized_type)
|
|
67
|
+
|
|
68
|
+
upcast_objects.concat(perform_upcast(upcaster, serialized_object, expected_types, upcast_context))
|
|
69
|
+
else
|
|
70
|
+
upcast_objects.push serialized_object
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
upcast_objects
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module Upcasting
|
|
3
|
+
# Provides contextual information about an object being upcast; generally this is information
|
|
4
|
+
# from the message containing the object to be upcast
|
|
5
|
+
#
|
|
6
|
+
# @abstract
|
|
7
|
+
class UpcastingContext
|
|
8
|
+
# @abstract
|
|
9
|
+
# @return [String]
|
|
10
|
+
def message_id; end
|
|
11
|
+
|
|
12
|
+
# @abstract
|
|
13
|
+
# @return [Hash]
|
|
14
|
+
def metadata; end
|
|
15
|
+
|
|
16
|
+
# @abstract
|
|
17
|
+
# @return [Time]
|
|
18
|
+
def timestamp; end
|
|
19
|
+
|
|
20
|
+
# @abstract
|
|
21
|
+
# @return [Object]
|
|
22
|
+
def aggregate_id; end
|
|
23
|
+
|
|
24
|
+
# @abstract
|
|
25
|
+
# @return [Integer]
|
|
26
|
+
def sequence_number; end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Upcasting context that provides information from serialized domain event data
|
|
30
|
+
class SerializedDomainEventUpcastingContext < UpcastingContext
|
|
31
|
+
extend Forwardable
|
|
32
|
+
|
|
33
|
+
# @return [Object]
|
|
34
|
+
attr_reader :aggregate_id
|
|
35
|
+
|
|
36
|
+
# @return [LazyObject]
|
|
37
|
+
attr_reader :serialized_metadata
|
|
38
|
+
|
|
39
|
+
# @param [SerializedDomainEventData] event_data
|
|
40
|
+
# @param [Object] aggregate_id
|
|
41
|
+
# @param [Serializer] serializer
|
|
42
|
+
# @return [undefined]
|
|
43
|
+
def initialize(event_data, aggregate_id, serializer)
|
|
44
|
+
@aggregate_id = aggregate_id
|
|
45
|
+
@event_data = event_data
|
|
46
|
+
@serialized_metadata = Serialization::LazyObject.new @event_data.metadata, serializer
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @return [Hash]
|
|
50
|
+
def metadata
|
|
51
|
+
@serialized_metadata.deserialized
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Delegators for serialized domain event data
|
|
55
|
+
def_delegators :@event_data, :id, :timestamp, :sequence_number
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module Upcasting
|
|
3
|
+
class UpcastSerializedDomainEventData < Serialization::SerializedDomainEventData
|
|
4
|
+
extend Forwardable
|
|
5
|
+
|
|
6
|
+
# @param [SerializedDomainEventData] original
|
|
7
|
+
# @param [Object] aggregate_id
|
|
8
|
+
# @param [SerializedObject] upcast_payload
|
|
9
|
+
# @return [undefined]
|
|
10
|
+
def initialize(original, aggregate_id, upcast_payload)
|
|
11
|
+
@original = original
|
|
12
|
+
@aggregate_id = aggregate_id
|
|
13
|
+
@upcast_payload = upcast_payload
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @return [SerializedObject]
|
|
17
|
+
def payload
|
|
18
|
+
@upcast_payload
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [Object]
|
|
22
|
+
def aggregate_id
|
|
23
|
+
@aggregate_id
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Delegators for serialized domain event data
|
|
27
|
+
def_delegators :@original, :id, :metadata, :timestamp, :sequence_number
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module Upcasting
|
|
3
|
+
# Specialized upcaster mixin for an upcaster that upcasts a serialized object into a single,
|
|
4
|
+
# newer serialized object.
|
|
5
|
+
#
|
|
6
|
+
# This mixin is not suitable if an upcaster needs to upcast a serialized object into multiple
|
|
7
|
+
# newer serialized objects, or when the output representation type is not the same as the
|
|
8
|
+
# expected representation type.
|
|
9
|
+
module SingleUpcaster
|
|
10
|
+
extend ActiveSupport::Concern
|
|
11
|
+
include Upcaster
|
|
12
|
+
|
|
13
|
+
# @param [SerialiedObject] intermediate
|
|
14
|
+
# @param [Array<SerializedType>] expected_types
|
|
15
|
+
# @param [UpcastingContext] upcast_context
|
|
16
|
+
# @return [Array<SerializedObject>]
|
|
17
|
+
def upcast(intermediate, expected_types, upcast_context)
|
|
18
|
+
upcast_content = perform_upcast(intermediate, upcast_context)
|
|
19
|
+
upcast_objects = Array.new
|
|
20
|
+
|
|
21
|
+
unless upcast_content
|
|
22
|
+
return upcast_objects
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
upcast_objects.push Serialization::SerializedObject.new(upcast_content, expected_content_type, expected_types.at(0))
|
|
26
|
+
upcast_objects
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @param [SerializedType] serialized_type
|
|
30
|
+
# @return [Array<SerializedType>]
|
|
31
|
+
def upcast_type(serialized_type)
|
|
32
|
+
upcast_type = perform_upcast_type(serialized_type)
|
|
33
|
+
upcast_types = Array.new
|
|
34
|
+
|
|
35
|
+
unless upcast_type
|
|
36
|
+
return upcast_types
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
upcast_types.push upcast_type
|
|
40
|
+
upcast_types
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
protected
|
|
44
|
+
|
|
45
|
+
# @abstract
|
|
46
|
+
# @param [SerializedObject] intermediate
|
|
47
|
+
# @param [UpcastingContext] upcast_context
|
|
48
|
+
# @return [Object] If nil is returned, the serialized object will be dropped
|
|
49
|
+
def perform_upcast(intermediate, upcast_context); end
|
|
50
|
+
|
|
51
|
+
# @abstract
|
|
52
|
+
# @param [SerializedType] serialized_type
|
|
53
|
+
# @return [SerializedType] If nil is returned, the serialized object will be dropped
|
|
54
|
+
def perform_upcast_type(serialized_type); end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module Upcasting
|
|
3
|
+
# Represents a mechanism for converting deprecated serialized objects into the current
|
|
4
|
+
# format used by the application. If the serializer itself is not able to cope with the changed
|
|
5
|
+
# formats, an upcaster provides flexibility for more complex structural transformations.
|
|
6
|
+
#
|
|
7
|
+
# Upcasters work on intermediate representations of the object to upcast. In most cases, this
|
|
8
|
+
# representation is an object structure of some kind. The serializer is responsible for
|
|
9
|
+
# converting the intermediate representation form to one that is compatible with the upcaster.
|
|
10
|
+
#
|
|
11
|
+
# For performance reasons, it is advisable to ensure that all upcasters in the same chain use
|
|
12
|
+
# the same intermediate representation type.
|
|
13
|
+
module Upcaster
|
|
14
|
+
extend ActiveSupport::Concern
|
|
15
|
+
|
|
16
|
+
included do
|
|
17
|
+
class_attribute :expected_content_type
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
module ClassMethods
|
|
21
|
+
# @param [Class] type
|
|
22
|
+
# @return [undefined]
|
|
23
|
+
def expects_content_type(type)
|
|
24
|
+
self.expected_content_type = type
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Returns true if this upcaster is capable of upcasting the given type
|
|
29
|
+
#
|
|
30
|
+
# @abstract
|
|
31
|
+
# @param [SerializedType] serialized_type
|
|
32
|
+
# @return [Boolean]
|
|
33
|
+
def can_upcast?(serialized_type); end
|
|
34
|
+
|
|
35
|
+
# Upcasts a given serialized object to zero or more upcast objects
|
|
36
|
+
#
|
|
37
|
+
# The types of the upcast objects should match the same length and order of the given array
|
|
38
|
+
# of upcast types.
|
|
39
|
+
#
|
|
40
|
+
# @abstract
|
|
41
|
+
# @param [SerialiedObject] intermediate
|
|
42
|
+
# @param [Array<SerializedType>] expected_types
|
|
43
|
+
# @param [UpcastingContext] upcast_context
|
|
44
|
+
# @return [Array<SerializedObject>]
|
|
45
|
+
def upcast(intermediate, expected_types, upcast_context); end
|
|
46
|
+
|
|
47
|
+
# Upcasts a given serialized type to zero or more upcast types
|
|
48
|
+
#
|
|
49
|
+
# @abstract
|
|
50
|
+
# @param [SerializedType] serialized_type
|
|
51
|
+
# @return [Array<SerializedType>]
|
|
52
|
+
def upcast_type(serialized_type); end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module Wiring
|
|
3
|
+
# Base mixin that make it easier to wire handlers to their respective types
|
|
4
|
+
# @abstract
|
|
5
|
+
module MessageWiring
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
# @return [WireRegistry]
|
|
10
|
+
class_attribute :wire_registry
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module ClassMethods
|
|
14
|
+
def wire(type, *args, &block)
|
|
15
|
+
options = args.extract_options!
|
|
16
|
+
|
|
17
|
+
unless options[:to]
|
|
18
|
+
unless block
|
|
19
|
+
raise ArgumentError, 'Expected block or option :to'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
options[:to] = block
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
wire = Wire.new type, options[:to]
|
|
26
|
+
|
|
27
|
+
self.wire_registry.register wire
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
protected
|
|
32
|
+
|
|
33
|
+
# @param [Message] message
|
|
34
|
+
# @param [Wire] wire
|
|
35
|
+
# @return [Object] Result of the handler invocation
|
|
36
|
+
def invoke_wire(message, wire)
|
|
37
|
+
wire.invoke self, message.payload
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module Wiring
|
|
3
|
+
# Represents a mapping between a payload type and a handler method or block
|
|
4
|
+
#
|
|
5
|
+
# Wires are ordered by the depth of the payload type that they handle. Wires that are
|
|
6
|
+
# for a more specific class are preferred over wires for an abstract class.
|
|
7
|
+
class Wire
|
|
8
|
+
# @return [Class] The type of payload that a handler is being wired to
|
|
9
|
+
attr_reader :type
|
|
10
|
+
|
|
11
|
+
# @return [Object] Either a method symbol or block
|
|
12
|
+
attr_reader :handler
|
|
13
|
+
|
|
14
|
+
# @param [Class] type
|
|
15
|
+
# @param [Object] handler Either a method symbol or block
|
|
16
|
+
# @return [undefined]]
|
|
17
|
+
def initialize(type, handler)
|
|
18
|
+
@type = type
|
|
19
|
+
@handler = handler
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @param [Object] target
|
|
23
|
+
# @param [Object...] args
|
|
24
|
+
# @return [Object] The result of the handler invocation
|
|
25
|
+
def invoke(target, *args)
|
|
26
|
+
if @handler.is_a? Symbol
|
|
27
|
+
target.send(@handler, *args)
|
|
28
|
+
else
|
|
29
|
+
target.instance_exec(*args, &@handler)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @param [Wire] other
|
|
34
|
+
# @return [Integer]
|
|
35
|
+
def <=>(other)
|
|
36
|
+
(@type <=> other.type) or 0
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @param [Wire] other
|
|
40
|
+
# @return [Boolean]
|
|
41
|
+
def ==(other)
|
|
42
|
+
self.class === other and
|
|
43
|
+
@type == other.type
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
alias eql? ==
|
|
47
|
+
|
|
48
|
+
# TODO Is this a good hash function? Probs not
|
|
49
|
+
# @return [Integer]
|
|
50
|
+
def hash
|
|
51
|
+
@type.hash
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module Wiring
|
|
3
|
+
class WireRegistry
|
|
4
|
+
# @param [Boolean] duplicates_allowed
|
|
5
|
+
# @return [undefined]
|
|
6
|
+
def initialize(duplicates_allowed)
|
|
7
|
+
@duplicates_allowed = duplicates_allowed
|
|
8
|
+
@wires = Array.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Yields the type that each wire is registered for
|
|
12
|
+
#
|
|
13
|
+
# @yield [Class]
|
|
14
|
+
# @return [undefined]
|
|
15
|
+
def each_type
|
|
16
|
+
@wires.each do |wire|
|
|
17
|
+
yield wire.type
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @raise [DuplicateWireError] If duplicates aren't allowed and another wire exists that
|
|
22
|
+
# wires the exact same type as the given wire
|
|
23
|
+
# @param [Wire] wire
|
|
24
|
+
# @return [undefined]
|
|
25
|
+
def register(wire)
|
|
26
|
+
unless @duplicates_allowed
|
|
27
|
+
if @wires.include? wire
|
|
28
|
+
raise DuplicateWireError
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
@wires.push wire
|
|
33
|
+
@wires.sort!
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Retrieves the most specific wire for a given type, if any
|
|
37
|
+
#
|
|
38
|
+
# @param [Class] target_type
|
|
39
|
+
# @return [Wire]
|
|
40
|
+
def wire_for(target_type)
|
|
41
|
+
@wires.find do |wire|
|
|
42
|
+
wire.type >= target_type
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Retrieves any wires for a given type, regardless of specificity
|
|
47
|
+
#
|
|
48
|
+
# @param [Class] target_type
|
|
49
|
+
# @return [Array]
|
|
50
|
+
def wires_for(target_type)
|
|
51
|
+
@wires.find_all do |wire|
|
|
52
|
+
wire.type >= target_type
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Raised if a wire registry doesn't allow duplicates and an attempt is made to wire the same
|
|
58
|
+
# type to multiple handlers
|
|
59
|
+
class DuplicateWireError < NonTransientError; end
|
|
60
|
+
end
|
|
61
|
+
end
|