synapse-core 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|