octiron 0.2.0 → 0.3.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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +43 -0
- data/lib/octiron/events/bus.rb +37 -19
- data/lib/octiron/version.rb +1 -1
- data/lib/octiron/world.rb +5 -2
- data/spec/events_bus_spec.rb +27 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77fcd14d6034f8507cd48bcccad8e1c842895bd7
|
4
|
+
data.tar.gz: fd7c20ee199a1406e6973ef92519617c14cd628a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 292f9c0256bec186e77be6ca75bb864a6d5b5ea99f1179be7202c6fbe941f4fbe3c4d238f056ad2539f6ed4f12d70f04beb8fce24b9b8616b22b429333447265
|
7
|
+
data.tar.gz: ce519cfd7d727e6241a745417c74319b84fd47f403a6a92f7e732e954921d69d1fdd106d633c32650564c2c880ec4d36673d1956d3185c29e6698968eca86271
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -122,6 +122,49 @@ end
|
|
122
122
|
publish(SourceEvent.new) # will raise RuntimeError
|
123
123
|
```
|
124
124
|
|
125
|
+
### Handler Classes
|
126
|
+
|
127
|
+
*The term "Handler Class" should not be confused with Ruby classes implementing
|
128
|
+
handlers. Instead, a class is a grouping "type".*
|
129
|
+
|
130
|
+
There may be situations where you want your handlers to be executed in a
|
131
|
+
particular order. That is especially the case when one handler relies on a
|
132
|
+
different handler having been executed earlier. For those instances, you can
|
133
|
+
sort your handlers into classes as you subscribe them:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
on_event(MyEvent, nil, SOME_CLASS) do |event|
|
137
|
+
# ...
|
138
|
+
end
|
139
|
+
|
140
|
+
on_event(MyEvent, nil, ANOTHER_CLASS) do |event|
|
141
|
+
# ...
|
142
|
+
end
|
143
|
+
```
|
144
|
+
|
145
|
+
In the above example, the two handlers are subscribed with the `SOME_CLASS` and
|
146
|
+
`ANOTHER_CLASS` constants as handler classes respectively. These parameters must
|
147
|
+
be sortable values: if `ANOTHER_CLASS`'s value is sorted before `SOME_CLASS`,
|
148
|
+
then the second handler is executed before the first, e.g. in this instance:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
ANOTHER_CLASS = 0
|
152
|
+
SOME_CLASS = 1
|
153
|
+
```
|
154
|
+
|
155
|
+
Note that we're passing a `nil` object as the second parameter every time. This
|
156
|
+
is because we're subscribing a block handler. For an object handler, the code
|
157
|
+
would have to be the following:
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
on_event(MyEvent, second_handler, SOME_CLASS)
|
161
|
+
on_event(MyEvent, first_handler, ANOTHER_CLASS)
|
162
|
+
```
|
163
|
+
|
164
|
+
Since handlers don't create new events, but pass the event from one handler to
|
165
|
+
another, ordering handlers in classes allows you to modify an event before it
|
166
|
+
reaches another handler.
|
167
|
+
|
125
168
|
### Singletons vs. API
|
126
169
|
|
127
170
|
The octiron gem exposes a number of simple wrapper functions we've used so far
|
data/lib/octiron/events/bus.rb
CHANGED
@@ -21,6 +21,9 @@ module Octiron::Events
|
|
21
21
|
# @return (String) the default namespace to search for events
|
22
22
|
attr_reader :default_namespace
|
23
23
|
|
24
|
+
# The default handler class
|
25
|
+
DEFAULT_CLASS = 'octiron-default'.freeze
|
26
|
+
|
24
27
|
##
|
25
28
|
# @param default_namespace (Symbol) The default namespace to look in for
|
26
29
|
# Event classes.
|
@@ -42,14 +45,19 @@ module Octiron::Events
|
|
42
45
|
# @param handler_object (Object) Handler object that must implement a
|
43
46
|
# `#call` method accepting an instance of the event class provided in
|
44
47
|
# the first parameter. If nil, a block needs to be provided.
|
48
|
+
# @param handler_class (Object) An object describing the handler class; the
|
49
|
+
# default is DEFAULT_CLASS. Handlers are executed sorted by handler class,
|
50
|
+
# so the class provided here must be sortable.
|
45
51
|
# @param handler_proc (Proc) Handler block that accepts an instance of the
|
46
52
|
# event class provided in the first parameter. If nil, a handler object
|
47
53
|
# must be provided.
|
48
54
|
# @return The class represented by the event_id, as a String name.
|
49
|
-
def subscribe(event_id, handler_object = nil,
|
50
|
-
|
51
|
-
|
52
|
-
|
55
|
+
def subscribe(event_id, handler_object = nil, handler_class = DEFAULT_CLASS,
|
56
|
+
&handler_proc)
|
57
|
+
return with_handlers(event_id, handler_class, handler_object,
|
58
|
+
handler_proc) do |hlist, h|
|
59
|
+
hlist << h
|
60
|
+
end
|
53
61
|
end
|
54
62
|
alias register subscribe
|
55
63
|
|
@@ -60,14 +68,19 @@ module Octiron::Events
|
|
60
68
|
# @param handler_object (Object) Handler object that must implement a
|
61
69
|
# `#call` method accepting an instance of the event class provided in
|
62
70
|
# the first parameter. If nil, a block needs to be provided.
|
71
|
+
# @param handler_class (Object) An object describing the handler class; the
|
72
|
+
# default is DEFAULT_CLASS. Handlers are executed sorted by handler class,
|
73
|
+
# so the class provided here must be sortable.
|
63
74
|
# @param handler_proc (Proc) Handler block that accepts an instance of the
|
64
75
|
# event class provided in the first parameter. If nil, a handler object
|
65
76
|
# must be provided.
|
66
77
|
# @return The class represented by the event_id, as a String name.
|
67
|
-
def unsubscribe(event_id, handler_object = nil,
|
68
|
-
|
69
|
-
|
70
|
-
|
78
|
+
def unsubscribe(event_id, handler_object = nil, handler_class = DEFAULT_CLASS,
|
79
|
+
&handler_proc)
|
80
|
+
return with_handlers(event_id, handler_class, handler_object,
|
81
|
+
handler_proc) do |hlist, h|
|
82
|
+
hlist.delete(h)
|
83
|
+
end
|
71
84
|
end
|
72
85
|
|
73
86
|
##
|
@@ -79,8 +92,10 @@ module Octiron::Events
|
|
79
92
|
if not event.is_a?(Hash)
|
80
93
|
event_name = event.class.to_s
|
81
94
|
end
|
82
|
-
|
83
|
-
|
95
|
+
@handlers.keys.sort.each do |handler_class|
|
96
|
+
handlers_for(event_name, handler_class, false).each do |handler|
|
97
|
+
handler.call(event)
|
98
|
+
end
|
84
99
|
end
|
85
100
|
end
|
86
101
|
alias broadcast publish
|
@@ -91,7 +106,10 @@ module Octiron::Events
|
|
91
106
|
# The first parameters is the event class or event name. The second parameter
|
92
107
|
# is whether this is for write or read access. We don't want to pollute
|
93
108
|
# @handlers with data from the #publish call.
|
94
|
-
def handlers_for(name, write)
|
109
|
+
def handlers_for(name, handler_class, write)
|
110
|
+
# Defaults for the class
|
111
|
+
@handlers[handler_class] ||= {}
|
112
|
+
|
95
113
|
# Use prototype matching for Hash names
|
96
114
|
if name.is_a?(Hash)
|
97
115
|
name.extend(::Collapsium::PrototypeMatch)
|
@@ -106,7 +124,7 @@ module Octiron::Events
|
|
106
124
|
best_proto = nil
|
107
125
|
|
108
126
|
# Find the best matching prototype
|
109
|
-
@handlers.keys.each do |proto|
|
127
|
+
@handlers[handler_class].keys.each do |proto|
|
110
128
|
score = name.prototype_match_score(proto)
|
111
129
|
if score > best_score
|
112
130
|
best_score = score
|
@@ -115,14 +133,14 @@ module Octiron::Events
|
|
115
133
|
end
|
116
134
|
|
117
135
|
if not best_proto.nil?
|
118
|
-
return @handlers[best_proto]
|
136
|
+
return @handlers[handler_class][best_proto]
|
119
137
|
end
|
120
138
|
else
|
121
139
|
merged = []
|
122
140
|
|
123
|
-
@handlers.keys.each do |proto|
|
141
|
+
@handlers[handler_class].keys.each do |proto|
|
124
142
|
if name.prototype_match(proto)
|
125
|
-
merged += @handlers[proto]
|
143
|
+
merged += @handlers[handler_class][proto]
|
126
144
|
end
|
127
145
|
end
|
128
146
|
|
@@ -140,19 +158,19 @@ module Octiron::Events
|
|
140
158
|
# If we're in write access, make sure to store an empty list as well as
|
141
159
|
# returning one (if necessary).
|
142
160
|
if write
|
143
|
-
@handlers[name] ||= []
|
161
|
+
@handlers[handler_class][name] ||= []
|
144
162
|
end
|
145
163
|
|
146
164
|
# In read access, want to either return an empty list, or the registered
|
147
165
|
# handlers, but not ovewrite the registered handlers.
|
148
|
-
return @handlers[name] || []
|
166
|
+
return @handlers[handler_class][name] || []
|
149
167
|
end
|
150
168
|
|
151
|
-
def with_handlers(event_id, handler_object, handler_proc)
|
169
|
+
def with_handlers(event_id, handler_class, handler_object, handler_proc)
|
152
170
|
handler = resolve_handler(handler_object, &handler_proc)
|
153
171
|
event_name = identify(event_id)
|
154
172
|
|
155
|
-
yield handlers_for(event_name, true), handler
|
173
|
+
yield handlers_for(event_name, handler_class, true), handler
|
156
174
|
|
157
175
|
return event_name
|
158
176
|
end
|
data/lib/octiron/version.rb
CHANGED
data/lib/octiron/world.rb
CHANGED
@@ -120,8 +120,11 @@ module Octiron::World
|
|
120
120
|
|
121
121
|
##
|
122
122
|
# Subscribe an event handler to an event with the singleton event bus
|
123
|
-
def on_event(event_id, handler_object = nil,
|
124
|
-
|
123
|
+
def on_event(event_id, handler_object = nil,
|
124
|
+
handler_class = ::Octiron::Events::Bus::DEFAULT_CLASS,
|
125
|
+
&handler_proc)
|
126
|
+
::Octiron::World.event_bus.subscribe(event_id, handler_object,
|
127
|
+
handler_class, &handler_proc)
|
125
128
|
end
|
126
129
|
|
127
130
|
##
|
data/spec/events_bus_spec.rb
CHANGED
@@ -295,7 +295,7 @@ describe Octiron::Events::Bus do
|
|
295
295
|
expect(handler2.invoked).to eql 1
|
296
296
|
end
|
297
297
|
|
298
|
-
it "unsubscripes proc handlers
|
298
|
+
it "unsubscripes proc handlers properly" do
|
299
299
|
event = TestEvent.new
|
300
300
|
invoked1 = 0
|
301
301
|
invoked2 = 0
|
@@ -319,4 +319,30 @@ describe Octiron::Events::Bus do
|
|
319
319
|
expect(invoked2).to eql 1
|
320
320
|
end
|
321
321
|
end
|
322
|
+
|
323
|
+
context "event handler classes" do
|
324
|
+
before :each do
|
325
|
+
@bus = ::Octiron::Events::Bus.new(::Octiron::Events)
|
326
|
+
end
|
327
|
+
|
328
|
+
it "executes handlers in order of handler classes" do
|
329
|
+
invoked = []
|
330
|
+
@bus.subscribe(TestEvent, nil, 1) do |_|
|
331
|
+
invoked << 1
|
332
|
+
end
|
333
|
+
@bus.subscribe(TestEvent, nil, 2) do |_|
|
334
|
+
invoked << 2
|
335
|
+
end
|
336
|
+
@bus.subscribe(TestEvent, nil, 0) do |_|
|
337
|
+
invoked << 0
|
338
|
+
end
|
339
|
+
|
340
|
+
@bus.publish(TestEvent.new)
|
341
|
+
|
342
|
+
# Since we used a simple numeric class for each handler, we expect the
|
343
|
+
# handlers to be executed in numeric sort order - independent of the order
|
344
|
+
# they were subscribed.
|
345
|
+
expect(invoked).to eql [0, 1, 2]
|
346
|
+
end
|
347
|
+
end
|
322
348
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: octiron
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jens Finkhaeuser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-12-
|
11
|
+
date: 2016-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|