octiron 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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