Permalink
Browse files

Optimize AS::Notifications to remember which subscribers don't match …

…and not run them. This will allow notifications that are only useful in dev or testing to run efficiently in production.
  • Loading branch information...
1 parent c88360e commit fc0882ba5a0f18281736859718252042b15614ad Carlhuda committed Mar 2, 2010
@@ -44,7 +44,7 @@ module Notifications
class << self
attr_writer :notifier
- delegate :publish, :subscribe, :to => :notifier
+ delegate :publish, :subscribe, :unsubscribe, :to => :notifier
delegate :instrument, :to => :instrumenter
def notifier
@@ -5,23 +5,30 @@ module Notifications
class Fanout
def initialize
@subscribers = []
+ @listeners_for = {}
end
def bind(pattern)
Binding.new(self, pattern)
end
def subscribe(pattern = nil, &block)
+ @listeners_for.clear
@subscribers << Subscriber.new(pattern, &block)
@subscribers.last
end
def unsubscribe(subscriber)
@subscribers.delete(subscriber)
+ @listeners_for.clear
end
- def publish(*args)
- @subscribers.each { |s| s.publish(*args) }
+ def publish(name, *args)
+ if listeners = @listeners_for[name]
+ listeners.each { |s| s.publish(name, *args) }
+ else
+ @listeners_for[name] = @subscribers.select { |s| s.publish(name, *args) }
+ end
end
# This is a sync queue, so there is not waiting.
@@ -53,7 +60,9 @@ def initialize(pattern, &block)
end
def publish(*args)
- push(*args) if matches?(args.first)
+ return unless matches?(args.first)
+ push(*args)
+ true
end
def drained?
@@ -20,15 +20,20 @@ def drain
end
class UnsubscribeTest < TestCase
- def unsubscribing_removes_a_subscription
+ def test_unsubscribing_removes_a_subscription
@notifier.publish :foo
@notifier.wait
assert_equal [[:foo]], @events
@notifier.unsubscribe(@subscription)
- @notifier.publish :bar
+ @notifier.publish :foo
@notifier.wait
assert_equal [[:foo]], @events
end
+
+ private
+ def event(*args)
+ args
+ end
end
class SyncPubSubTest < TestCase
@@ -38,6 +43,28 @@ def test_events_are_published_to_a_listener
assert_equal [[:foo]], @events
end
+ def test_publishing_multiple_times_works
+ @notifier.publish :foo
+ @notifier.publish :foo
+ @notifier.wait
+ assert_equal [[:foo], [:foo]], @events
+ end
+
+ def test_publishing_after_a_new_subscribe_works
+ @notifier.publish :foo
+ @notifier.publish :foo
+
+ @notifier.subscribe("not_existant") do |*args|
+ @events << ActiveSupport::Notifications::Event.new(*args)
+ end
+
+ @notifier.publish :foo
+ @notifier.publish :foo
+ @notifier.wait
+
+ assert_equal [[:foo]] * 4, @events
+ end
+
def test_log_subscriber_with_pattern
events = []
@notifier.subscribe('1') { |*args| events << args }

0 comments on commit fc0882b

Please sign in to comment.