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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5f6820493b0a41711b72e1cfa9b460a668c1c51a
4
- data.tar.gz: 927c382237fb5ac19863356b451a5cef89610248
3
+ metadata.gz: 77fcd14d6034f8507cd48bcccad8e1c842895bd7
4
+ data.tar.gz: fd7c20ee199a1406e6973ef92519617c14cd628a
5
5
  SHA512:
6
- metadata.gz: 4a2ed141ecc3d958d49e9e9e3e79ee6e2d6187b4c470934119f8cfb71c7a756d7b8caf89a2b26552d69cc7545d61d72c342ed076c0a7a97b152e875c0afed399
7
- data.tar.gz: d6843fe8e9550957fb1eee0a2cfdbee28d01ee65eab309c69842f1056709c26ad9a0bc4707c515e8c2213ca74fcdc6ba8665fdea2d996cb12e4e9189b7f53953
6
+ metadata.gz: 292f9c0256bec186e77be6ca75bb864a6d5b5ea99f1179be7202c6fbe941f4fbe3c4d238f056ad2539f6ed4f12d70f04beb8fce24b9b8616b22b429333447265
7
+ data.tar.gz: ce519cfd7d727e6241a745417c74319b84fd47f403a6a92f7e732e954921d69d1fdd106d633c32650564c2c880ec4d36673d1956d3185c29e6698968eca86271
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- octiron (0.2.0)
4
+ octiron (0.3.0)
5
5
  collapsium (~> 0.8)
6
6
  rgl (~> 0.5)
7
7
 
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
@@ -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, &handler_proc)
50
- return with_handlers(event_id, handler_object, handler_proc) do |hlist, h|
51
- hlist << h
52
- end
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, &handler_proc)
68
- return with_handlers(event_id, handler_object, handler_proc) do |hlist, h|
69
- hlist.delete(h)
70
- end
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
- handlers_for(event_name, false).each do |handler|
83
- handler.call(event)
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
@@ -8,5 +8,5 @@
8
8
  #
9
9
  module Octiron
10
10
  # The current release version
11
- VERSION = "0.2.0".freeze
11
+ VERSION = "0.3.0".freeze
12
12
  end
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, &handler_proc)
124
- ::Octiron::World.event_bus.subscribe(event_id, handler_object, &handler_proc)
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
  ##
@@ -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 properly" do
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.2.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-14 00:00:00.000000000 Z
11
+ date: 2016-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler