synapse-core 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/synapse.rb +1 -1
- data/lib/synapse/command.rb +1 -1
- data/lib/synapse/command/command_handler.rb +1 -1
- data/lib/synapse/command/mapping.rb +71 -0
- data/lib/synapse/command/message.rb +0 -16
- data/lib/synapse/command/simple_command_bus.rb +5 -2
- data/lib/synapse/common/message.rb +16 -0
- data/lib/synapse/configuration.rb +1 -18
- data/lib/synapse/configuration/component/command_bus.rb +7 -24
- data/lib/synapse/configuration/component/command_bus/simple_command_bus.rb +31 -7
- data/lib/synapse/configuration/component/event_bus.rb +3 -8
- data/lib/synapse/configuration/component/event_sourcing.rb +11 -8
- data/lib/synapse/configuration/component/event_sourcing/aggregate_snapshot_taker.rb +48 -0
- data/lib/synapse/configuration/component/event_sourcing/interval_snapshot_policy.rb +33 -0
- data/lib/synapse/configuration/component/event_sourcing/repository.rb +36 -1
- data/lib/synapse/configuration/component/repository.rb +4 -8
- data/lib/synapse/configuration/component/serialization.rb +5 -16
- data/lib/synapse/configuration/component/uow.rb +3 -8
- data/lib/synapse/configuration/component/upcasting.rb +3 -8
- data/lib/synapse/configuration/container_builder.rb +29 -2
- data/lib/synapse/configuration/definition_builder.rb +47 -23
- data/lib/synapse/domain/message.rb +0 -16
- data/lib/synapse/event_bus.rb +1 -1
- data/lib/synapse/event_bus/event_listener.rb +1 -1
- data/lib/synapse/event_bus/mapping.rb +47 -0
- data/lib/synapse/event_sourcing.rb +3 -2
- data/lib/synapse/event_sourcing/aggregate_factory.rb +4 -3
- data/lib/synapse/event_sourcing/aggregate_root.rb +17 -0
- data/lib/synapse/event_sourcing/conflict_resolver.rb +3 -0
- data/lib/synapse/event_sourcing/member.rb +34 -6
- data/lib/synapse/event_sourcing/repository.rb +17 -0
- data/lib/synapse/event_sourcing/snapshot/aggregate_taker.rb +38 -0
- data/lib/synapse/event_sourcing/snapshot/policy.rb +27 -0
- data/lib/synapse/event_sourcing/snapshot/taker.rb +2 -37
- data/lib/synapse/event_sourcing/snapshot/unit_listener.rb +26 -0
- data/lib/synapse/event_sourcing/stream_decorator.rb +8 -6
- data/lib/synapse/event_store/errors.rb +2 -2
- data/lib/synapse/mapping.rb +2 -0
- data/lib/synapse/mapping/mapper.rb +75 -0
- data/lib/synapse/{wiring/wire.rb → mapping/mapping.rb} +8 -8
- data/lib/synapse/process_manager.rb +2 -2
- data/lib/synapse/process_manager/mapping/process.rb +44 -0
- data/lib/synapse/process_manager/{wiring → mapping}/process_manager.rb +13 -13
- data/lib/synapse/process_manager/process.rb +3 -3
- data/lib/synapse/repository/locking.rb +14 -8
- data/lib/synapse/upcasting/upcaster_chain.rb +2 -2
- data/lib/synapse/version.rb +1 -1
- data/test/command/{wiring_test.rb → mapping_test.rb} +11 -11
- data/test/configuration/component/command_bus/simple_command_bus_test.rb +30 -0
- data/test/configuration/component/event_bus/simple_event_bus_test.rb +2 -2
- data/test/configuration/component/event_sourcing/repository_test.rb +71 -0
- data/test/configuration/component/repository/simple_repository_test.rb +35 -0
- data/test/configuration/component/upcasting/upcaster_chain_test.rb +29 -0
- data/test/configuration/container_builder_test.rb +4 -6
- data/test/event_bus/{wiring_test.rb → mapping_test.rb} +6 -6
- data/test/event_sourcing/aggregate_factory_test.rb +5 -1
- data/test/event_sourcing/aggregate_root_test.rb +1 -0
- data/test/event_sourcing/fixtures.rb +21 -21
- data/test/event_sourcing/repository_test.rb +10 -0
- data/test/event_sourcing/snapshot/aggregate_taker_test.rb +1 -1
- data/test/event_sourcing/snapshot/interval_policy_test.rb +24 -0
- data/test/process_manager/{wiring → mapping}/fixtures.rb +7 -8
- data/test/process_manager/{wiring → mapping}/process_manager_test.rb +6 -6
- data/test/process_manager/{wiring → mapping}/process_test.rb +3 -3
- data/test/serialization/converter/chain_test.rb +2 -2
- data/test/serialization/converter/factory_test.rb +2 -2
- data/test/serialization/converter/identity_test.rb +1 -1
- data/test/serialization/converter/json_test.rb +2 -2
- data/test/serialization/converter/ox_test.rb +2 -2
- data/test/serialization/lazy_object_test.rb +1 -1
- data/test/serialization/message/metadata_test.rb +1 -1
- data/test/serialization/message/serialization_aware_message_test.rb +5 -5
- data/test/serialization/message/serialized_message_builder_test.rb +1 -1
- data/test/serialization/message/serialized_message_test.rb +5 -5
- data/test/serialization/message/serializer_test.rb +2 -2
- data/test/serialization/revision_resolver_test.rb +1 -1
- data/test/serialization/serialized_object_test.rb +2 -2
- data/test/serialization/serialized_type_test.rb +2 -2
- data/test/serialization/serializer/marshal_test.rb +1 -1
- data/test/serialization/serializer/oj_test.rb +1 -1
- data/test/serialization/serializer/ox_test.rb +2 -2
- data/test/serialization/serializer_test.rb +1 -1
- data/test/uow/factory_test.rb +1 -1
- data/test/uow/outer_commit_listener_test.rb +4 -4
- data/test/uow/provider_test.rb +5 -5
- data/test/uow/uow_test.rb +19 -17
- data/test/upcasting/chain_test.rb +1 -1
- data/test/upcasting/data_test.rb +3 -1
- metadata +30 -37
- data/lib/synapse/command/wiring.rb +0 -47
- data/lib/synapse/event_bus/wiring.rb +0 -20
- data/lib/synapse/event_sourcing/snapshot/count_stream.rb +0 -86
- data/lib/synapse/event_sourcing/snapshot/count_trigger.rb +0 -91
- data/lib/synapse/process_manager/wiring/process.rb +0 -27
- data/lib/synapse/wiring.rb +0 -3
- data/lib/synapse/wiring/message_wiring.rb +0 -76
- data/lib/synapse/wiring/wire_registry.rb +0 -61
- data/test/event_sourcing/snapshot/integration_test.rb +0 -65
- data/test/wiring/wire_registry_test.rb +0 -60
- data/test/wiring/wire_test.rb +0 -51
@@ -8,6 +8,7 @@ require 'synapse/event_sourcing/member'
|
|
8
8
|
require 'synapse/event_sourcing/aggregate_root'
|
9
9
|
require 'synapse/event_sourcing/entity'
|
10
10
|
|
11
|
-
require 'synapse/event_sourcing/snapshot/
|
12
|
-
require 'synapse/event_sourcing/snapshot/count_trigger'
|
11
|
+
require 'synapse/event_sourcing/snapshot/policy'
|
13
12
|
require 'synapse/event_sourcing/snapshot/taker'
|
13
|
+
require 'synapse/event_sourcing/snapshot/aggregate_taker'
|
14
|
+
require 'synapse/event_sourcing/snapshot/unit_listener'
|
@@ -21,7 +21,7 @@ module Synapse
|
|
21
21
|
# @abstract
|
22
22
|
# @return [String] Type identifier used to store the aggregate in the event store
|
23
23
|
def type_identifier; end
|
24
|
-
end
|
24
|
+
end # AggregateFactory
|
25
25
|
|
26
26
|
# Aggregate factory that uses a convention to create instances of aggregates
|
27
27
|
class GenericAggregateFactory < AggregateFactory
|
@@ -46,6 +46,7 @@ module Synapse
|
|
46
46
|
|
47
47
|
if payload.is_a? AggregateRoot
|
48
48
|
aggregate = payload
|
49
|
+
aggregate.reset_initial_version
|
49
50
|
else
|
50
51
|
aggregate = @aggregate_type.allocate
|
51
52
|
end
|
@@ -64,6 +65,6 @@ module Synapse
|
|
64
65
|
def post_process(aggregate)
|
65
66
|
aggregate
|
66
67
|
end
|
67
|
-
end
|
68
|
-
end
|
68
|
+
end # GenericAggregateFactory
|
69
|
+
end # EventSourcing
|
69
70
|
end
|
@@ -19,11 +19,26 @@ module Synapse
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
# The sequence number of the first event that the aggregate was initialized from
|
23
|
+
#
|
24
|
+
# If the aggregate was initialized from a snapshot, this should be reset to the sequence
|
25
|
+
# number of the last event in the snapshot. Otherwise, this will be the sequence number
|
26
|
+
# of the first event contained in the event stream used to initialize the aggregate.
|
27
|
+
#
|
28
|
+
# @return [Integer]
|
29
|
+
attr_reader :initial_version
|
30
|
+
|
22
31
|
# @return [Integer] The sequence number of the last committed event
|
23
32
|
def version
|
24
33
|
last_committed_sequence_number
|
25
34
|
end
|
26
35
|
|
36
|
+
# Resets the initial version to the current version of the aggregate
|
37
|
+
# @return [undefined]
|
38
|
+
def reset_initial_version
|
39
|
+
@initial_version = last_committed_sequence_number
|
40
|
+
end
|
41
|
+
|
27
42
|
# Initializes the state of this aggregate from the given domain event stream
|
28
43
|
#
|
29
44
|
# @raise [RuntimeError] If aggregate has already been initialized
|
@@ -36,6 +51,8 @@ module Synapse
|
|
36
51
|
|
37
52
|
pre_initialize
|
38
53
|
|
54
|
+
@initial_version = stream.peek.sequence_number
|
55
|
+
|
39
56
|
last_sequence_number = nil
|
40
57
|
|
41
58
|
stream.each do |event|
|
@@ -2,11 +2,14 @@ module Synapse
|
|
2
2
|
module EventSourcing
|
3
3
|
# Represents a mechanism that is capable of detecting conflicts between applied changes
|
4
4
|
# to the aggregate and unseen changes made to the aggregate.
|
5
|
+
#
|
6
|
+
# @abstract
|
5
7
|
class ConflictResolver
|
6
8
|
# Checks the list of changes applied to the aggregate and compares it to the list of
|
7
9
|
# events already applied to the aggregate. If a conflict is detected, this should throw
|
8
10
|
# an exception. Otherwise, the changes will be applied.
|
9
11
|
#
|
12
|
+
# @abstract
|
10
13
|
# @raise [ConflictingModificationException] If any conflicts were detected
|
11
14
|
# @param [Array] applied_changes List of changes applied to the aggregate
|
12
15
|
# @param [Array] committed_changes List of events that were unexpected by the command handler
|
@@ -4,7 +4,17 @@ module Synapse
|
|
4
4
|
# applied to the aggregate
|
5
5
|
module Member
|
6
6
|
extend ActiveSupport::Concern
|
7
|
-
|
7
|
+
|
8
|
+
included do
|
9
|
+
# @return [Mapper::Mapping]
|
10
|
+
class_attribute :command_mapper
|
11
|
+
|
12
|
+
# @return [Mapper::Mapping]
|
13
|
+
class_attribute :event_mapper
|
14
|
+
|
15
|
+
self.command_mapper = Mapping::Mapper.new false
|
16
|
+
self.event_mapper = Mapping::Mapper.new true
|
17
|
+
end
|
8
18
|
|
9
19
|
module ClassMethods
|
10
20
|
# Registers an instance variable as a child entity
|
@@ -22,6 +32,24 @@ module Synapse
|
|
22
32
|
def child_entities
|
23
33
|
@child_entities ||= Set.new
|
24
34
|
end
|
35
|
+
|
36
|
+
# @see Mapper#map
|
37
|
+
# @param [Class] type
|
38
|
+
# @param [Object...] args
|
39
|
+
# @param [Proc] block
|
40
|
+
# @return [undefined]
|
41
|
+
def map_command(type, *args, &block)
|
42
|
+
commnad_mapper.map type, *args, &block
|
43
|
+
end
|
44
|
+
|
45
|
+
# @see Mapper#map
|
46
|
+
# @param [Class] type
|
47
|
+
# @param [Object...] args
|
48
|
+
# @param [Proc] block
|
49
|
+
# @return [undefined]
|
50
|
+
def map_event(type, *args, &block)
|
51
|
+
event_mapper.map type, *args, &block
|
52
|
+
end
|
25
53
|
end
|
26
54
|
|
27
55
|
protected
|
@@ -57,9 +85,9 @@ module Synapse
|
|
57
85
|
# @param [EventMessage] event
|
58
86
|
# @return [undefined]
|
59
87
|
def handle_event(event)
|
60
|
-
|
61
|
-
if
|
62
|
-
|
88
|
+
mapping = self.event_mapper.mapping_for event.payload_type
|
89
|
+
if mapping
|
90
|
+
mapping.invoke self, event.payload
|
63
91
|
end
|
64
92
|
end
|
65
93
|
|
@@ -72,6 +100,6 @@ module Synapse
|
|
72
100
|
entity.is_a? Member
|
73
101
|
end
|
74
102
|
end
|
75
|
-
end
|
76
|
-
end
|
103
|
+
end # Member
|
104
|
+
end # EventSourcing
|
77
105
|
end
|
@@ -12,6 +12,12 @@ module Synapse
|
|
12
12
|
# @return [EventStore]
|
13
13
|
attr_reader :event_store
|
14
14
|
|
15
|
+
# @return [SnapshotPolicy]
|
16
|
+
attr_accessor :snapshot_policy
|
17
|
+
|
18
|
+
# @return [SnapshotTaker]
|
19
|
+
attr_accessor :snapshot_taker
|
20
|
+
|
15
21
|
# @return [Array<EventStreamDecorator>]
|
16
22
|
attr_reader :stream_decorators
|
17
23
|
|
@@ -76,6 +82,17 @@ module Synapse
|
|
76
82
|
aggregate
|
77
83
|
end
|
78
84
|
|
85
|
+
# @param [AggregateRoot] aggregate
|
86
|
+
# @return [undefined]
|
87
|
+
def post_registration(aggregate)
|
88
|
+
if @snapshot_policy and @snapshot_taker
|
89
|
+
listener =
|
90
|
+
SnapshotUnitOfWorkListener.new type_identifier, aggregate, @snapshot_policy, @snapshot_taker
|
91
|
+
|
92
|
+
register_listener listener
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
79
96
|
# @return [Class]
|
80
97
|
def aggregate_type
|
81
98
|
@aggregate_factory.aggregate_type
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Synapse
|
2
|
+
module EventSourcing
|
3
|
+
# Snapshot taker that uses the actual aggregate and its state to create a snapshot event
|
4
|
+
class AggregateSnapshotTaker < SnapshotTaker
|
5
|
+
# @param [SnapshotEventStore] event_store
|
6
|
+
# @return [undefined]
|
7
|
+
def initialize(event_store)
|
8
|
+
@aggregate_factories = Hash.new
|
9
|
+
@event_store = event_store
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param [AggregateFactory] factory
|
13
|
+
# @return [undefined]
|
14
|
+
def register_factory(factory)
|
15
|
+
@aggregate_factories.store factory.type_identifier, factory
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param [String] type_identifier
|
19
|
+
# @param [Object] aggregate_id
|
20
|
+
# @return [undefined]
|
21
|
+
def schedule_snapshot(type_identifier, aggregate_id)
|
22
|
+
stream = @event_store.read_events type_identifier, aggregate_id
|
23
|
+
factory = @aggregate_factories.fetch type_identifier
|
24
|
+
|
25
|
+
aggregate = factory.create_aggregate aggregate_id, stream.peek
|
26
|
+
aggregate.initialize_from_stream stream
|
27
|
+
|
28
|
+
snapshot = Domain::DomainEventMessage.build do |builder|
|
29
|
+
builder.payload = aggregate
|
30
|
+
builder.aggregate_id = aggregate.id
|
31
|
+
builder.sequence_number = aggregate.version
|
32
|
+
end
|
33
|
+
|
34
|
+
@event_store.append_snapshot_event type_identifier, snapshot
|
35
|
+
end
|
36
|
+
end # AggregateSnapshotTaker
|
37
|
+
end # EventSourcing
|
38
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Synapse
|
2
|
+
module EventSourcing
|
3
|
+
# Represents a mechanism for determining if an aggregate should have a snapshot taken
|
4
|
+
class SnapshotPolicy
|
5
|
+
# Returns true if a snapshot should be scheduled for the given aggregate
|
6
|
+
#
|
7
|
+
# @param [AggregateRoot] aggregate
|
8
|
+
# @return [Boolean]
|
9
|
+
def should_snapshot?(aggregate); end
|
10
|
+
end # SnapshotPolicy
|
11
|
+
|
12
|
+
# Snapshot policy that takes a snapshot if the number of events committed in an aggregate since
|
13
|
+
# the last snapshot goes over the configured threshold
|
14
|
+
class IntervalSnapshotPolicy < SnapshotPolicy
|
15
|
+
# @return [undefined]
|
16
|
+
def initialize(threshold)
|
17
|
+
@threshold = threshold
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param [AggregateRoot] aggregate
|
21
|
+
# @return [Boolean]
|
22
|
+
def should_snapshot?(aggregate)
|
23
|
+
(aggregate.version - (aggregate.initial_version or 0)) >= @threshold
|
24
|
+
end
|
25
|
+
end # IntervalSnapshotPolicy
|
26
|
+
end # EventSourcing
|
27
|
+
end
|
@@ -15,41 +15,6 @@ module Synapse
|
|
15
15
|
# @param [Object] aggregate_id
|
16
16
|
# @return [undefined]
|
17
17
|
def schedule_snapshot(type_identifier, aggregate_id); end
|
18
|
-
end
|
19
|
-
|
20
|
-
# Snapshot taker that uses the actual aggregate and its state to create a snapshot event
|
21
|
-
class AggregateSnapshotTaker < SnapshotTaker
|
22
|
-
# @param [SnapshotEventStore] event_store
|
23
|
-
# @return [undefined]
|
24
|
-
def initialize(event_store)
|
25
|
-
@aggregate_factories = Hash.new
|
26
|
-
@event_store = event_store
|
27
|
-
end
|
28
|
-
|
29
|
-
# @param [AggregateFactory] factory
|
30
|
-
# @return [undefined]
|
31
|
-
def register_factory(factory)
|
32
|
-
@aggregate_factories.store factory.type_identifier, factory
|
33
|
-
end
|
34
|
-
|
35
|
-
# @param [String] type_identifier
|
36
|
-
# @param [Object] aggregate_id
|
37
|
-
# @return [undefined]
|
38
|
-
def schedule_snapshot(type_identifier, aggregate_id)
|
39
|
-
stream = @event_store.read_events type_identifier, aggregate_id
|
40
|
-
factory = @aggregate_factories.fetch type_identifier
|
41
|
-
|
42
|
-
aggregate = factory.create_aggregate aggregate_id, stream.peek
|
43
|
-
aggregate.initialize_from_stream stream
|
44
|
-
|
45
|
-
snapshot = Domain::DomainEventMessage.build do |builder|
|
46
|
-
builder.payload = aggregate
|
47
|
-
builder.aggregate_id = aggregate.id
|
48
|
-
builder.sequence_number = aggregate.version
|
49
|
-
end
|
50
|
-
|
51
|
-
@event_store.append_snapshot_event type_identifier, snapshot
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
18
|
+
end # SnapshotTaker
|
19
|
+
end # EventSourcing
|
55
20
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Synapse
|
2
|
+
module EventSourcing
|
3
|
+
# Unit of work listener that schedules snapshots
|
4
|
+
class SnapshotUnitOfWorkListener < UnitOfWork::UnitOfWorkListener
|
5
|
+
# @param [String] type_identifier
|
6
|
+
# @param [AggregateRoot] aggregate
|
7
|
+
# @param [SnapshotPolicy] policy
|
8
|
+
# @param [SnapshotTaker] taker
|
9
|
+
# @return [undefined]
|
10
|
+
def initialize(type_identifier, aggregate, policy, taker)
|
11
|
+
@type_identifier = type_identifier
|
12
|
+
@aggregate = aggregate
|
13
|
+
@policy = policy
|
14
|
+
@taker = taker
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param [UnitOfWork] unit
|
18
|
+
# @return [undefined]
|
19
|
+
def on_cleanup(unit)
|
20
|
+
if @policy.should_snapshot? @aggregate
|
21
|
+
@taker.schedule_snapshot @type_identifier, @aggregate.id
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end # SnapshotUnitOfWorkListener
|
25
|
+
end # EventSourcing
|
26
|
+
end
|
@@ -5,21 +5,23 @@ module Synapse
|
|
5
5
|
class EventStreamDecorator
|
6
6
|
# Decorates an event stream when it is read from the event store
|
7
7
|
#
|
8
|
-
# @abstract
|
9
8
|
# @param [String] type_identifier
|
10
9
|
# @param [Object] aggregate_id
|
11
10
|
# @param [DomainEventStream] stream
|
12
11
|
# @return [DomainEventStream]
|
13
|
-
def decorate_for_read(type_identifier, aggregate_id, stream)
|
12
|
+
def decorate_for_read(type_identifier, aggregate_id, stream)
|
13
|
+
stream
|
14
|
+
end
|
14
15
|
|
15
16
|
# Decorates an event stream when it is appended to the event store
|
16
17
|
#
|
17
|
-
# @abstract
|
18
18
|
# @param [String] type_identifier
|
19
19
|
# @param [AggregateRoot] aggregate
|
20
20
|
# @param [DomainEventStream] stream
|
21
21
|
# @return [DomainEventStream]
|
22
|
-
def decorate_for_append(type_identifier, aggregate, stream)
|
23
|
-
|
24
|
-
|
22
|
+
def decorate_for_append(type_identifier, aggregate, stream)
|
23
|
+
stream
|
24
|
+
end
|
25
|
+
end # EventStreamDecorator
|
26
|
+
end # EventSourcing
|
25
27
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Synapse
|
2
|
+
module Mapping
|
3
|
+
class Mapper
|
4
|
+
# @param [Boolean] duplicates_allowed
|
5
|
+
# @return [undefined]
|
6
|
+
def initialize(duplicates_allowed)
|
7
|
+
@duplicates_allowed = duplicates_allowed
|
8
|
+
@mappings = Array.new
|
9
|
+
end
|
10
|
+
|
11
|
+
# Yields the type that each mapping is registered for
|
12
|
+
#
|
13
|
+
# @yield [Class]
|
14
|
+
# @return [undefined]
|
15
|
+
def each_type
|
16
|
+
@mappings.each do |mapping|
|
17
|
+
yield mapping.type
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# @raise [DuplicateMappingError] If duplicates aren't allowed and another mapping exists that
|
22
|
+
# maps the exact same type as the given mapping
|
23
|
+
# @param [Class] type
|
24
|
+
# @param [Object...] args
|
25
|
+
# @param [Proc] block
|
26
|
+
# @return [undefined]
|
27
|
+
def map(type, *args, &block)
|
28
|
+
options = args.extract_options!
|
29
|
+
mapping = create_from type, options, &block
|
30
|
+
|
31
|
+
unless @duplicates_allowed
|
32
|
+
if @mappings.include? mapping
|
33
|
+
raise DuplicateMappingError
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
@mappings.push mapping
|
38
|
+
@mappings.sort!
|
39
|
+
end
|
40
|
+
|
41
|
+
# Retrieves the most specific mapping for a given type, if any
|
42
|
+
#
|
43
|
+
# @param [Class] target_type
|
44
|
+
# @return [Mapping]
|
45
|
+
def mapping_for(target_type)
|
46
|
+
@mappings.find do |mapping|
|
47
|
+
mapping.type >= target_type
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# @param [Class] type
|
54
|
+
# @param [Hash] options
|
55
|
+
# @param [Proc] block
|
56
|
+
# @return [Mapping]
|
57
|
+
def create_from(type, options, &block)
|
58
|
+
to = options.delete :to
|
59
|
+
unless to
|
60
|
+
unless block
|
61
|
+
raise ArgumentError, 'Expected block or option :to'
|
62
|
+
end
|
63
|
+
|
64
|
+
to = block
|
65
|
+
end
|
66
|
+
|
67
|
+
Mapping.new type, options, to
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Raised if a mapping registry doesn't allow duplicates and an attempt is made to map the same
|
72
|
+
# type to multiple handlers
|
73
|
+
class DuplicateMappingError < NonTransientError; end
|
74
|
+
end
|
75
|
+
end
|