synapse-core 0.5.1 → 0.5.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.
- 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
|