wonkavision 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,5 @@
1
+ == 0.5.1
2
+ * Ensure that subscriptions to an event namespace will only get notified once per incoming message
1
3
 
2
4
  == 0.5.0
3
5
  * Initial release
@@ -1,33 +1,33 @@
1
- module Wonkavision
2
-
3
- class Event < Wonkavision::EventPathSegment
4
-
5
- def initialize(name, namespace, opts={})
6
- super name,namespace,opts
7
- @source_events = []
8
- source_events(*opts.delete(:source_events)) if opts.keys.include?(:source_events)
9
- end
10
-
11
- def matches(event_path)
12
- event_path == path || @source_events.detect{|evt|evt.matches(event_path)} != nil
13
- end
14
-
15
- def notify_subscribers(event_data,event_path)
16
- super(event_data,self.path)
17
- end
18
-
19
- def source_events(*args)
20
- return @source_events if args.blank?
21
- @source_events = @source_events.concat(args.map do |source|
22
- source_ns = namespace
23
- if (source=~/^\/.*/)
24
- source_ns = root_namespace
25
- source = source[1..-1]
26
- end
27
- source_ns.find_or_create(source)
28
- end)
29
- end
30
- end
31
-
32
- end
1
+ module Wonkavision
2
+
3
+ class Event < Wonkavision::EventPathSegment
4
+
5
+ def initialize(name, namespace, opts={})
6
+ super name,namespace,opts
7
+ @source_events = []
8
+ source_events(*opts.delete(:source_events)) if opts.keys.include?(:source_events)
9
+ end
10
+
11
+ def matches(event_path)
12
+ event_path == path || @source_events.detect{|evt|evt.matches(event_path)} != nil
13
+ end
14
+
15
+ def notify_subscribers(event_data,event_path)
16
+ super(event_data,self.path)
17
+ end
18
+
19
+ def source_events(*args)
20
+ return @source_events if args.blank?
21
+ @source_events = @source_events.concat(args.map do |source|
22
+ source_ns = namespace
23
+ if (source=~/^\/.*/)
24
+ source_ns = root_namespace
25
+ source = source[1..-1]
26
+ end
27
+ source_ns.find_or_create(source)
28
+ end)
29
+ end
30
+ end
31
+
32
+ end
33
33
 
@@ -39,7 +39,7 @@ module Wonkavision
39
39
  return unless event_data = process_incoming_event(event_path,event_data)
40
40
 
41
41
  event_path = Wonkavision.normalize_event_path(event_path)
42
- targets = root_namespace.find_matching_events(event_path)
42
+ targets = root_namespace.find_matching_segments(event_path).values
43
43
  #If the event wasn't matched, maybe someone is subscribing to '/*' ?
44
44
  targets = [root_namespace] if targets.blank?
45
45
  targets.each{|target|target.notify_subscribers(event_data,event_path)}
@@ -28,13 +28,13 @@ module Wonkavision
28
28
  end
29
29
  end
30
30
 
31
- def find_matching_events (event_path)
32
- events = []
31
+ def find_matching_segments (event_path)
32
+ selected = {}
33
33
  @children.each_value do |child|
34
34
  if (child.is_a?(Wonkavision::Event))
35
- events << child if child.matches(event_path)
35
+ select_segment(child,selected) if child.matches(event_path)
36
36
  elsif (child.is_a?(Wonkavision::EventNamespace))
37
- events.concat(child.find_matching_events(event_path))
37
+ selected.merge!(child.find_matching_segments(event_path))
38
38
  else
39
39
  raise "An unexpected child type was encountered in find_matching_events #{child.class}"
40
40
  end
@@ -42,8 +42,8 @@ module Wonkavision
42
42
  #If no child was found, and the event matches this namespace, we should add ourselves to the list.
43
43
  #This is not necessary if any child event was located, because in that case event notifications
44
44
  #would bubble up to us anyway. If no event was found, there's nobody to blow the bubble but us.
45
- events << self if events.blank? && matches_event(event_path)
46
- events
45
+ select_segment(self,selected) if selected.blank? && matches_event(event_path)
46
+ selected
47
47
  end
48
48
 
49
49
  def matches_event(event_path)
@@ -54,7 +54,7 @@ module Wonkavision
54
54
  def namespace(*args)
55
55
  return super if args.blank?
56
56
  name, opts = args.shift, (args.shift || {})
57
- ns = Wonkavision::EventNamespace.new(name,self,opts)
57
+ ns = @children[name] || Wonkavision::EventNamespace.new(name,self,opts)
58
58
  yield ns if block_given?
59
59
  @children[ns.name] = ns
60
60
  ns
@@ -63,10 +63,17 @@ module Wonkavision
63
63
  def event(*args)
64
64
  name, opts = args.shift, args.extract_options!
65
65
  opts[:source_events] = (opts[:source_events] || []).concat(args) unless args.blank?
66
- evt = Wonkavision::Event.new(name,self,opts)
66
+ evt = @children[name] || Wonkavision::Event.new(name,self,opts)
67
67
  yield evt if block_given?
68
68
  @children[evt.name] = evt
69
69
  evt
70
70
  end
71
+
72
+ private
73
+ def select_segment(segment,selected)
74
+ selected[segment.name] = segment
75
+ select_segment(segment.namespace,selected) if segment.namespace
76
+ end
77
+
71
78
  end
72
79
  end
@@ -22,7 +22,6 @@ module Wonkavision
22
22
  @subscribers.each do |sub|
23
23
  sub.call(event_data,event_path)
24
24
  end
25
- namespace.notify_subscribers(event_data,event_path) if namespace
26
25
  end
27
26
 
28
27
  def root_namespace
@@ -1,3 +1,3 @@
1
1
  module Wonkavision
2
- VERSION = '0.5.0'
2
+ VERSION = '0.5.1'
3
3
  end
@@ -23,8 +23,8 @@ class EventHandlerTest < ActiveSupport::TestCase
23
23
  should "handle subscriptions to the configured namespace" do
24
24
  TestEventHandler.reset
25
25
  Wonkavision.event_coordinator.receive_event("vermicious/hose",1)
26
- Wonkavision.event_coordinator.receive_event("vermicious/kid",2)
27
- Wonkavision.event_coordinator.receive_event("vermiciouser/kid",3)
26
+ Wonkavision.event_coordinator.receive_event("vermicious/dog",2)
27
+ Wonkavision.event_coordinator.receive_event("vermiciouser/knid",3)
28
28
  puts TestEventHandler.knids.inspect
29
29
  assert_equal 2, TestEventHandler.knids.length
30
30
  assert_equal 1, TestEventHandler.knids[0][0]
@@ -42,6 +42,19 @@ class EventHandlerTest < ActiveSupport::TestCase
42
42
  assert_equal 3, TestEventHandler.knids[2][0]
43
43
 
44
44
  end
45
+
46
+ should "only notify once per namespace, even if multiple events are matched in a given namespace" do
47
+ TestEventHandler.reset
48
+
49
+ Wonkavision.event_coordinator.map do |events|
50
+ events.namespace :vermicious do |v|
51
+ v.event :composite, 'oompa','loompa'
52
+ end
53
+ end
54
+
55
+ Wonkavision.event_coordinator.receive_event("vermicious/oompa",1);
56
+ assert_equal 1, TestEventHandler.knids.length
57
+ end
45
58
  end
46
59
 
47
60
  end
@@ -1,109 +1,109 @@
1
- require "test_helper"
2
-
3
- class EventNamespaceTest < ActiveSupport::TestCase
4
-
5
- context "EventNamespace#namespace" do
6
- should "return the namespace if no arguments are provided" do
7
- ns1 = Wonkavision::EventNamespace.new :ns1
8
- ns2 = Wonkavision::EventNamespace.new :ns2, ns1
9
- assert_equal ns1, ns2.namespace
10
- end
11
- should "create a new namespace with the provided name" do
12
- ns1 = Wonkavision::EventNamespace.new :ns1
13
- ns2 = ns1.namespace :ns2
14
- assert_equal ns1, ns2.namespace
15
- assert_equal ns2, ns1.children[ns2.name]
16
- end
17
- should "yield the new namespace for modification" do
18
- ns1 = Wonkavision::EventNamespace.new :ns1
19
- ns2 = ns1.namespace(:ns2){|child|child.namespace(:ns3)}
20
- assert_equal 1, ns2.children.length
21
- assert_equal "ns3", ns2.children.keys[0]
22
- end
23
- end
24
-
25
- context "EventNamespace#event" do
26
- should "create a new event with the provided name" do
27
- ns1 = Wonkavision::EventNamespace.new :ns1
28
- evt = ns1.event :evt1
29
- assert_equal ns1, evt.namespace
30
- assert_equal evt, ns1.children[evt.name]
31
- end
32
- should "provide source_events to the new event if in the opts hash" do
33
- ns1 = Wonkavision::EventNamespace.new :ns1
34
- evt = ns1.event :evt1, :source_events=>"evt2"
35
- assert_equal "evt2", evt.source_events[0].name
36
- end
37
- should "yield new event to block if provided" do
38
- ns1 = Wonkavision::EventNamespace.new :ns1
39
- evt = ns1.event(:evt1) {|evt|evt.source_events "evt2"}
40
- assert_equal "evt2", evt.source_events[0].name
41
- end
42
- end
43
-
44
- context "EventNamespace#find_or_create" do
45
- should "find an existing direct child event" do
46
- ns1 = Wonkavision::EventNamespace.new :ns1
47
- evt = ns1.event :evt1
48
- assert_equal evt, ns1.find_or_create("evt1")
49
- end
50
- should "find a nested event" do
51
- ns1 = Wonkavision::EventNamespace.new :ns1
52
- evt = ns1.namespace(:ns2).event(:evt1)
53
- assert_equal evt, ns1.find_or_create("ns2/evt1")
54
- end
55
- should "find a direct child namespace" do
56
- ns1 = Wonkavision::EventNamespace.new :ns1
57
- ns2 = ns1.namespace :ns2
58
- assert_equal ns2, ns1.find_or_create("ns2")
59
- end
60
- should "find a nested namespace" do
61
- ns1 = Wonkavision::EventNamespace.new :ns1
62
- ns3 = ns1.namespace(:ns2).namespace(:ns3)
63
- assert_equal ns3, ns1.find_or_create("ns2/ns3")
64
- end
65
- should "create a top level child event if not found" do
66
- ns1 = Wonkavision::EventNamespace.new :ns1
67
- evt = ns1.find_or_create("TheNewEvent")
68
- assert_equal "ns1/the_new_event", evt.path
69
- end
70
- should "create a top level child namespace if not found" do
71
- ns1 = Wonkavision::EventNamespace.new :ns1
72
- ns2 = ns1.find_or_create("TheNewNamespace",:namespace)
73
- assert_equal "ns1/the_new_namespace",ns2.path
74
- end
75
- should "create a nested event if namespace exits but event not found" do
76
- ns1 = Wonkavision::EventNamespace.new(:ns1)
77
- ns1.namespace :ns2
78
- evt = ns1.find_or_create("ns2/new_event")
79
- assert_equal "ns1/ns2/new_event",evt.path
80
- end
81
- should "create a nested namespace and event if not found" do
82
- ns1 = Wonkavision::EventNamespace.new :ns1
83
- evt = ns1.find_or_create("ns3/new_event")
84
- assert_equal "ns1/ns3/new_event",evt.path
85
- assert ns1.children["ns3"].children["new_event"]
86
- end
87
- should "create nested namespaces if not found" do
88
- ns1 = Wonkavision::EventNamespace.new :ns1
89
- ns3 = ns1.find_or_create "not/found/my/friend",:namespace
90
- assert ns3.is_a?(Wonkavision::EventNamespace)
91
- assert_equal "ns1/not/found/my/friend", ns3.path
92
- end
93
- end
94
- context "EventNamespace#find_matching_values" do
95
- should "find all events matching the specified path" do
96
- ns1 = Wonkavision::EventNamespace.new :ns1
97
- ns2 = ns1.namespace :ns2
98
- ns2.event "my_event"
99
- ns2.event :e1, "my_event"
100
- ns3 = ns2.namespace :ns3
101
- ns3.event :e2, "/ns2/my_event"
102
- ns4 = ns1.namespace :ns4
103
- ns4.event :e3, "/ns2/my_event"
104
- ns4.event "my_event"
105
-
106
- assert_equal 4, ns1.find_matching_events("ns1/ns2/my_event").length
107
- end
108
- end
1
+ require "test_helper"
2
+
3
+ class EventNamespaceTest < ActiveSupport::TestCase
4
+
5
+ context "EventNamespace#namespace" do
6
+ should "return the namespace if no arguments are provided" do
7
+ ns1 = Wonkavision::EventNamespace.new :ns1
8
+ ns2 = Wonkavision::EventNamespace.new :ns2, ns1
9
+ assert_equal ns1, ns2.namespace
10
+ end
11
+ should "create a new namespace with the provided name" do
12
+ ns1 = Wonkavision::EventNamespace.new :ns1
13
+ ns2 = ns1.namespace :ns2
14
+ assert_equal ns1, ns2.namespace
15
+ assert_equal ns2, ns1.children[ns2.name]
16
+ end
17
+ should "yield the new namespace for modification" do
18
+ ns1 = Wonkavision::EventNamespace.new :ns1
19
+ ns2 = ns1.namespace(:ns2){|child|child.namespace(:ns3)}
20
+ assert_equal 1, ns2.children.length
21
+ assert_equal "ns3", ns2.children.keys[0]
22
+ end
23
+ end
24
+
25
+ context "EventNamespace#event" do
26
+ should "create a new event with the provided name" do
27
+ ns1 = Wonkavision::EventNamespace.new :ns1
28
+ evt = ns1.event :evt1
29
+ assert_equal ns1, evt.namespace
30
+ assert_equal evt, ns1.children[evt.name]
31
+ end
32
+ should "provide source_events to the new event if in the opts hash" do
33
+ ns1 = Wonkavision::EventNamespace.new :ns1
34
+ evt = ns1.event :evt1, :source_events=>"evt2"
35
+ assert_equal "evt2", evt.source_events[0].name
36
+ end
37
+ should "yield new event to block if provided" do
38
+ ns1 = Wonkavision::EventNamespace.new :ns1
39
+ evt = ns1.event(:evt1) {|evt|evt.source_events "evt2"}
40
+ assert_equal "evt2", evt.source_events[0].name
41
+ end
42
+ end
43
+
44
+ context "EventNamespace#find_or_create" do
45
+ should "find an existing direct child event" do
46
+ ns1 = Wonkavision::EventNamespace.new :ns1
47
+ evt = ns1.event :evt1
48
+ assert_equal evt, ns1.find_or_create("evt1")
49
+ end
50
+ should "find a nested event" do
51
+ ns1 = Wonkavision::EventNamespace.new :ns1
52
+ evt = ns1.namespace(:ns2).event(:evt1)
53
+ assert_equal evt, ns1.find_or_create("ns2/evt1")
54
+ end
55
+ should "find a direct child namespace" do
56
+ ns1 = Wonkavision::EventNamespace.new :ns1
57
+ ns2 = ns1.namespace :ns2
58
+ assert_equal ns2, ns1.find_or_create("ns2")
59
+ end
60
+ should "find a nested namespace" do
61
+ ns1 = Wonkavision::EventNamespace.new :ns1
62
+ ns3 = ns1.namespace(:ns2).namespace(:ns3)
63
+ assert_equal ns3, ns1.find_or_create("ns2/ns3")
64
+ end
65
+ should "create a top level child event if not found" do
66
+ ns1 = Wonkavision::EventNamespace.new :ns1
67
+ evt = ns1.find_or_create("TheNewEvent")
68
+ assert_equal "ns1/the_new_event", evt.path
69
+ end
70
+ should "create a top level child namespace if not found" do
71
+ ns1 = Wonkavision::EventNamespace.new :ns1
72
+ ns2 = ns1.find_or_create("TheNewNamespace",:namespace)
73
+ assert_equal "ns1/the_new_namespace",ns2.path
74
+ end
75
+ should "create a nested event if namespace exits but event not found" do
76
+ ns1 = Wonkavision::EventNamespace.new(:ns1)
77
+ ns1.namespace :ns2
78
+ evt = ns1.find_or_create("ns2/new_event")
79
+ assert_equal "ns1/ns2/new_event",evt.path
80
+ end
81
+ should "create a nested namespace and event if not found" do
82
+ ns1 = Wonkavision::EventNamespace.new :ns1
83
+ evt = ns1.find_or_create("ns3/new_event")
84
+ assert_equal "ns1/ns3/new_event",evt.path
85
+ assert ns1.children["ns3"].children["new_event"]
86
+ end
87
+ should "create nested namespaces if not found" do
88
+ ns1 = Wonkavision::EventNamespace.new :ns1
89
+ ns3 = ns1.find_or_create "not/found/my/friend",:namespace
90
+ assert ns3.is_a?(Wonkavision::EventNamespace)
91
+ assert_equal "ns1/not/found/my/friend", ns3.path
92
+ end
93
+ end
94
+ context "EventNamespace#find_matching_values" do
95
+ should "find all events matching the specified path" do
96
+ ns1 = Wonkavision::EventNamespace.new :ns1
97
+ ns2 = ns1.namespace :ns2
98
+ ns2.event "my_event"
99
+ ns2.event :e1, "my_event"
100
+ ns3 = ns2.namespace :ns3
101
+ ns3.event :e2, "/ns2/my_event"
102
+ ns4 = ns1.namespace :ns4
103
+ ns4.event :e3, "/ns2/my_event"
104
+ ns4.event "my_event"
105
+
106
+ assert_equal 8, ns1.find_matching_segments("ns1/ns2/my_event").length
107
+ end
108
+ end
109
109
  end
@@ -1,56 +1,42 @@
1
- require "test_helper"
2
-
3
- class EventPathSegmentTest < ActiveSupport::TestCase
4
- context "EventPathSegment#path" do
5
- should "not include path segments for root segments" do
6
- assert_equal "a_segment", Wonkavision::EventPathSegment.new(:a_segment).path
7
- end
8
- should "join the parent namespace in the path for non root segments" do
9
- ns1 = Wonkavision::EventPathSegment.new(:ns_1)
10
- ns2 = Wonkavision::EventPathSegment.new(:ns_2, ns1)
11
- assert_equal "ns_1/ns_2/a_segment", Wonkavision::EventPathSegment.new(:a_segment,ns2).path
12
- end
13
- should "ignore segments in a hierarchy with a nil name" do
14
- ns1 = Wonkavision::EventPathSegment.new(:ns_1)
15
- ns2 = Wonkavision::EventPathSegment.new(nil,ns1)
16
- assert_equal "ns_1/a_segment", Wonkavision::EventPathSegment.new(:a_segment,ns2).path
17
- end
18
- end
19
-
20
- context "EventPathSegment#subscribe" do
21
- should "Add the provided block to the list of subscribers" do
22
- seg = Wonkavision::EventPathSegment.new
23
- x = 1
24
- seg.subscribe {x+=1 }
25
- assert_equal 1, seg.subscribers.length
26
- seg.subscribers[0].call
27
- assert_equal 2, x
28
- end
29
- end
30
-
31
- context "EventPathSegment#notifiy_subscribers" do
32
- should "call each subscribed block" do
33
- seg = Wonkavision::EventPathSegment.new
34
- x = 1
35
- seg.subscribe {x+=1}
36
- seg.subscribe {|data,path|x+=data+path}
37
- seg.notify_subscribers(5,2)
38
-
39
- assert_equal 9, x
40
- end
41
- should "bubble the call to notify_subscribers up the hierarchy" do
42
- called = []
43
- ns1 = Wonkavision::EventPathSegment.new(:ns1)
44
- ns1.subscribe {called << ns1}
45
- ns2 = Wonkavision::EventPathSegment.new(:ns2,ns1)
46
- ns2.subscribe {called << ns2}
47
- evt = Wonkavision::EventPathSegment.new(:evt,ns2)
48
-
49
- evt.notify_subscribers(nil)
50
-
51
- assert_equal 2, called.length
52
- assert_equal ns2, called[0]
53
- assert_equal ns1, called[1]
54
- end
55
- end
1
+ require "test_helper"
2
+
3
+ class EventPathSegmentTest < ActiveSupport::TestCase
4
+ context "EventPathSegment#path" do
5
+ should "not include path segments for root segments" do
6
+ assert_equal "a_segment", Wonkavision::EventPathSegment.new(:a_segment).path
7
+ end
8
+ should "join the parent namespace in the path for non root segments" do
9
+ ns1 = Wonkavision::EventPathSegment.new(:ns_1)
10
+ ns2 = Wonkavision::EventPathSegment.new(:ns_2, ns1)
11
+ assert_equal "ns_1/ns_2/a_segment", Wonkavision::EventPathSegment.new(:a_segment,ns2).path
12
+ end
13
+ should "ignore segments in a hierarchy with a nil name" do
14
+ ns1 = Wonkavision::EventPathSegment.new(:ns_1)
15
+ ns2 = Wonkavision::EventPathSegment.new(nil,ns1)
16
+ assert_equal "ns_1/a_segment", Wonkavision::EventPathSegment.new(:a_segment,ns2).path
17
+ end
18
+ end
19
+
20
+ context "EventPathSegment#subscribe" do
21
+ should "Add the provided block to the list of subscribers" do
22
+ seg = Wonkavision::EventPathSegment.new
23
+ x = 1
24
+ seg.subscribe {x+=1 }
25
+ assert_equal 1, seg.subscribers.length
26
+ seg.subscribers[0].call
27
+ assert_equal 2, x
28
+ end
29
+ end
30
+
31
+ context "EventPathSegment#notifiy_subscribers" do
32
+ should "call each subscribed block" do
33
+ seg = Wonkavision::EventPathSegment.new
34
+ x = 1
35
+ seg.subscribe {x+=1}
36
+ seg.subscribe {|data,path|x+=data+path}
37
+ seg.notify_subscribers(5,2)
38
+
39
+ assert_equal 9, x
40
+ end
41
+ end
56
42
  end