From d287e90870a9832c9d7e9d222881d3a6102bd04d Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sat, 5 Nov 2011 12:02:54 -0700 Subject: implements AS::Notifications.subscribed, which provides subscriptions to events while a block runs --- activesupport/CHANGELOG.md | 2 ++ activesupport/lib/active_support/notifications.rb | 41 +++++++++++++++++++++++ activesupport/test/notifications_test.rb | 20 +++++++++++ 3 files changed, 63 insertions(+) (limited to 'activesupport') diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index ad3828d5e8..e03bfdee92 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,5 +1,7 @@ ## Rails 3.2.0 (unreleased) ## +* ActiveSupport::Notifications.subscribed provides subscriptions to events while a block runs. *fxn* + * Module#qualified_const_(defined?|get|set) are analogous to the corresponding methods in the standard API, but accept qualified constant names. *fxn* diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb index 89afe7b982..719f074948 100644 --- a/activesupport/lib/active_support/notifications.rb +++ b/activesupport/lib/active_support/notifications.rb @@ -63,6 +63,40 @@ module ActiveSupport # and even pass no argument to +subscribe+, in which case you are subscribing # to all events. # + # == Temporary Subscriptions + # + # Sometimes you do not want to subscribe to an event for the entire life of + # the application. There are two ways two unsubscribe. + # + # === Subscribe While a Block Runs + # + # You can subscribe to some event temporarily while some block runs. For + # example, in + # + # callback = lambda {|*args| ... } + # ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do + # ... + # end + # + # the callback will be called for all "sql.active_record" events instrumented + # during the execution of the block. The callback is unsubscribed automatically + # after that. + # + # === Manual Unsubscription + # + # The +subscribe+ method returns a subscriber object: + # + # subscriber = ActiveSupport::Notifications.subscribe("render") do |*args| + # ... + # end + # + # To prevent that block from being called anymore, just unsubscribe passing + # that reference: + # + # ActiveSupport::Notifications.unsubscribe(subscriber) + # + # == Default Queue + # # Notifications ships with a queue implementation that consumes and publish events # to log subscribers in a thread. You can use any queue implementation you want. # @@ -94,6 +128,13 @@ module ActiveSupport end end + def subscribed(callback, *args, &block) + subscriber = subscribe(*args, &callback) + yield + ensure + unsubscribe(subscriber) + end + def unsubscribe(args) notifier.unsubscribe(args) @instrumenters.clear diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb index 884ee61547..fc9fa90d07 100644 --- a/activesupport/test/notifications_test.rb +++ b/activesupport/test/notifications_test.rb @@ -24,6 +24,26 @@ module Notifications end end + class SubscribedTest < TestCase + def test_subscribed + name = "foo" + name2 = name * 2 + expected = [name, name] + + events = [] + callback = lambda {|*_| events << _.first} + ActiveSupport::Notifications.subscribed(callback, name) do + ActiveSupport::Notifications.instrument(name) + ActiveSupport::Notifications.instrument(name2) + ActiveSupport::Notifications.instrument(name) + end + assert_equal expected, events + + ActiveSupport::Notifications.instrument(name) + assert_equal expected, events + end + end + class UnsubscribeTest < TestCase def test_unsubscribing_removes_a_subscription @notifier.publish :foo -- cgit v1.2.3