aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Schierbeck <dasch@zendesk.com>2013-09-19 11:03:58 +0200
committerDaniel Schierbeck <dasch@zendesk.com>2013-09-20 10:14:28 +0200
commitd2824a347fd827bb0af3c16ffed5a3608b358ffc (patch)
treef30fee6a3f57ebfaf02dfaf81f7f90da50783e21
parent76d36458eadcb32c233f44065fccfbbef9a58119 (diff)
downloadrails-d2824a347fd827bb0af3c16ffed5a3608b358ffc.tar.gz
rails-d2824a347fd827bb0af3c16ffed5a3608b358ffc.tar.bz2
rails-d2824a347fd827bb0af3c16ffed5a3608b358ffc.zip
Allow attaching to AS::Notifications namespace up front
Before, you were required to attach *after* adding the methods to the class, since the attachment process needed the methods to be present. With this change, any new method will also be attached to the configured namespace.
-rw-r--r--activesupport/CHANGELOG.md27
-rw-r--r--activesupport/lib/active_support/subscriber.rb27
-rw-r--r--activesupport/test/subscriber_test.rb40
3 files changed, 92 insertions, 2 deletions
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 9ab81c73c8..08c4573b14 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,30 @@
+* Allow attaching event subscribers to ActiveSupport::Notifications namespaces
+ before they're defined. Essentially, this means instead of this:
+
+ class JokeSubscriber < ActiveSupport::Subscriber
+ def sql(event)
+ puts "A rabbi and a priest walk into a bar..."
+ end
+
+ # This call needs to happen *after* defining the methods.
+ attach_to "active_record"
+ end
+
+ You can do this:
+
+ class JokeSubscriber < ActiveSupport::Subscriber
+ # This is much easier to read!
+ attach_to "active_record"
+
+ def sql(event)
+ puts "A rabbi and a priest walk into a bar..."
+ end
+ end
+
+ This should make it easier to read and understand these subscribers.
+
+ *Daniel Schierbeck*
+
* Add `Date#middle_of_day`, `DateTime#middle_of_day` and `Time#middle_of_day` methods.
Also added `midday`, `noon`, `at_midday`, `at_noon` and `at_middle_of_day` as aliases.
diff --git a/activesupport/lib/active_support/subscriber.rb b/activesupport/lib/active_support/subscriber.rb
index 34c6f900c1..f2966f23fc 100644
--- a/activesupport/lib/active_support/subscriber.rb
+++ b/activesupport/lib/active_support/subscriber.rb
@@ -31,18 +31,41 @@ module ActiveSupport
# Attach the subscriber to a namespace.
def attach_to(namespace, subscriber=new, notifier=ActiveSupport::Notifications)
+ @namespace = namespace
+ @subscriber = subscriber
+ @notifier = notifier
+
subscribers << subscriber
+ # Add event subscribers for all existing methods on the class.
subscriber.public_methods(false).each do |event|
- next if %w{ start finish }.include?(event.to_s)
+ add_event_subscriber(event)
+ end
+ end
- notifier.subscribe("#{event}.#{namespace}", subscriber)
+ # Adds event subscribers for all new methods added to the class.
+ def method_added(event)
+ # Only public methods are added as subscribers, and only if a notifier
+ # has been set up. This means that subscribers will only be set up for
+ # classes that call #attach_to.
+ if public_method_defined?(event) && notifier
+ add_event_subscriber(event)
end
end
def subscribers
@@subscribers ||= []
end
+
+ protected
+
+ attr_reader :subscriber, :notifier, :namespace
+
+ def add_event_subscriber(event)
+ return if %w{ start finish }.include?(event.to_s)
+
+ notifier.subscribe("#{event}.#{namespace}", subscriber)
+ end
end
def initialize
diff --git a/activesupport/test/subscriber_test.rb b/activesupport/test/subscriber_test.rb
new file mode 100644
index 0000000000..253411aa3d
--- /dev/null
+++ b/activesupport/test/subscriber_test.rb
@@ -0,0 +1,40 @@
+require 'abstract_unit'
+require 'active_support/subscriber'
+
+class TestSubscriber < ActiveSupport::Subscriber
+ attach_to :doodle
+
+ cattr_reader :event
+
+ def self.clear
+ @@event = nil
+ end
+
+ def open_party(event)
+ @@event = event
+ end
+
+ private
+
+ def private_party(event)
+ @@event = event
+ end
+end
+
+class SubscriberTest < ActiveSupport::TestCase
+ def setup
+ TestSubscriber.clear
+ end
+
+ def test_attaches_subscribers
+ ActiveSupport::Notifications.instrument("open_party.doodle")
+
+ assert_equal "open_party.doodle", TestSubscriber.event.name
+ end
+
+ def test_does_not_attach_private_methods
+ ActiveSupport::Notifications.instrument("private_party.doodle")
+
+ assert_nil TestSubscriber.event
+ end
+end