emittance 1.1.0 → 2.0.0.pre.1
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 +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +4 -1
- data/.yardopts +2 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +20 -2
- data/docs/RoutingStrategies.md +39 -0
- data/emittance.gemspec +2 -2
- data/lib/emittance/brokerage.rb +87 -13
- data/lib/emittance/dispatcher/registration_map.rb +5 -1
- data/lib/emittance/dispatcher/topic_registration_map.rb +281 -0
- data/lib/emittance/dispatcher.rb +63 -6
- data/lib/emittance/dispatchers/synchronous.rb +1 -0
- data/lib/emittance/emitter.rb +2 -5
- data/lib/emittance/event.rb +49 -5
- data/lib/emittance/event_lookup.rb +4 -4
- data/lib/emittance/middleware/logging.rb +34 -0
- data/lib/emittance/middleware.rb +48 -0
- data/lib/emittance/topic_lookup.rb +25 -0
- data/lib/emittance/version.rb +1 -1
- data/lib/emittance/watcher.rb +7 -6
- data/lib/emittance.rb +40 -5
- metadata +25 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9ef6d6a01910b713c52f871249fffbddcd3534818b7b92640de2de23b9b1d838
|
4
|
+
data.tar.gz: 55a9f2bd1d5734a4171d42db6098bb0dba27a26cae0071a43712dff4d34011b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8475538f43bdfe7d0a524270a7f69c31ecd7f90a19e7146899a0f286606d8bf68f087c6ac40d321b02c5fc38b279217fb648b4352c693168814c0715f420ed8
|
7
|
+
data.tar.gz: f3b5f39f6ba0a5f311378e21d6e09158048c57c8f0b4c22f11a16c15146a82e85c17acac4f4c181acd4c78d6dc18a9215d1081933e1855a5f45478c0f17185e3
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.5.3
|
data/.travis.yml
CHANGED
@@ -3,7 +3,10 @@ env:
|
|
3
3
|
- secure: "uBY5L4Qs7b9dEVG2XAJ2x9O+PgJTIA9Ezkiu7KrfxjNhMViSUOGmkKvVxBWKwFzChfsFT2wQK/TYcNNtpZoFCLxqyBTCFV1DLHiPQ3mAW4yHPiRbwkEX5HSjypn+4ONd+nk26hMgfrnnAoHM5m4tkAQRo1dY8ARv46iH2wctErVYzj5ACf/OUmrIoF/+QXkE98oOWLMYhtyAhmlBusdcM+czreMD2BUzFilkhVLLY41KA1f7EE0W4v8aY87SOsBR6Q6bFKXm9bW3xxR6nKHukFXgXtfkkylcGOZur8VrvTxx/NAKTOyx/mCo4h1SqwZrIJQoPh3uBwv6n41YGkIzFQoebPiUnnsVYCnlz0V2AnnCdcZ/LrpIVra+bN7bh3oMtEKmlrU8cHeRQy0HlaD9u4o1KYwlg0X8lApGpsSsc+GKAC9MzGk4P3aOWFFSxqs/oo98bhlxuCvYjEh+x/aXeOqG6a/3Vlg6p/gJPxqDlaHmF6JfYGWrCysnJQtbBAstH/HhT2XHm/96uH3OURI7o+tx/I63/Qz/YG68O0nV9leFUrcmARK8XMavn1N5BM0Uoh/XhC0JUnu3GJJ7g7kABPkck81U1qWskDMeUm8hhfJgWVSixnAxKBehX+rKrizbcj3/UyqYKy7SnNHJ6fQo34rBxDLe0O8ULbWifj5/Xg4="
|
4
4
|
language: ruby
|
5
5
|
rvm:
|
6
|
-
- 2.
|
6
|
+
- 2.2.10
|
7
|
+
- 2.4.5
|
8
|
+
- 2.5.4
|
9
|
+
- 2.6.2
|
7
10
|
before_script:
|
8
11
|
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
9
12
|
- chmod +x ./cc-test-reporter
|
data/.yardopts
CHANGED
data/CHANGELOG.md
ADDED
data/Gemfile.lock
CHANGED
@@ -6,20 +6,27 @@ PATH
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
+
ast (2.4.0)
|
9
10
|
coderay (1.1.2)
|
10
11
|
diff-lcs (1.3)
|
11
12
|
docile (1.1.5)
|
13
|
+
jaro_winkler (1.5.2)
|
12
14
|
json (2.1.0)
|
13
15
|
method_source (0.9.0)
|
16
|
+
parallel (1.14.0)
|
17
|
+
parser (2.6.0.0)
|
18
|
+
ast (~> 2.4.0)
|
19
|
+
powerpack (0.1.2)
|
14
20
|
pry (0.11.3)
|
15
21
|
coderay (~> 1.1.0)
|
16
22
|
method_source (~> 0.9.0)
|
23
|
+
rainbow (3.0.0)
|
17
24
|
rake (10.5.0)
|
18
25
|
rspec (3.7.0)
|
19
26
|
rspec-core (~> 3.7.0)
|
20
27
|
rspec-expectations (~> 3.7.0)
|
21
28
|
rspec-mocks (~> 3.7.0)
|
22
|
-
rspec-core (3.7.
|
29
|
+
rspec-core (3.7.1)
|
23
30
|
rspec-support (~> 3.7.0)
|
24
31
|
rspec-expectations (3.7.0)
|
25
32
|
diff-lcs (>= 1.2.0, < 2.0)
|
@@ -28,11 +35,21 @@ GEM
|
|
28
35
|
diff-lcs (>= 1.2.0, < 2.0)
|
29
36
|
rspec-support (~> 3.7.0)
|
30
37
|
rspec-support (3.7.0)
|
38
|
+
rubocop (0.62.0)
|
39
|
+
jaro_winkler (~> 1.5.1)
|
40
|
+
parallel (~> 1.10)
|
41
|
+
parser (>= 2.5, != 2.5.1.1)
|
42
|
+
powerpack (~> 0.1)
|
43
|
+
rainbow (>= 2.2.2, < 4.0)
|
44
|
+
ruby-progressbar (~> 1.7)
|
45
|
+
unicode-display_width (~> 1.4.0)
|
46
|
+
ruby-progressbar (1.10.0)
|
31
47
|
simplecov (0.15.1)
|
32
48
|
docile (~> 1.1.0)
|
33
49
|
json (>= 1.8, < 3)
|
34
50
|
simplecov-html (~> 0.10.0)
|
35
51
|
simplecov-html (0.10.2)
|
52
|
+
unicode-display_width (1.4.1)
|
36
53
|
yard (0.9.12)
|
37
54
|
|
38
55
|
PLATFORMS
|
@@ -44,8 +61,9 @@ DEPENDENCIES
|
|
44
61
|
pry
|
45
62
|
rake (~> 10.0)
|
46
63
|
rspec (~> 3.0)
|
64
|
+
rubocop
|
47
65
|
simplecov
|
48
66
|
yard
|
49
67
|
|
50
68
|
BUNDLED WITH
|
51
|
-
1.
|
69
|
+
1.17.2
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# @title Routing Strategies
|
2
|
+
|
3
|
+
# Routing Strategies
|
4
|
+
|
5
|
+
Emittance can be configured to use one of several "routing strategies." A routing strategy is a way in which an event is identified so that watchers can decide which events they wish to subscribe to. All routing strategies encapsulate the same following basic ideas:
|
6
|
+
|
7
|
+
1. Events have one or more "identifiers." These identifiers are meant to express the "type" of event that was emitted, such as `order_completed`, or `user_logged_in`.
|
8
|
+
2. Watchers can choose the identifier(s) they wish to subscribe to. Some routing strategies can even allow a watcher to watch for multiple kinds of events with a single identifier. For instance, if we are using the `:topical` routing strategy, we can watch for the identifier `posts.*`, and be able to receive events with the identifier `posts.create` and `posts.destroy`.
|
9
|
+
|
10
|
+
## Routing Strategy Architecture
|
11
|
+
|
12
|
+
All routing strategies encompass two procedures: the creation of an event, and the registration/retrieval of watcher subscriptions. If you wish to create your own routing strategy, then you must implement both.
|
13
|
+
|
14
|
+
### Event Lookup & Creation
|
15
|
+
|
16
|
+
Event lookup is a residual feature of the "classical" routing strategy, which created a separate class for a given event identifier. This might eventually be removed in later versions, but for now a routing strategy must provide an object or class that implements three methods: `.identifiers_for_klass`, `.find_event_klass`, and `.register_identifier`.
|
17
|
+
|
18
|
+
`.identifiers_for_klass` takes an event class and (optionally) an event object, returning a list of identifiers for that given class. In the future this workflow will be simplified, but for now it is how an event's identifier is determined.
|
19
|
+
|
20
|
+
`.find_event_klass` takes an identifier or set of identifiers, returning the relevant event class for those identifiers. With future lookup strategies, this will be unnecessary being that all events will have the same class.
|
21
|
+
|
22
|
+
`.register_identifier` adds an identifier to a given event class. This is essentially a no-op with future lookup strategies, but the idea is that a given event type can have multiple identifiers.
|
23
|
+
|
24
|
+
### Subscription Registration & Identifier Routing
|
25
|
+
|
26
|
+
The primary purpose of a routing strategy is to facilitate the registration and retrieval of subscriptions given a specific event identifier. A routing strategy provides a class the instances of which serve to store subscriptions and route queries. Such a class must implement four instance methods: `#register`, `#[]`, `#clear_registrations_for`, and `#clear`.
|
27
|
+
|
28
|
+
`#register` takes an identifier and a subscription object (subscriptions can be anything) and stores the pair for later retrieval.
|
29
|
+
|
30
|
+
`#[]` takes an identifier and returns an enumerable collection of subscriptions relevant to that particular identifier. The rules for which subscriptions are returned are up to the author. This method should also return an object which can also be used to add a subscription to the parent registry using the `#<<` method.
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
subscriptions = my_regisration_map['some_identifier']
|
34
|
+
subscriptions << another_subscription
|
35
|
+
```
|
36
|
+
|
37
|
+
`#clear_registrations_for` takes an identifier and clears all subscriptions relevant to that identifier.
|
38
|
+
|
39
|
+
`#clear` clears all subscriptions.
|
data/emittance.gemspec
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# coding: utf-8
|
3
2
|
|
4
|
-
lib = File.expand_path('
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
5
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
5
|
require 'emittance/version'
|
7
6
|
|
@@ -27,6 +26,7 @@ Gem::Specification.new do |spec|
|
|
27
26
|
spec.add_development_dependency 'pry'
|
28
27
|
spec.add_development_dependency 'rake', '~> 10.0'
|
29
28
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
29
|
+
spec.add_development_dependency 'rubocop'
|
30
30
|
spec.add_development_dependency 'simplecov'
|
31
31
|
spec.add_development_dependency 'yard'
|
32
32
|
end
|
data/lib/emittance/brokerage.rb
CHANGED
@@ -5,31 +5,105 @@ module Emittance
|
|
5
5
|
# The clearinghouse for brokers. Registers brokers, and decides which broker to use when sent an event. First point of
|
6
6
|
# contact for event propagation.
|
7
7
|
#
|
8
|
-
|
8
|
+
# == Multiple brokers
|
9
|
+
#
|
10
|
+
# Emittance can support multiple brokers. This is implemented in a whitelist fashion. To enable a broker, just call
|
11
|
+
# {Emittance::Brokerage.use_broker}:
|
12
|
+
#
|
13
|
+
# Emittance.use_broker :asynchronous
|
14
|
+
#
|
15
|
+
# Watchers subscribe to events on a per-broker basis. By default, a watcher will subscribe on the default broker
|
16
|
+
# Emittance initializes with +synchronous+ as the default broker). You can override that default by specifying it in
|
17
|
+
# a parameter on the {Emittance::Watcher.watch} method:
|
18
|
+
#
|
19
|
+
# MyWatcher.watch :something_cool_happened, broker: :asynchronous { |event| puts event.payload.inspect }
|
20
|
+
#
|
21
|
+
# To change the default broker, use {Emittance::Brokerage.default_broker=}:
|
22
|
+
#
|
23
|
+
# Emittance.default_broker = :asynchronous
|
24
|
+
#
|
25
|
+
module Brokerage
|
26
|
+
class BrokerNotInUseError < StandardError; end
|
27
|
+
|
9
28
|
@enabled = true
|
10
|
-
@current_broker = nil
|
11
29
|
|
12
30
|
class << self
|
31
|
+
attr_reader :default_broker
|
32
|
+
|
33
|
+
# Sends an event to all brokers that are in-use.
|
34
|
+
#
|
13
35
|
# @param event [Emittance::Event] the event object
|
14
|
-
def send_event(event)
|
15
|
-
|
36
|
+
def send_event(event, middleware: Emittance::Middleware)
|
37
|
+
return nil unless enabled?
|
38
|
+
|
39
|
+
event = middleware.up(event)
|
40
|
+
brokers_in_use.each { |broker| broker.process_event(event) }
|
16
41
|
end
|
17
42
|
|
18
|
-
# @return [
|
19
|
-
def
|
20
|
-
@
|
43
|
+
# @return [Set<Emittance::Broker>]
|
44
|
+
def brokers_in_use
|
45
|
+
@brokers_in_use ||= Set.new
|
21
46
|
end
|
22
47
|
|
23
|
-
#
|
24
|
-
|
25
|
-
|
48
|
+
# Normalizes broker input in order to provide an interface that allows either a {Emittance::Broker} subclass _or_
|
49
|
+
# its identifier to be passed in to a method.
|
50
|
+
#
|
51
|
+
# @param broker [Class, Symbol, nil] either a broker or its identifier
|
52
|
+
def find_broker(broker)
|
53
|
+
if brokers_in_use.include?(broker) || (broker.is_a?(Class) && broker <= Emittance::Broker)
|
54
|
+
broker
|
55
|
+
elsif broker.nil?
|
56
|
+
default_broker
|
57
|
+
else
|
58
|
+
registry.fetch(broker)
|
59
|
+
end
|
26
60
|
end
|
27
61
|
|
28
|
-
#
|
29
|
-
|
30
|
-
|
62
|
+
# Checks if a broker is in use in this brokerage.
|
63
|
+
#
|
64
|
+
# @return [Boolean] true if broker is in use, false otherwise
|
65
|
+
def broker_in_use?(broker)
|
66
|
+
broker = find_broker(broker)
|
67
|
+
|
68
|
+
brokers_in_use.include?(broker)
|
31
69
|
end
|
32
70
|
|
71
|
+
# Adds a broker to the list of {Emittance::Broker} subclasses available. The first broker to be added becomes the
|
72
|
+
# default broker.
|
73
|
+
#
|
74
|
+
# @param broker [Class, Symbol] the symbol you have registered the broker to
|
75
|
+
def use_broker(broker)
|
76
|
+
broker = find_broker(broker)
|
77
|
+
|
78
|
+
brokers_in_use << broker
|
79
|
+
self.default_broker = broker unless default_broker
|
80
|
+
end
|
81
|
+
|
82
|
+
# Sets the default broker. If the watcher does not specify the broker, this will be the broker that gets
|
83
|
+
def default_broker=(broker)
|
84
|
+
broker = find_broker(broker)
|
85
|
+
raise BrokerNotInUseError, 'Default broker must be in use' unless broker_in_use?(broker)
|
86
|
+
|
87
|
+
@default_broker = broker
|
88
|
+
end
|
89
|
+
|
90
|
+
# A semi-private API. If you have created your own broker, this method adds it to the available pool of brokers.
|
91
|
+
#
|
92
|
+
# Emittance::Brokerage.register_broker MyBroker, :mine
|
93
|
+
#
|
94
|
+
# @param broker [Class] the broker you would like to register
|
95
|
+
# @param identifier [Symbol] the symbol you would like use to point to your registered broker
|
96
|
+
def register_broker(broker, identifier)
|
97
|
+
registry.register broker, identifier
|
98
|
+
end
|
99
|
+
|
100
|
+
def dispatcher_for(broker = nil)
|
101
|
+
broker = find_broker(broker)
|
102
|
+
broker.dispatcher
|
103
|
+
end
|
104
|
+
|
105
|
+
alias dispatcher dispatcher_for
|
106
|
+
|
33
107
|
# @return [Module] the registry containing all broker registrations
|
34
108
|
def registry
|
35
109
|
Emittance::Brokerage::Registry
|
@@ -8,7 +8,7 @@ module Emittance
|
|
8
8
|
# A proxy for a hash. Identifies special identifiers.
|
9
9
|
#
|
10
10
|
class RegistrationMap
|
11
|
-
SPECIAL_IDENTIFIER_REGEX =
|
11
|
+
SPECIAL_IDENTIFIER_REGEX = /^\@/.freeze
|
12
12
|
|
13
13
|
class << self
|
14
14
|
# @param identifier the identifier we want to know information about
|
@@ -38,6 +38,10 @@ module Emittance
|
|
38
38
|
self
|
39
39
|
end
|
40
40
|
|
41
|
+
def clear
|
42
|
+
@reg_map = {}
|
43
|
+
end
|
44
|
+
|
41
45
|
private
|
42
46
|
|
43
47
|
attr_reader :reg_map
|
@@ -0,0 +1,281 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module Emittance
|
6
|
+
class Dispatcher
|
7
|
+
##
|
8
|
+
# Tracks registrations for a set of topics.
|
9
|
+
#
|
10
|
+
# == Structure & Registration
|
11
|
+
#
|
12
|
+
# A +TopicRegistrationMap+ is structured like a hash, where the keys are topic parts, and the values are something
|
13
|
+
# called a +Mapping+. A +Mapping+ is a struct containing a set of subscriptions for its immediate topic level, as
|
14
|
+
# well as another +TopicRegistrationMap+. This forms a tree-like structure. For example, if we have a set of
|
15
|
+
# subscriptions on the following topics (their index is denoted above each element for clarity:
|
16
|
+
#
|
17
|
+
# # 0 1 2 3 4 5 6 7 8 9 10 11 12
|
18
|
+
# routing_key = ['*', '*', '*', '*', '*.b', '*.b', 'a', 'a.*', 'a.*', 'a.*', 'a.*.c', 'a.*.c', 'a.a']
|
19
|
+
#
|
20
|
+
# We could register them each using the {#register} method:
|
21
|
+
#
|
22
|
+
# registrations = TopicRegistrationMap.new
|
23
|
+
#
|
24
|
+
# routing_key.each_with_index do |routing_key, idx|
|
25
|
+
# registrations.register(routing_key, idx)
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# The resulting map would look like this:
|
29
|
+
#
|
30
|
+
# root map:
|
31
|
+
# *:
|
32
|
+
# subscriptions: [0, 1, 2, 3]
|
33
|
+
# map:
|
34
|
+
# b:
|
35
|
+
# subscriptions: [4, 5]
|
36
|
+
# a:
|
37
|
+
# subscriptions: [6]
|
38
|
+
# map:
|
39
|
+
# *:
|
40
|
+
# subscriptions: [7, 8, 9]
|
41
|
+
# map:
|
42
|
+
# c:
|
43
|
+
# subscriptions: [10, 11]
|
44
|
+
# a:
|
45
|
+
# subscriptions: [12]
|
46
|
+
#
|
47
|
+
# == Lookup
|
48
|
+
#
|
49
|
+
# Suppose we publish to the topic +a.a+. We can use the {#[]} method to fetch all the subscriptions relevant to
|
50
|
+
# that topic:
|
51
|
+
#
|
52
|
+
# registrations['a.a'] # => [7, 8, 9, 12]
|
53
|
+
#
|
54
|
+
class TopicRegistrationMap
|
55
|
+
Subscription = Struct.new(:routing_key, :registration)
|
56
|
+
|
57
|
+
# @param root [TopicRegistrationMap] (private API)
|
58
|
+
def initialize(root = nil)
|
59
|
+
@root = root
|
60
|
+
end
|
61
|
+
|
62
|
+
# @private
|
63
|
+
def root
|
64
|
+
@root || self
|
65
|
+
end
|
66
|
+
|
67
|
+
# @private
|
68
|
+
def mappings
|
69
|
+
@mappings ||= new_mappings
|
70
|
+
end
|
71
|
+
|
72
|
+
# Looks up subscriptions whose registrations match the given topic.
|
73
|
+
#
|
74
|
+
# @param topic_or_event [#to_s, Emittance::Event] the topic or event for which you wish to look up subscriptions
|
75
|
+
# @return [Enumerable] the set of subscriptions
|
76
|
+
def [](topic_or_event)
|
77
|
+
topic, head, tail, parts = process_routing_key(topic_or_event)
|
78
|
+
|
79
|
+
items = parts.length == 1 ? my_subscriptions(head, original_lookup: topic) : child_subscriptions(head, tail)
|
80
|
+
|
81
|
+
Result.new(root, topic, items)
|
82
|
+
end
|
83
|
+
|
84
|
+
# @private
|
85
|
+
def subscriptions_for_exactly(topic_part, original_lookup:)
|
86
|
+
Result.new(root, original_lookup, mappings[topic_part].subscriptions)
|
87
|
+
end
|
88
|
+
|
89
|
+
# @private
|
90
|
+
def all_child_subscriptions_for_exactly(topic_part, original_lookup:)
|
91
|
+
mappings.values.reduce(Result.new(root, original_lookup, Set.new)) do |result, mapping|
|
92
|
+
result + mapping.map.subscriptions_for_exactly(topic_part, original_lookup: original_lookup)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Registers a subscription to the given routing key.
|
97
|
+
#
|
98
|
+
# @param routing_key [#to_s] the routing key that you wish to subscribe to
|
99
|
+
# @param registration [Object] the registration you wish to store under that routing key
|
100
|
+
# @param original_routing_key [#to_s] (private API)
|
101
|
+
def register(routing_key, registration, original_routing_key: nil)
|
102
|
+
routing_key, head, tail, parts = process_routing_key(routing_key)
|
103
|
+
original_routing_key ||= routing_key
|
104
|
+
|
105
|
+
mapping = mappings[head]
|
106
|
+
|
107
|
+
if parts.length == 1
|
108
|
+
mapping << Subscription.new(original_routing_key, registration)
|
109
|
+
else
|
110
|
+
mapping.map.register(tail, registration, original_routing_key: original_routing_key)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Clears registrations associated with a given routing key.
|
115
|
+
#
|
116
|
+
# @param routing_key [#to_s] the routing key the registrations for which you with to clear from this map
|
117
|
+
def clear_registrations_for(routing_key)
|
118
|
+
_routing_key, head, tail, parts = process_routing_key(routing_key)
|
119
|
+
|
120
|
+
mapping = mappings[head]
|
121
|
+
|
122
|
+
if parts.length == 1
|
123
|
+
mapping.subscriptions.clear
|
124
|
+
else
|
125
|
+
mapping.map.clear_registrations_for(tail)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def clear
|
130
|
+
@mappings = new_mappings
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
# rubocop:disable Metrics/AbcSize
|
136
|
+
def my_subscriptions(head, original_lookup:)
|
137
|
+
mappings['#'].subscriptions +
|
138
|
+
mappings['*'].subscriptions +
|
139
|
+
mappings[head].subscriptions +
|
140
|
+
mappings[head].map.subscriptions_for_exactly('#', original_lookup: original_lookup) +
|
141
|
+
mappings['*'].map.subscriptions_for_exactly('#', original_lookup: original_lookup) +
|
142
|
+
mappings['#'].map.subscriptions_for_exactly(head, original_lookup: original_lookup) +
|
143
|
+
mappings['#'].map.subscriptions_for_exactly('*', original_lookup: original_lookup)
|
144
|
+
end
|
145
|
+
|
146
|
+
def child_subscriptions(head, tail)
|
147
|
+
Result.new(root, tail, mappings['#'].subscriptions) +
|
148
|
+
child_subscriptions_for_hash_on_tail(tail) +
|
149
|
+
mappings['*'].map[tail] +
|
150
|
+
mappings[head].map[tail]
|
151
|
+
end
|
152
|
+
|
153
|
+
def child_subscriptions_for_hash_on_tail(routing_key)
|
154
|
+
original_routing_key = routing_key
|
155
|
+
result = Result.new(root, original_routing_key)
|
156
|
+
|
157
|
+
until parts_for_routing_key(routing_key).empty?
|
158
|
+
routing_key, _, tail, = process_routing_key(routing_key)
|
159
|
+
result += Result.new(root, original_routing_key, mappings['#'].map[routing_key].items)
|
160
|
+
|
161
|
+
routing_key = tail
|
162
|
+
end
|
163
|
+
|
164
|
+
result
|
165
|
+
end
|
166
|
+
# rubocop:enable Metrics/AbcSize
|
167
|
+
|
168
|
+
def process_routing_key(routing_key)
|
169
|
+
routing_key = normalize_routing_key(routing_key)
|
170
|
+
parts = parts_for_routing_key(routing_key)
|
171
|
+
tail = routing_key_for_parts(parts[1..-1])
|
172
|
+
|
173
|
+
[routing_key, parts.first, tail, parts]
|
174
|
+
end
|
175
|
+
|
176
|
+
def normalize_routing_key(routing_key)
|
177
|
+
if routing_key.is_a?(Emittance::Event)
|
178
|
+
routing_key.topic
|
179
|
+
elsif routing_key.to_s == '@all' # support for legacy special identifier
|
180
|
+
'#'
|
181
|
+
else
|
182
|
+
routing_key
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def parts_for_routing_key(routing_key)
|
187
|
+
routing_key.to_s.split('.')
|
188
|
+
end
|
189
|
+
|
190
|
+
def routing_key_for_parts(parts)
|
191
|
+
parts.join('.')
|
192
|
+
end
|
193
|
+
|
194
|
+
def new_mappings
|
195
|
+
Hash.new { |h, k| h[k] = Mapping.new(root) }
|
196
|
+
end
|
197
|
+
|
198
|
+
# @private
|
199
|
+
class Mapping
|
200
|
+
attr_reader :root_map
|
201
|
+
|
202
|
+
def initialize(root_map)
|
203
|
+
@root_map = root_map
|
204
|
+
end
|
205
|
+
|
206
|
+
def push(new_subscription)
|
207
|
+
subscriptions << new_subscription
|
208
|
+
end
|
209
|
+
|
210
|
+
alias << push
|
211
|
+
|
212
|
+
def subscriptions
|
213
|
+
@subscriptions ||= Set.new
|
214
|
+
end
|
215
|
+
|
216
|
+
def map
|
217
|
+
@map ||= TopicRegistrationMap.new(root_map)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# @private
|
222
|
+
class Result
|
223
|
+
include Enumerable
|
224
|
+
|
225
|
+
attr_reader :root_map, :lookup_key, :items
|
226
|
+
|
227
|
+
def initialize(root_map, lookup_key, items = Set.new)
|
228
|
+
@root_map = root_map
|
229
|
+
@lookup_key = lookup_key
|
230
|
+
@items = items
|
231
|
+
end
|
232
|
+
|
233
|
+
def each
|
234
|
+
return enum_for(:each) unless block_given?
|
235
|
+
|
236
|
+
items.each { |item| item.respond_to?(:registration) ? yield(item.registration) : yield(item) }
|
237
|
+
end
|
238
|
+
|
239
|
+
# Adds a subscription to the root mapping. This is set up all wonky in this manner with a (sort of) circular
|
240
|
+
# reference because the original API was set up this way. This allows us to add subscriptions to the
|
241
|
+
# collection itself.
|
242
|
+
def push(new_subscription)
|
243
|
+
root_map.register(lookup_key, new_subscription)
|
244
|
+
end
|
245
|
+
|
246
|
+
alias << push
|
247
|
+
|
248
|
+
def +(other)
|
249
|
+
unless root_map == other.root_map && lookup_key == other.lookup_key
|
250
|
+
raise ArgumentError, 'Cannot add two Results with different root_maps or lookup_keys'
|
251
|
+
end
|
252
|
+
|
253
|
+
self.class.new(root_map, lookup_key, items + other.items)
|
254
|
+
end
|
255
|
+
|
256
|
+
def empty?
|
257
|
+
items.empty?
|
258
|
+
end
|
259
|
+
|
260
|
+
def length
|
261
|
+
items.length
|
262
|
+
end
|
263
|
+
|
264
|
+
alias size length
|
265
|
+
alias count length
|
266
|
+
|
267
|
+
def first
|
268
|
+
items.first
|
269
|
+
end
|
270
|
+
|
271
|
+
def last
|
272
|
+
items.last
|
273
|
+
end
|
274
|
+
|
275
|
+
def clear
|
276
|
+
root_map.clear_registrations_for(lookup_key)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
data/lib/emittance/dispatcher.rb
CHANGED
@@ -3,10 +3,11 @@
|
|
3
3
|
require 'set'
|
4
4
|
|
5
5
|
require 'emittance/dispatcher/registration_map'
|
6
|
+
require 'emittance/dispatcher/topic_registration_map'
|
6
7
|
|
7
8
|
module Emittance
|
8
9
|
##
|
9
|
-
# Abstract class for dispatchers. Subclasses must implement the following methods:
|
10
|
+
# Abstract class for dispatchers. Subclasses must implement the following class methods:
|
10
11
|
#
|
11
12
|
# - +._process_event+
|
12
13
|
# - +._register+
|
@@ -17,11 +18,65 @@ module Emittance
|
|
17
18
|
# you want, but typically represent the callback you would like to run whenever an event of a certain type is
|
18
19
|
# emitted.
|
19
20
|
#
|
21
|
+
# == Example
|
22
|
+
#
|
23
|
+
# Suppose we have a simple dispatcher. We're not going to worry about method calls, so we're just going to focus on
|
24
|
+
# implementing +._register+ and +._process_event+.
|
25
|
+
#
|
26
|
+
# class SimpleDispatcher < Emittance::Dispatcher
|
27
|
+
# class << self
|
28
|
+
# private
|
29
|
+
#
|
30
|
+
# # +._register+ takes the original identifier/topic, an optional params hash, and a block. To register the
|
31
|
+
# # callback, push it on to the collection returned by the +.registrations_for+ method. You can format the
|
32
|
+
# # callback in any way you like.
|
33
|
+
# def _register(identifier, _params = {}, &callback)
|
34
|
+
# registrations_for(event) << format_callback(callback)
|
35
|
+
# callback
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# # +._process_event+ is simple -- we just need to fetch the registrations related to the event, and process
|
39
|
+
# # them. The registrations are returned in the exact same format as they were stored in +._register+. So, in
|
40
|
+
# # this case, we will get a set of +CallbackWrapper+ objects, each of which responds to +#call+.
|
41
|
+
# #
|
42
|
+
# # IMPORTANT: You also need to make sure that the +down+ middleware stack is called in the process.
|
43
|
+
# def _process_event(event)
|
44
|
+
# event = Emittance::Middleware.down(event)
|
45
|
+
# registrations_for(event).each { |registration| registration.call(event) }
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# def format_callback(callback)
|
49
|
+
# CallbackWrapper.new(callback)
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
20
54
|
class Dispatcher
|
55
|
+
ROUTING_STRATEGIES = {
|
56
|
+
classical: RegistrationMap,
|
57
|
+
topical: TopicRegistrationMap
|
58
|
+
}.freeze
|
59
|
+
|
60
|
+
@routing_strategy = RegistrationMap
|
61
|
+
|
21
62
|
class << self
|
22
|
-
|
23
|
-
|
24
|
-
|
63
|
+
def routing_strategy
|
64
|
+
@routing_strategy || ::Emittance::Dispatcher.instance_variable_get('@routing_strategy')
|
65
|
+
end
|
66
|
+
|
67
|
+
alias registration_router_klass routing_strategy
|
68
|
+
|
69
|
+
def routing_strategy=(new_strategy_name)
|
70
|
+
new_strategy =
|
71
|
+
if new_strategy_name.is_a?(Module)
|
72
|
+
new_strategy_name
|
73
|
+
else
|
74
|
+
ROUTING_STRATEGIES[new_strategy_name.to_sym]
|
75
|
+
end
|
76
|
+
|
77
|
+
raise ArgumentError, 'Could not find a routing strategy with that name' unless new_strategy
|
78
|
+
|
79
|
+
@routing_strategy = new_strategy
|
25
80
|
end
|
26
81
|
|
27
82
|
# Calls the subclass's +_process_event+ method.
|
@@ -47,7 +102,7 @@ module Emittance
|
|
47
102
|
|
48
103
|
# @return [RegistrationMap] the registrations
|
49
104
|
def clear_registrations!
|
50
|
-
registrations.
|
105
|
+
registrations.clear
|
51
106
|
registrations
|
52
107
|
end
|
53
108
|
|
@@ -59,7 +114,9 @@ module Emittance
|
|
59
114
|
|
60
115
|
private
|
61
116
|
|
62
|
-
|
117
|
+
def registrations
|
118
|
+
@registrations ||= registration_router_klass.new
|
119
|
+
end
|
63
120
|
|
64
121
|
def _process_event(_event)
|
65
122
|
raise NotImplementedError
|
data/lib/emittance/emitter.rb
CHANGED
@@ -58,14 +58,12 @@ module Emittance
|
|
58
58
|
# @param payload [*] any additional information that might be helpful for an event's handler to have. Can be
|
59
59
|
# standardized on a per-event basis by pre-defining the class associated with the identifier and validating
|
60
60
|
# the payload. See {Emittance::Event} for more details.
|
61
|
-
# @param broker [Symbol] the identifier for the broker you wish to handle the event. Requires additional gems
|
62
|
-
# if not using the default.
|
63
61
|
#
|
64
62
|
# @return the payload
|
65
63
|
def emit(identifier, payload: nil)
|
66
64
|
now = Time.now
|
67
65
|
event_klass = _event_klass_for identifier
|
68
|
-
event = event_klass.new(self, now, payload)
|
66
|
+
event = event_klass.new(self, now, payload).tap { |the_event| the_event.topic = identifier }
|
69
67
|
_send_to_broker event
|
70
68
|
|
71
69
|
payload
|
@@ -76,11 +74,10 @@ module Emittance
|
|
76
74
|
#
|
77
75
|
# @param identifiers [*] anything that can be used to generate an +Event+ class.
|
78
76
|
# @param payload (@see #emit)
|
79
|
-
# @param broker (@see #emit)
|
80
77
|
def emit_with_dynamic_identifier(*identifiers, payload:)
|
81
78
|
now = Time.now
|
82
79
|
event_klass = _event_klass_for(*identifiers)
|
83
|
-
event = event_klass.new(self, now, payload)
|
80
|
+
event = event_klass.new(self, now, payload).tap { |the_event| the_event.topic = identifiers.join('.') }
|
84
81
|
_send_to_broker event
|
85
82
|
|
86
83
|
payload
|
data/lib/emittance/event.rb
CHANGED
@@ -2,6 +2,21 @@
|
|
2
2
|
|
3
3
|
module Emittance
|
4
4
|
##
|
5
|
+
# = Topical Event Lookup
|
6
|
+
#
|
7
|
+
# This section describes the new ('topical') style of event lookup. This will be maintained in the future in favor
|
8
|
+
# of the old ('classical') style. However, it is not enabled by default. To enable this strategy, you must configure
|
9
|
+
# Emittance to use it:
|
10
|
+
#
|
11
|
+
# Emittance.event_routing_strategy = :topical
|
12
|
+
#
|
13
|
+
# This strategy mimicks the topic name format used by RabbitMQ.
|
14
|
+
#
|
15
|
+
# = Classical Event Lookup (Legacy)
|
16
|
+
#
|
17
|
+
# This section describes the old ('classical') style of event lookup. While it's unlikely to be removed, it will
|
18
|
+
# remain unsupported in favor of the new ('topical') style of event lookup, described above.
|
19
|
+
#
|
5
20
|
# Basic usage of Emittance doesn't require that you fiddle with objects of type +Emittance::Event+. However, this
|
6
21
|
# class is open for you to inherit from in the cases where you would like to customize some aspects of the event.
|
7
22
|
#
|
@@ -104,10 +119,37 @@ module Emittance
|
|
104
119
|
# We can manually add an identifier post-hoc, but this would nevertheless become confusing.
|
105
120
|
#
|
106
121
|
class Event
|
122
|
+
LOOKUP_STRATEGIES = {
|
123
|
+
classical: EventLookup,
|
124
|
+
topical: TopicLookup
|
125
|
+
}.freeze
|
126
|
+
|
127
|
+
@lookup_strategy = EventLookup
|
128
|
+
|
107
129
|
class << self
|
130
|
+
attr_reader :lookup_strategy
|
131
|
+
|
132
|
+
# @param new_strategy_name [#to_sym] the name of the new lookup strategy
|
133
|
+
def lookup_strategy=(new_strategy_name)
|
134
|
+
new_strategy =
|
135
|
+
if new_strategy_name.is_a?(Module)
|
136
|
+
new_strategy_name
|
137
|
+
else
|
138
|
+
LOOKUP_STRATEGIES[new_strategy_name.to_sym]
|
139
|
+
end
|
140
|
+
|
141
|
+
raise ArgumentError, 'Could not find a lookup strategy with that name' unless new_strategy
|
142
|
+
|
143
|
+
@lookup_strategy = new_strategy
|
144
|
+
end
|
145
|
+
|
146
|
+
def inherited(subklass)
|
147
|
+
subklass.instance_variable_set('@lookup_strategy', lookup_strategy)
|
148
|
+
end
|
149
|
+
|
108
150
|
# @return [Array<Symbol>] the identifier that can be used by the {Emittance::Broker broker} to find event handlers
|
109
|
-
def identifiers
|
110
|
-
|
151
|
+
def identifiers(event = nil)
|
152
|
+
lookup_strategy.identifiers_for_klass(self, event).to_a
|
111
153
|
end
|
112
154
|
|
113
155
|
# Gives the Event object a custom identifier.
|
@@ -115,17 +157,19 @@ module Emittance
|
|
115
157
|
# @param sym [Symbol] the identifier you wish to identify this event by when emitting and watching for it
|
116
158
|
def add_identifier(sym)
|
117
159
|
raise Emittance::InvalidIdentifierError, 'Identifiers must respond to #to_sym' unless sym.respond_to?(:to_sym)
|
118
|
-
|
160
|
+
|
161
|
+
lookup_strategy.register_identifier self, sym.to_sym
|
119
162
|
end
|
120
163
|
|
121
164
|
# @param identifiers [*] anything that can be derived into an identifier (or the event class itself) for the
|
122
165
|
# purposes of looking up an event class.
|
123
166
|
def event_klass_for(*identifiers)
|
124
|
-
|
167
|
+
lookup_strategy.find_event_klass(*identifiers)
|
125
168
|
end
|
126
169
|
end
|
127
170
|
|
128
171
|
attr_reader :emitter, :timestamp, :payload
|
172
|
+
attr_accessor :topic
|
129
173
|
|
130
174
|
# @param emitter the object that emitted the event
|
131
175
|
# @param timestamp [Time] the time at which the event occurred
|
@@ -138,7 +182,7 @@ module Emittance
|
|
138
182
|
|
139
183
|
# @return [Array<Symbol>] all identifiers that can be used to identify the event
|
140
184
|
def identifiers
|
141
|
-
self.class.identifiers
|
185
|
+
self.class.identifiers(self)
|
142
186
|
end
|
143
187
|
end
|
144
188
|
end
|
@@ -8,9 +8,9 @@ module Emittance
|
|
8
8
|
# event class.
|
9
9
|
#
|
10
10
|
module EventLookup
|
11
|
-
|
12
|
-
include Emittance::Helpers::StringHelpers
|
11
|
+
extend Emittance::Helpers::StringHelpers
|
13
12
|
|
13
|
+
class << self
|
14
14
|
# Look up an {Emittance::Event} class by an identifier. Generates an Event class if no such class exists for
|
15
15
|
# that identifier.
|
16
16
|
#
|
@@ -55,7 +55,7 @@ module Emittance
|
|
55
55
|
|
56
56
|
# @param klass [Class] a subclass of {Emittance::Event} you wish to find the identifiers for
|
57
57
|
# @return [Set<Symbol>] a collection of identifiers that can be used to identify that event class
|
58
|
-
def identifiers_for_klass(klass)
|
58
|
+
def identifiers_for_klass(klass, _event = nil)
|
59
59
|
Emittance::EventLookup::Registry.identifiers_for_klass(klass)
|
60
60
|
end
|
61
61
|
|
@@ -219,7 +219,7 @@ module Emittance
|
|
219
219
|
#
|
220
220
|
# @param event_klass [Class] the class you want the identifiers for
|
221
221
|
# @return [Set<Symbol>] all identifiers that can be used to identify the given event class
|
222
|
-
def identifiers_for_klass(event_klass)
|
222
|
+
def identifiers_for_klass(event_klass, _event = nil)
|
223
223
|
lookup_klass_to_identifier_mapping(event_klass) ||
|
224
224
|
(create_mapping_for_klass(event_klass) && lookup_klass_to_identifier_mapping(event_klass))
|
225
225
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module Emittance
|
6
|
+
class Middleware
|
7
|
+
##
|
8
|
+
# Middleware for logging events
|
9
|
+
#
|
10
|
+
class Logging < Emittance::Middleware
|
11
|
+
@current_logger = Logger.new(STDOUT)
|
12
|
+
|
13
|
+
class << self
|
14
|
+
attr_accessor :current_logger
|
15
|
+
end
|
16
|
+
|
17
|
+
def up
|
18
|
+
current_logger.info event_log_str
|
19
|
+
|
20
|
+
event
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def current_logger
|
26
|
+
self.class.current_logger
|
27
|
+
end
|
28
|
+
|
29
|
+
def event_log_str
|
30
|
+
"Emittance: #{event.identifiers.last.inspect} event emitted."
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Emittance
|
4
|
+
##
|
5
|
+
# Module for managing middlewares.
|
6
|
+
#
|
7
|
+
class Middleware
|
8
|
+
@registered_middlewares = []
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_reader :registered_middlewares
|
12
|
+
|
13
|
+
# @param middleware [Class, Array<#up, #down>] the middleware or array of middlewares you wish to register.
|
14
|
+
# @return [Array] the updated list of registered middlewares.
|
15
|
+
def register(middleware)
|
16
|
+
middlewares = Array(middleware)
|
17
|
+
|
18
|
+
middlewares.each { |mw| registered_middlewares << mw }
|
19
|
+
end
|
20
|
+
|
21
|
+
def clear_registrations!
|
22
|
+
registered_middlewares.clear
|
23
|
+
end
|
24
|
+
|
25
|
+
def up(input_event)
|
26
|
+
registered_middlewares.reduce(input_event) { |event, klass| klass.new(event).up }
|
27
|
+
end
|
28
|
+
|
29
|
+
def down(input_event)
|
30
|
+
registered_middlewares.reduce(input_event) { |event, klass| klass.new(event).down }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_reader :event
|
35
|
+
|
36
|
+
def initialize(event)
|
37
|
+
@event = event
|
38
|
+
end
|
39
|
+
|
40
|
+
def up
|
41
|
+
event
|
42
|
+
end
|
43
|
+
|
44
|
+
def down
|
45
|
+
event
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Emittance
|
4
|
+
##
|
5
|
+
# Since events don't need to be dynamically generated when using topics, we essentially want to stub out all of the
|
6
|
+
# class creation and registration logic.
|
7
|
+
#
|
8
|
+
module TopicLookup
|
9
|
+
class << self
|
10
|
+
def identifiers_for_klass(_klass, event = nil)
|
11
|
+
raise ArgumentError, 'Cannot generate identifiers without an event' unless event
|
12
|
+
|
13
|
+
[event.topic]
|
14
|
+
end
|
15
|
+
|
16
|
+
def register_identifier(klass, identifier)
|
17
|
+
# no op
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_event_klass(*_identifiers)
|
21
|
+
Emittance::Event
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/emittance/version.rb
CHANGED
data/lib/emittance/watcher.rb
CHANGED
@@ -11,21 +11,22 @@ module Emittance
|
|
11
11
|
# @param identifier [Symbol] the event's identifier
|
12
12
|
# @param callback_method [Symbol] one option for adding a callback--the method on the object to call when the
|
13
13
|
# event fires
|
14
|
+
# @param params [Hash] any parameters related to the registration of a watcher
|
14
15
|
# @param callback [Block] the other option for adding a callback--the block you wish to be executed when the event
|
15
16
|
# fires
|
16
17
|
# @return [Proc] the block that will run when the event fires
|
17
|
-
def watch(identifier, callback_method = nil, params
|
18
|
-
if
|
19
|
-
_dispatcher.
|
18
|
+
def watch(identifier, callback_method = nil, **params, &callback)
|
19
|
+
if callback
|
20
|
+
_dispatcher(params).register identifier, params, &callback
|
20
21
|
else
|
21
|
-
_dispatcher.
|
22
|
+
_dispatcher(params).register_method_call identifier, self, callback_method, params
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
25
26
|
private
|
26
27
|
|
27
|
-
def _dispatcher
|
28
|
-
Emittance.
|
28
|
+
def _dispatcher(params)
|
29
|
+
Emittance.dispatcher_for(params[:broker])
|
29
30
|
end
|
30
31
|
end
|
31
32
|
end
|
data/lib/emittance.rb
CHANGED
@@ -6,12 +6,14 @@ require 'emittance/errors'
|
|
6
6
|
require 'emittance/helpers/string_helpers'
|
7
7
|
require 'emittance/helpers/constant_helpers'
|
8
8
|
require 'emittance/event_lookup'
|
9
|
+
require 'emittance/topic_lookup'
|
9
10
|
require 'emittance/dispatcher'
|
10
11
|
require 'emittance/brokerage'
|
11
12
|
require 'emittance/broker'
|
12
13
|
require 'emittance/event'
|
13
14
|
require 'emittance/emitter'
|
14
15
|
require 'emittance/watcher'
|
16
|
+
require 'emittance/middleware'
|
15
17
|
require 'emittance/notifier'
|
16
18
|
require 'emittance/action'
|
17
19
|
|
@@ -20,6 +22,8 @@ require 'emittance/action'
|
|
20
22
|
#
|
21
23
|
module Emittance
|
22
24
|
class << self
|
25
|
+
attr_reader :event_routing_strategy
|
26
|
+
|
23
27
|
# Enable eventing process-wide
|
24
28
|
def enable!
|
25
29
|
Emittance::Brokerage.enable!
|
@@ -36,20 +40,45 @@ module Emittance
|
|
36
40
|
end
|
37
41
|
|
38
42
|
# @return [Class] the currently enabled broker class
|
39
|
-
def
|
40
|
-
Emittance::Brokerage.
|
43
|
+
def default_broker
|
44
|
+
Emittance::Brokerage.default_broker
|
45
|
+
end
|
46
|
+
|
47
|
+
alias broker default_broker
|
48
|
+
|
49
|
+
def dispatcher_for(*args)
|
50
|
+
Emittance::Brokerage.dispatcher_for(*args)
|
41
51
|
end
|
42
52
|
|
53
|
+
alias dispatcher dispatcher_for
|
54
|
+
|
43
55
|
# @return [Class] the dispatcher attached to the currently enabled broker
|
44
|
-
def
|
45
|
-
|
56
|
+
def default_dispatcher
|
57
|
+
default_broker.dispatcher
|
46
58
|
end
|
47
59
|
|
48
|
-
# @param [
|
60
|
+
# @param identifier [#to_sym] the identifier that can be used to identify the broker you wish to use
|
49
61
|
def use_broker(identifier)
|
50
62
|
Emittance::Brokerage.use_broker identifier
|
51
63
|
end
|
52
64
|
|
65
|
+
def default_broker=(identifier)
|
66
|
+
Emittance::Brokerage.default_broker = identifier
|
67
|
+
end
|
68
|
+
|
69
|
+
# Emittance.use_middleware MyMiddleware
|
70
|
+
# Emittance.use_middleware MyOtherMiddleware, MyCoolMiddleware
|
71
|
+
#
|
72
|
+
# @param middlewares [Array<Class>] each middleware you wish to run.
|
73
|
+
def use_middleware(*middlewares)
|
74
|
+
Emittance::Middleware.register middlewares
|
75
|
+
end
|
76
|
+
|
77
|
+
# Removes all middlewares from the app.
|
78
|
+
def clear_middleware!
|
79
|
+
Emittance::Middleware.clear_registrations!
|
80
|
+
end
|
81
|
+
|
53
82
|
# Not yet implemented! Remove nocov and private flags when finished.
|
54
83
|
# :nocov:
|
55
84
|
# @private
|
@@ -58,6 +87,12 @@ module Emittance
|
|
58
87
|
# Emittance::Dispatcher.suppress(&blk)
|
59
88
|
end
|
60
89
|
# :nocov:
|
90
|
+
|
91
|
+
def event_routing_strategy=(new_strategy)
|
92
|
+
@event_routing_strategy = new_strategy
|
93
|
+
Emittance::Event.lookup_strategy = new_strategy
|
94
|
+
Emittance::Dispatcher.routing_strategy = new_strategy
|
95
|
+
end
|
61
96
|
end
|
62
97
|
end
|
63
98
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: emittance
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.pre.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tyler Guillen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: simplecov
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -106,6 +120,7 @@ files:
|
|
106
120
|
- ".ruby-version"
|
107
121
|
- ".travis.yml"
|
108
122
|
- ".yardopts"
|
123
|
+
- CHANGELOG.md
|
109
124
|
- CODE_OF_CONDUCT.md
|
110
125
|
- Gemfile
|
111
126
|
- Gemfile.lock
|
@@ -114,6 +129,7 @@ files:
|
|
114
129
|
- Rakefile
|
115
130
|
- bin/console
|
116
131
|
- bin/setup
|
132
|
+
- docs/RoutingStrategies.md
|
117
133
|
- emittance.gemspec
|
118
134
|
- lib/emittance.rb
|
119
135
|
- lib/emittance/action.rb
|
@@ -123,6 +139,7 @@ files:
|
|
123
139
|
- lib/emittance/dispatcher.rb
|
124
140
|
- lib/emittance/dispatcher/registration_collection_proxy.rb
|
125
141
|
- lib/emittance/dispatcher/registration_map.rb
|
142
|
+
- lib/emittance/dispatcher/topic_registration_map.rb
|
126
143
|
- lib/emittance/dispatchers/synchronous.rb
|
127
144
|
- lib/emittance/emitter.rb
|
128
145
|
- lib/emittance/errors.rb
|
@@ -130,7 +147,10 @@ files:
|
|
130
147
|
- lib/emittance/event_lookup.rb
|
131
148
|
- lib/emittance/helpers/constant_helpers.rb
|
132
149
|
- lib/emittance/helpers/string_helpers.rb
|
150
|
+
- lib/emittance/middleware.rb
|
151
|
+
- lib/emittance/middleware/logging.rb
|
133
152
|
- lib/emittance/notifier.rb
|
153
|
+
- lib/emittance/topic_lookup.rb
|
134
154
|
- lib/emittance/version.rb
|
135
155
|
- lib/emittance/watcher.rb
|
136
156
|
homepage: https://github.com/aastronautss/emittance
|
@@ -148,12 +168,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
148
168
|
version: '0'
|
149
169
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
170
|
requirements:
|
151
|
-
- - "
|
171
|
+
- - ">"
|
152
172
|
- !ruby/object:Gem::Version
|
153
|
-
version:
|
173
|
+
version: 1.3.1
|
154
174
|
requirements: []
|
155
175
|
rubyforge_project:
|
156
|
-
rubygems_version: 2.6
|
176
|
+
rubygems_version: 2.7.6
|
157
177
|
signing_key:
|
158
178
|
specification_version: 4
|
159
179
|
summary: A robust and flexible eventing library for Ruby.
|