omnes 0.1.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 +7 -0
- data/.github/workflows/lint.yml +24 -0
- data/.github/workflows/test.yml +26 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +44 -0
- data/.travis.yml +6 -0
- data/.yardopts +9 -0
- data/CHANGELOG.md +11 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +92 -0
- data/LICENSE.txt +21 -0
- data/README.md +617 -0
- data/Rakefile +8 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/lib/omnes/bus.rb +274 -0
- data/lib/omnes/errors.rb +101 -0
- data/lib/omnes/event.rb +72 -0
- data/lib/omnes/execution.rb +42 -0
- data/lib/omnes/publication.rb +43 -0
- data/lib/omnes/registry.rb +102 -0
- data/lib/omnes/subscriber/adapter/active_job.rb +74 -0
- data/lib/omnes/subscriber/adapter/method/errors.rb +51 -0
- data/lib/omnes/subscriber/adapter/method.rb +45 -0
- data/lib/omnes/subscriber/adapter/sidekiq.rb +92 -0
- data/lib/omnes/subscriber/adapter.rb +33 -0
- data/lib/omnes/subscriber/errors.rb +24 -0
- data/lib/omnes/subscriber/state.rb +68 -0
- data/lib/omnes/subscriber.rb +229 -0
- data/lib/omnes/subscription.rb +58 -0
- data/lib/omnes/unstructured_event.rb +42 -0
- data/lib/omnes/version.rb +5 -0
- data/lib/omnes.rb +83 -0
- data/omnes.gemspec +45 -0
- metadata +157 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "omnes/errors"
|
4
|
+
|
5
|
+
module Omnes
|
6
|
+
module Subscriber
|
7
|
+
module Adapter
|
8
|
+
class Method
|
9
|
+
# Raised when trying to subscribe to a missing method
|
10
|
+
class UnknownMethodSubscriptionAttemptError < Omnes::Error
|
11
|
+
attr_reader :method_name
|
12
|
+
|
13
|
+
# @api private
|
14
|
+
def initialize(method_name:)
|
15
|
+
@method_name = method_name
|
16
|
+
super(default_message)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def default_message
|
22
|
+
<<~MSG
|
23
|
+
You tried to subscribe an unexisting "#{method_name}" method. Event
|
24
|
+
handlers need to be public methods on the subscriber class.
|
25
|
+
MSG
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Raised when trying to subscribe to a private method
|
30
|
+
class PrivateMethodSubscriptionAttemptError < Omnes::Error
|
31
|
+
attr_reader :method_name
|
32
|
+
|
33
|
+
# @api private
|
34
|
+
def initialize(method_name:)
|
35
|
+
@method_name = method_name
|
36
|
+
super(default_message)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def default_message
|
42
|
+
<<~MSG
|
43
|
+
You tried to subscribe "#{method_name}" private method. Event handlers
|
44
|
+
need to be public methods on the subscriber class.
|
45
|
+
MSG
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "omnes/subscriber/adapter/method/errors"
|
4
|
+
|
5
|
+
module Omnes
|
6
|
+
module Subscriber
|
7
|
+
module Adapter
|
8
|
+
# Builds a callback from a method of the instance
|
9
|
+
#
|
10
|
+
# You can use instance of this class as the adapter:
|
11
|
+
#
|
12
|
+
# ```ruby
|
13
|
+
# handle :foo, with: Adapter::Method.new(:foo)
|
14
|
+
# ```
|
15
|
+
#
|
16
|
+
# However, you can short-circuit with a {Symbol}.
|
17
|
+
#
|
18
|
+
# ```ruby
|
19
|
+
# handle :foo, with: :foo
|
20
|
+
# ```
|
21
|
+
class Method
|
22
|
+
attr_reader :name
|
23
|
+
|
24
|
+
def initialize(name)
|
25
|
+
@name = name
|
26
|
+
end
|
27
|
+
|
28
|
+
# @api private
|
29
|
+
def call(instance)
|
30
|
+
check_method(instance)
|
31
|
+
|
32
|
+
->(event) { instance.method(name).(event) }
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def check_method(instance)
|
38
|
+
raise PrivateMethodSubscriptionAttemptError.new(method_name: name) if instance.private_methods.include?(name)
|
39
|
+
|
40
|
+
raise UnknownMethodSubscriptionAttemptError.new(method_name: name) unless instance.methods.include?(name)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/configurable"
|
4
|
+
|
5
|
+
module Omnes
|
6
|
+
module Subscriber
|
7
|
+
module Adapter
|
8
|
+
# [Sidekiq](https://sidekiq.org/) adapter
|
9
|
+
#
|
10
|
+
# Builds subscription to be processed as Sidekiq's background jobs.
|
11
|
+
#
|
12
|
+
# Sidekiq requires that the argument passed to `#perform` is serializable.
|
13
|
+
# By default, the result of calling `#payload` in the event is taken.
|
14
|
+
#
|
15
|
+
# ```
|
16
|
+
# class MySubscriber
|
17
|
+
# include Omnes::Subscriber
|
18
|
+
# include Sidekiq::Job
|
19
|
+
#
|
20
|
+
# handle :my_event, with: Adapter::Sidekiq
|
21
|
+
#
|
22
|
+
# def perform(payload)
|
23
|
+
# # do_something
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# bus = Omnes::Bus.new
|
28
|
+
# bus.register(:my_event)
|
29
|
+
# bus.publish(:my_event, "foo" => "bar")
|
30
|
+
# ```
|
31
|
+
#
|
32
|
+
# However, you can configure how the event is serialized thanks to the
|
33
|
+
# `serializer:` option. It needs to be something callable taking the
|
34
|
+
# event as argument:
|
35
|
+
#
|
36
|
+
# ```
|
37
|
+
# handle :my_event, with: Adapter::Sidekiq[serializer: :serialized_payload.to_proc]
|
38
|
+
# ```
|
39
|
+
#
|
40
|
+
# You can also globally configure the default serializer:
|
41
|
+
#
|
42
|
+
# ```
|
43
|
+
# Omnes.config.subscriber.adapter.sidekiq.serializer = :serialized_payload.to_proc
|
44
|
+
# ```
|
45
|
+
#
|
46
|
+
# You can delay the callback execution from the publication time with the
|
47
|
+
# {.in} method (analogous to {Sidekiq::Job.perform_in}).
|
48
|
+
#
|
49
|
+
# @example
|
50
|
+
# handle :my_event, with: Adapter::Sidekiq.in(60)
|
51
|
+
module Sidekiq
|
52
|
+
extend Dry::Configurable
|
53
|
+
|
54
|
+
setting :serializer, default: :payload.to_proc
|
55
|
+
|
56
|
+
# @param serializer [#call]
|
57
|
+
def self.[](serializer: config.serializer)
|
58
|
+
Instance.new(serializer: serializer)
|
59
|
+
end
|
60
|
+
|
61
|
+
# @api private
|
62
|
+
def self.call(instance, event)
|
63
|
+
self.[].(instance, event)
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param seconds [Integer]
|
67
|
+
def self.in(seconds)
|
68
|
+
self.[].in(seconds)
|
69
|
+
end
|
70
|
+
|
71
|
+
# @api private
|
72
|
+
class Instance
|
73
|
+
attr_reader :serializer
|
74
|
+
|
75
|
+
def initialize(serializer:)
|
76
|
+
@serializer = serializer
|
77
|
+
end
|
78
|
+
|
79
|
+
def call(instance, event)
|
80
|
+
instance.class.perform_async(serializer.(event))
|
81
|
+
end
|
82
|
+
|
83
|
+
def in(seconds)
|
84
|
+
lambda do |instance, event|
|
85
|
+
instance.class.perform_in(seconds, serializer.(event))
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "omnes/subscriber/adapter/active_job"
|
4
|
+
require "omnes/subscriber/adapter/method"
|
5
|
+
require "omnes/subscriber/adapter/sidekiq"
|
6
|
+
|
7
|
+
module Omnes
|
8
|
+
module Subscriber
|
9
|
+
# Adapters to build {Omnes::Subscription}'s callbacks
|
10
|
+
#
|
11
|
+
# Adapters need to implement a method `#call` taking the instance of
|
12
|
+
# {Omnes::Subscriber} and the event.
|
13
|
+
#
|
14
|
+
# Alternatively, they can be curried and only take the instance as an
|
15
|
+
# argument, returning a one-argument callable taking the event.
|
16
|
+
module Adapter
|
17
|
+
# @api private
|
18
|
+
# TODO: Simplify when when we can take callables and Proc in a polymorphic
|
19
|
+
# way: https://bugs.ruby-lang.org/issues/18644
|
20
|
+
# > builder.to_proc.curry[instance]
|
21
|
+
def self.Type(value)
|
22
|
+
case value
|
23
|
+
when Symbol
|
24
|
+
Type(Method.new(value))
|
25
|
+
when Proc
|
26
|
+
value
|
27
|
+
else
|
28
|
+
value.method(:call)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "omnes/errors"
|
4
|
+
|
5
|
+
module Omnes
|
6
|
+
module Subscriber
|
7
|
+
# Raised when subscribing the same subscriber instance to the same bus twice
|
8
|
+
class MultipleSubscriberSubscriptionAttemptError < Omnes::Error
|
9
|
+
# @api private
|
10
|
+
def initialize
|
11
|
+
super(default_message)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def default_message
|
17
|
+
<<~MSG
|
18
|
+
Omnes::Subscriber#subscribe_to method can only be called once for a
|
19
|
+
given instance on a given bus
|
20
|
+
MSG
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "omnes/subscriber/adapter"
|
4
|
+
require "omnes/subscriber/errors"
|
5
|
+
require "omnes/subscription"
|
6
|
+
|
7
|
+
module Omnes
|
8
|
+
module Subscriber
|
9
|
+
# @api private
|
10
|
+
class State
|
11
|
+
attr_reader :subscription_definitions, :calling_cache, :autodiscover_strategy
|
12
|
+
|
13
|
+
def initialize(autodiscover_strategy:, subscription_definitions: [], calling_cache: [])
|
14
|
+
@subscription_definitions = subscription_definitions
|
15
|
+
@calling_cache = calling_cache
|
16
|
+
@autodiscover_strategy = autodiscover_strategy
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(bus, instance)
|
20
|
+
raise MultipleSubscriberSubscriptionAttemptError if already_called?(bus, instance)
|
21
|
+
|
22
|
+
autodiscover_subscription_definitions(bus, instance) unless autodiscover_strategy.nil?
|
23
|
+
|
24
|
+
definitions = subscription_definitions.map { |defn| defn.(bus) }
|
25
|
+
|
26
|
+
subscribe_definitions(definitions, bus, instance).tap do
|
27
|
+
mark_as_called(bus, instance)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_subscription_definition(&block)
|
32
|
+
@subscription_definitions << block
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def already_called?(bus, instance)
|
38
|
+
calling_cache.include?([bus, instance])
|
39
|
+
end
|
40
|
+
|
41
|
+
def mark_as_called(bus, instance)
|
42
|
+
@calling_cache << [bus, instance]
|
43
|
+
end
|
44
|
+
|
45
|
+
def autodiscover_subscription_definitions(bus, instance)
|
46
|
+
bus.registry.event_names.each do |event_name|
|
47
|
+
method_name = autodiscover_strategy.(event_name)
|
48
|
+
next unless instance.respond_to?(method_name, true)
|
49
|
+
|
50
|
+
add_subscription_definition do |_bus|
|
51
|
+
[
|
52
|
+
Subscription::SINGLE_EVENT_MATCHER.curry[event_name],
|
53
|
+
Adapter.Type(Adapter::Method.new(method_name))
|
54
|
+
]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def subscribe_definitions(definitions, bus, instance)
|
60
|
+
matcher_with_callbacks = definitions.map do |(matcher, adapter)|
|
61
|
+
[matcher, adapter.curry[instance]]
|
62
|
+
end
|
63
|
+
|
64
|
+
matcher_with_callbacks.map { |matcher, callback| bus.subscribe_with_matcher(matcher, callback) }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/configurable"
|
4
|
+
require "omnes/subscriber/adapter"
|
5
|
+
require "omnes/subscriber/state"
|
6
|
+
require "omnes/subscription"
|
7
|
+
|
8
|
+
module Omnes
|
9
|
+
# Supscriptions provider for a {Omnes::Bus}
|
10
|
+
#
|
11
|
+
# This module allows an including class to use its context to create event
|
12
|
+
# handlers.
|
13
|
+
#
|
14
|
+
# In its simplest form, you can match an event to a method in the class.
|
15
|
+
#
|
16
|
+
# ```
|
17
|
+
# class MySubscriber
|
18
|
+
# include Omnes::Subscriber
|
19
|
+
#
|
20
|
+
# handle :foo, with: :my_handler
|
21
|
+
#
|
22
|
+
# def my_handler(event)
|
23
|
+
# # do_something
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# ```
|
27
|
+
#
|
28
|
+
# Equivalent to the subscribe methods in {Omnes::Bus}, you can also subscribe
|
29
|
+
# to all events or use a custom matcher:
|
30
|
+
#
|
31
|
+
# ```
|
32
|
+
# class MySubscriber
|
33
|
+
# include Omnes::Subscriber
|
34
|
+
#
|
35
|
+
# handle_all with: :my_handler_one
|
36
|
+
# handle_with_matcher my_matcher, with: :my_handler_two
|
37
|
+
#
|
38
|
+
# def my_handler_one(event)
|
39
|
+
# # do_something
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# def my_handler_two(event)
|
43
|
+
# # do_something_else
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
# ```
|
47
|
+
#
|
48
|
+
# Another option is to let the event handlers be automatically discovered. You
|
49
|
+
# need to enable the `autodiscover` feature and prefix the event name with
|
50
|
+
# `on_` for your handler name.
|
51
|
+
#
|
52
|
+
# ```
|
53
|
+
# class MySubscriber
|
54
|
+
# include Omnes::Subscriber[
|
55
|
+
# autodiscover: true
|
56
|
+
# ]
|
57
|
+
#
|
58
|
+
# def on_foo(event)
|
59
|
+
# # do_something
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
# ```
|
63
|
+
#
|
64
|
+
# If you prefer, you can make `autodiscover` on by default:
|
65
|
+
#
|
66
|
+
# ```
|
67
|
+
# Omnes.config.subscriber.autodiscover = true
|
68
|
+
# ```
|
69
|
+
#
|
70
|
+
# You can specify your own autodiscover strategy. It must be something
|
71
|
+
# callable, transforming the event name into the handler name.
|
72
|
+
#
|
73
|
+
# ```
|
74
|
+
# AUTODISCOVER_STRATEGY = ->(event_name) { event_name }
|
75
|
+
#
|
76
|
+
# class MySubscriber
|
77
|
+
# include Omnes::Subscriber[
|
78
|
+
# autodiscover: true,
|
79
|
+
# autodiscover_strategy: AUTODISCOVER_STRATEGY
|
80
|
+
# ]
|
81
|
+
#
|
82
|
+
# def foo(event)
|
83
|
+
# # do_something
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
# ```
|
87
|
+
# You're not limited to using method names as event handlers. You can create
|
88
|
+
# your own adapters from the subscriber instance context.
|
89
|
+
#
|
90
|
+
# ```
|
91
|
+
# ADAPTER = lambda do |instance, event|
|
92
|
+
# event.foo? ? instance.foo_true(event) : instance.foo_false(event)
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# class MySubscriber
|
96
|
+
# include Omnes::Subscriber
|
97
|
+
#
|
98
|
+
# handle :my_event, with: ADAPTER
|
99
|
+
#
|
100
|
+
# def foo_true(event)
|
101
|
+
# # do_something
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# def foo_false(event)
|
105
|
+
# # do_something_else
|
106
|
+
# end
|
107
|
+
# end
|
108
|
+
# ```
|
109
|
+
#
|
110
|
+
# Subscriber adapters can be leveraged to build integrations with background
|
111
|
+
# job libraries. See {Omnes::Subscriber::Adapter} for what comes shipped with
|
112
|
+
# the library.
|
113
|
+
#
|
114
|
+
# Once you've defined the event handlers, you can subscribe to a {Omnes::Bus}
|
115
|
+
# instance:
|
116
|
+
#
|
117
|
+
# ```
|
118
|
+
# MySubscriber.new.subscribe_to(bus)
|
119
|
+
# ```
|
120
|
+
#
|
121
|
+
# Notice that a subscriber instance can only be subscribed once to the same
|
122
|
+
# bus. However, you can subscribe distinct instances to the same bus or the
|
123
|
+
# same instance to different buses.
|
124
|
+
module Subscriber
|
125
|
+
extend Dry::Configurable
|
126
|
+
|
127
|
+
# @api private
|
128
|
+
ON_PREFIX_STRATEGY = ->(event_name) { :"on_#{event_name}" }
|
129
|
+
|
130
|
+
setting :autodiscover, default: false
|
131
|
+
|
132
|
+
setting :autodiscover_strategy, default: ON_PREFIX_STRATEGY
|
133
|
+
|
134
|
+
# Includes with options
|
135
|
+
#
|
136
|
+
# ```
|
137
|
+
# include Omnes::Subscriber[autodiscover: true]
|
138
|
+
# ```
|
139
|
+
#
|
140
|
+
# Use regular `include Omnes::Subscriber` in case you want to use the
|
141
|
+
# defaults (which can be changed through configuration).
|
142
|
+
#
|
143
|
+
# @param autodiscover [Boolean]
|
144
|
+
# @param autodiscover_strategy [#call]
|
145
|
+
def self.[](autodiscover: config.autodiscover, autodiscover_strategy: config.autodiscover_strategy)
|
146
|
+
Module.new(autodiscover_strategy: autodiscover ? autodiscover_strategy : nil)
|
147
|
+
end
|
148
|
+
|
149
|
+
# @api private
|
150
|
+
def self.included(klass)
|
151
|
+
klass.include(self.[])
|
152
|
+
end
|
153
|
+
|
154
|
+
# @api private
|
155
|
+
class Module < ::Module
|
156
|
+
attr_reader :autodiscover_strategy
|
157
|
+
|
158
|
+
def initialize(autodiscover_strategy:)
|
159
|
+
@autodiscover_strategy = autodiscover_strategy
|
160
|
+
super()
|
161
|
+
end
|
162
|
+
|
163
|
+
def included(klass)
|
164
|
+
klass.instance_variable_set(:@_mutex, Mutex.new)
|
165
|
+
klass.instance_variable_set(:@_state, State.new(autodiscover_strategy: autodiscover_strategy))
|
166
|
+
klass.extend(ClassMethods)
|
167
|
+
klass.include(InstanceMethods)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Instance methods included in a {Omnes::Subscriber}
|
172
|
+
module InstanceMethods
|
173
|
+
# Subscribes event handlers to a bus
|
174
|
+
#
|
175
|
+
# @param bus [Omnes::Bus]
|
176
|
+
#
|
177
|
+
# @return [Omnes::Subscriber::Subscribers]
|
178
|
+
#
|
179
|
+
# @raise [Omnes::Subscriber::UnknownMethodSubscriptionAttemptError] when
|
180
|
+
# subscribing a method that doesn't exist
|
181
|
+
# @raise [Omnes::Subscriber::PrivateMethodSubscriptionAttemptError] when
|
182
|
+
# trying to subscribe a method that is private
|
183
|
+
# @raise [Omnes::Subscriber::DuplicateSubscriptionAttemptError] when
|
184
|
+
# trying to subscribe to the same event with the same method more than once
|
185
|
+
def subscribe_to(bus)
|
186
|
+
self.class.instance_variable_get(:@_state).public_send(:call, bus, self)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Included DSL methods for a {Omnes::Subscriber}
|
191
|
+
module ClassMethods
|
192
|
+
# Match a single event name
|
193
|
+
#
|
194
|
+
# @param event_name [Symbol]
|
195
|
+
# @param with [Symbol, #call] Public method in the class or an adapter
|
196
|
+
def handle(event_name, with:)
|
197
|
+
@_mutex.synchronize do
|
198
|
+
@_state.add_subscription_definition do |bus|
|
199
|
+
bus.registry.check_event_name(event_name)
|
200
|
+
[Subscription::SINGLE_EVENT_MATCHER.curry[event_name], Adapter.Type(with)]
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Handles all events
|
206
|
+
#
|
207
|
+
# @param with [Symbol, #call] Public method in the class or an adapter
|
208
|
+
def handle_all(with:)
|
209
|
+
@_mutex.synchronize do
|
210
|
+
@_state.add_subscription_definition do |_bus|
|
211
|
+
[Subscription::ALL_EVENTS_MATCHER, Adapter.Type(with)]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# Handles events with a custom matcher
|
217
|
+
#
|
218
|
+
# @param matcher [#call]
|
219
|
+
# @param with [Symbol, #call] Public method in the class or an adapter
|
220
|
+
def handle_with_matcher(matcher, with:)
|
221
|
+
@_mutex.synchronize do
|
222
|
+
@_state.add_subscription_definition do |_bus|
|
223
|
+
[matcher, Adapter.Type(with)]
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "benchmark"
|
4
|
+
require "omnes/execution"
|
5
|
+
|
6
|
+
module Omnes
|
7
|
+
# Subscription to an event
|
8
|
+
#
|
9
|
+
# An instance of it is returned on {Omnes::Bus} subscription methods.
|
10
|
+
#
|
11
|
+
# Usually, it isn't used directly beyond as a reference to unsubscribe.
|
12
|
+
#
|
13
|
+
# ```
|
14
|
+
# bus = Omnes::Bus.new
|
15
|
+
# bus.register(:foo)
|
16
|
+
# subscription = bus.subscribe(:foo) { |_event| do_something }
|
17
|
+
# bus.unsubscribe(subscription)
|
18
|
+
# ```
|
19
|
+
class Subscription
|
20
|
+
SINGLE_EVENT_MATCHER = lambda do |subscribed, candidate|
|
21
|
+
subscribed == candidate.omnes_event_name
|
22
|
+
end
|
23
|
+
|
24
|
+
ALL_EVENTS_MATCHER = ->(_candidate) { true }
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
attr_reader :matcher, :callback
|
28
|
+
|
29
|
+
# @api private
|
30
|
+
def initialize(matcher:, callback:)
|
31
|
+
@matcher = matcher
|
32
|
+
@callback = callback
|
33
|
+
end
|
34
|
+
|
35
|
+
# @api private
|
36
|
+
def call(event)
|
37
|
+
result = nil
|
38
|
+
benchmark = Benchmark.measure do
|
39
|
+
result = @callback.(event)
|
40
|
+
end
|
41
|
+
|
42
|
+
Execution.new(subscription: self, result: result, benchmark: benchmark)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @api private
|
46
|
+
def matches?(candidate)
|
47
|
+
matcher.(candidate)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns self within a single-item array
|
51
|
+
#
|
52
|
+
# This method can be helpful to act polymorphic to an array of subscriptions
|
53
|
+
# from an {Omnes::Subscriber}, usually for testing purposes.
|
54
|
+
def subscriptions
|
55
|
+
[self]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Omnes
|
4
|
+
# Event with a payload defined at publication time
|
5
|
+
#
|
6
|
+
# An instance of it is automatically created on {Omnes::Bus#publish} when a
|
7
|
+
# name and payload are given.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# bus = Omnes::Bus.new
|
11
|
+
# bus.register(:foo)
|
12
|
+
# bus.subscribe(:foo) do |event|
|
13
|
+
# puts event[:bar]
|
14
|
+
# end
|
15
|
+
# bus.publish(:foo, bar: 'bar') # it'll generate an instance of this class
|
16
|
+
class UnstructuredEvent
|
17
|
+
# Name of the event
|
18
|
+
#
|
19
|
+
# @return [Symbol]
|
20
|
+
attr_reader :omnes_event_name
|
21
|
+
|
22
|
+
# Information made available to the matching subscriptions
|
23
|
+
#
|
24
|
+
# @return [Hash]
|
25
|
+
attr_reader :payload
|
26
|
+
|
27
|
+
# @api private
|
28
|
+
def initialize(payload:, omnes_event_name:)
|
29
|
+
@payload = payload
|
30
|
+
@omnes_event_name = omnes_event_name
|
31
|
+
end
|
32
|
+
|
33
|
+
# Delegates to {#payload}
|
34
|
+
#
|
35
|
+
# @param key [Any]
|
36
|
+
#
|
37
|
+
# @return Any
|
38
|
+
def [](key)
|
39
|
+
payload[key]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|