aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/lib/active_model/observing.rb
diff options
context:
space:
mode:
authorVijay Dev <vijaydev.cse@gmail.com>2012-08-04 15:18:35 +0530
committerVijay Dev <vijaydev.cse@gmail.com>2012-08-04 15:18:35 +0530
commit3d3fa165e40c8cdaaebdab9dd2985d0ca3a36236 (patch)
tree21ae9b984d34c9487628097f3933f8fa14a3558f /activemodel/lib/active_model/observing.rb
parentc963f883a41913624363bfd8203b5640318198c2 (diff)
parentb51201242aaf77c6db5a9b2f72e433c521df79c5 (diff)
downloadrails-3d3fa165e40c8cdaaebdab9dd2985d0ca3a36236.tar.gz
rails-3d3fa165e40c8cdaaebdab9dd2985d0ca3a36236.tar.bz2
rails-3d3fa165e40c8cdaaebdab9dd2985d0ca3a36236.zip
Merge branch 'master' of github.com:lifo/docrails
Conflicts: activemodel/lib/active_model/secure_password.rb activerecord/lib/active_record/associations/collection_proxy.rb
Diffstat (limited to 'activemodel/lib/active_model/observing.rb')
-rw-r--r--activemodel/lib/active_model/observing.rb205
1 files changed, 158 insertions, 47 deletions
diff --git a/activemodel/lib/active_model/observing.rb b/activemodel/lib/active_model/observing.rb
index acc96ddc9f..9db7639ea3 100644
--- a/activemodel/lib/active_model/observing.rb
+++ b/activemodel/lib/active_model/observing.rb
@@ -8,6 +8,7 @@ require 'active_support/core_ext/object/try'
require 'active_support/descendants_tracker'
module ActiveModel
+ # == Active Model Observers Activation
module Observing
extend ActiveSupport::Concern
@@ -16,9 +17,7 @@ module ActiveModel
end
module ClassMethods
- # == Active Model Observers Activation
- #
- # Activates the observers assigned. Examples:
+ # Activates the observers assigned.
#
# class ORM
# include ActiveModel::Observing
@@ -34,34 +33,95 @@ module ActiveModel
# ORM.observers = Cacher, GarbageCollector
#
# Note: Setting this does not instantiate the observers yet.
- # +instantiate_observers+ is called during startup, and before
+ # <tt>instantiate_observers</tt> is called during startup, and before
# each development request.
def observers=(*values)
observers.replace(values.flatten)
end
- # Gets an array of observers observing this model.
- # The array also provides +enable+ and +disable+ methods
- # that allow you to selectively enable and disable observers.
- # (see <tt>ActiveModel::ObserverArray.enable</tt> and
- # <tt>ActiveModel::ObserverArray.disable</tt> for more on this)
+ # Gets an array of observers observing this model. The array also provides
+ # +enable+ and +disable+ methods that allow you to selectively enable and
+ # disable observers (see ActiveModel::ObserverArray.enable and
+ # ActiveModel::ObserverArray.disable for more on this).
+ #
+ # class ORM
+ # include ActiveModel::Observing
+ # end
+ #
+ # ORM.observers = :cacher, :garbage_collector
+ # ORM.observers # => [:cacher, :garbage_collector]
+ # ORM.observers.class # => ActiveModel::ObserverArray
def observers
@observers ||= ObserverArray.new(self)
end
- # Gets the current observer instances.
+ # Returns the current observer instances.
+ #
+ # class Foo
+ # include ActiveModel::Observing
+ #
+ # attr_accessor :status
+ # end
+ #
+ # class FooObserver < ActiveModel::Observer
+ # def on_spec(record, *args)
+ # record.status = true
+ # end
+ # end
+ #
+ # Foo.observers = FooObserver
+ # Foo.instantiate_observers
+ #
+ # Foo.observer_instances # => [#<FooObserver:0x007fc212c40820>]
def observer_instances
@observer_instances ||= []
end
# Instantiate the global observers.
+ #
+ # class Foo
+ # include ActiveModel::Observing
+ #
+ # attr_accessor :status
+ # end
+ #
+ # class FooObserver < ActiveModel::Observer
+ # def on_spec(record, *args)
+ # record.status = true
+ # end
+ # end
+ #
+ # Foo.observers = FooObserver
+ #
+ # foo = Foo.new
+ # foo.status = false
+ # foo.notify_observers(:on_spec)
+ # foo.status # => false
+ #
+ # Foo.instantiate_observers # => [FooObserver]
+ #
+ # foo = Foo.new
+ # foo.status = false
+ # foo.notify_observers(:on_spec)
+ # foo.status # => true
def instantiate_observers
observers.each { |o| instantiate_observer(o) }
end
- # Add a new observer to the pool.
- # The new observer needs to respond to 'update', otherwise it
- # raises an +ArgumentError+ exception.
+ # Add a new observer to the pool. The new observer needs to respond to
+ # <tt>update</tt>, otherwise it raises an +ArgumentError+ exception.
+ #
+ # class Foo
+ # include ActiveModel::Observing
+ # end
+ #
+ # class FooObserver < ActiveModel::Observer
+ # end
+ #
+ # Foo.add_observer(FooObserver.instance)
+ #
+ # Foo.observers_instance
+ # # => [#<FooObserver:0x007fccf55d9390>]
def add_observer(observer)
unless observer.respond_to? :update
raise ArgumentError, "observer needs to respond to 'update'"
@@ -69,16 +129,47 @@ module ActiveModel
observer_instances << observer
end
- # Notify list of observers of a change.
+ # Fires notifications to model's observers.
+ #
+ # def save
+ # notify_observers(:before_save)
+ # ...
+ # notify_observers(:after_save)
+ # end
+ #
+ # Custom notifications can be sent in a similar fashion:
+ #
+ # notify_observers(:custom_notification, :foo)
+ #
+ # This will call <tt>custom_notification</tt>, passing as arguments
+ # the current object and <tt>:foo</tt>.
def notify_observers(*args)
observer_instances.each { |observer| observer.update(*args) }
end
- # Total number of observers.
+ # Returns the total number of instantiated observers.
+ #
+ # class Foo
+ # include ActiveModel::Observing
+ #
+ # attr_accessor :status
+ # end
+ #
+ # class FooObserver < ActiveModel::Observer
+ # def on_spec(record, *args)
+ # record.status = true
+ # end
+ # end
+ #
+ # Foo.observers = FooObserver
+ # Foo.observers_count # => 0
+ # Foo.instantiate_observers
+ # Foo.observers_count # => 1
def observers_count
observer_instances.size
end
+ # <tt>count_observers</tt> is deprecated. Use #observers_count.
def count_observers
msg = "count_observers is deprecated in favor of observers_count"
ActiveSupport::Deprecation.warn(msg)
@@ -103,27 +194,36 @@ module ActiveModel
end
# Notify observers when the observed class is subclassed.
- def inherited(subclass)
+ def inherited(subclass) #:nodoc:
super
notify_observers :observed_class_inherited, subclass
end
end
- # Fires notifications to model's observers
+ # Notify a change to the list of observers.
+ #
+ # class Foo
+ # include ActiveModel::Observing
#
- # def save
- # notify_observers(:before_save)
- # ...
- # notify_observers(:after_save)
+ # attr_accessor :status
# end
#
- # Custom notifications can be sent in a similar fashion:
+ # class FooObserver < ActiveModel::Observer
+ # def on_spec(record, *args)
+ # record.status = true
+ # end
+ # end
#
- # notify_observers(:custom_notification, :foo)
+ # Foo.observers = FooObserver
+ # Foo.instantiate_observers # => [FooObserver]
#
- # This will call +custom_notification+, passing as arguments
- # the current object and :foo.
+ # foo = Foo.new
+ # foo.status = false
+ # foo.notify_observers(:on_spec)
+ # foo.status # => true
#
+ # See ActiveModel::Observing::ClassMethods.notify_observers for more
+ # information.
def notify_observers(method, *extra_args)
self.class.notify_observers(method, self, *extra_args)
end
@@ -135,15 +235,15 @@ module ActiveModel
# behavior outside the original class. This is a great way to reduce the
# clutter that normally comes when the model class is burdened with
# functionality that doesn't pertain to the core responsibility of the
- # class. Example:
+ # class.
#
# class CommentObserver < ActiveModel::Observer
# def after_save(comment)
- # Notifications.comment("admin@do.com", "New comment was posted", comment).deliver
+ # Notifications.comment('admin@do.com', 'New comment was posted', comment).deliver
# end
# end
#
- # This Observer sends an email when a Comment#save is finished.
+ # This Observer sends an email when a <tt>Comment#save</tt> is finished.
#
# class ContactObserver < ActiveModel::Observer
# def after_create(contact)
@@ -160,44 +260,50 @@ module ActiveModel
# == Observing a class that can't be inferred
#
# Observers will by default be mapped to the class with which they share a
- # name. So CommentObserver will be tied to observing Comment, ProductManagerObserver
- # to ProductManager, and so on. If you want to name your observer differently than
- # the class you're interested in observing, you can use the <tt>Observer.observe</tt>
- # class method which takes either the concrete class (Product) or a symbol for that
- # class (:product):
+ # name. So <tt>CommentObserver</tt> will be tied to observing <tt>Comment</tt>,
+ # <tt>ProductManagerObserver</tt> to <tt>ProductManager</tt>, and so on. If
+ # you want to name your observer differently than the class you're interested
+ # in observing, you can use the <tt>Observer.observe</tt> class method which
+ # takes either the concrete class (<tt>Product</tt>) or a symbol for that
+ # class (<tt>:product</tt>):
#
# class AuditObserver < ActiveModel::Observer
# observe :account
#
# def after_update(account)
- # AuditTrail.new(account, "UPDATED")
+ # AuditTrail.new(account, 'UPDATED')
# end
# end
#
- # If the audit observer needs to watch more than one kind of object, this can be
- # specified with multiple arguments:
+ # If the audit observer needs to watch more than one kind of object, this can
+ # be specified with multiple arguments:
#
# class AuditObserver < ActiveModel::Observer
# observe :account, :balance
#
# def after_update(record)
- # AuditTrail.new(record, "UPDATED")
+ # AuditTrail.new(record, 'UPDATED')
# end
# end
#
- # The AuditObserver will now act on both updates to Account and Balance by treating
- # them both as records.
+ # The <tt>AuditObserver</tt> will now act on both updates to <tt>Account</tt>
+ # and <tt>Balance</tt> by treating them both as records.
#
- # If you're using an Observer in a Rails application with Active Record, be sure to
- # read about the necessary configuration in the documentation for
+ # If you're using an Observer in a Rails application with Active Record, be
+ # sure to read about the necessary configuration in the documentation for
# ActiveRecord::Observer.
- #
class Observer
include Singleton
extend ActiveSupport::DescendantsTracker
class << self
# Attaches the observer to the supplied model classes.
+ #
+ # class AuditObserver < ActiveModel::Observer
+ # observe :account, :balance
+ # end
+ #
+ # AuditObserver.observed_classes # => [Account, Balance]
def observe(*models)
models.flatten!
models.collect! { |model| model.respond_to?(:to_sym) ? model.to_s.camelize.constantize : model }
@@ -206,6 +312,8 @@ module ActiveModel
# Returns an array of Classes to observe.
#
+ # AccountObserver.observed_classes # => [Account]
+ #
# You can override this instead of using the +observe+ helper.
#
# class AuditObserver < ActiveModel::Observer
@@ -217,8 +325,11 @@ module ActiveModel
Array(observed_class)
end
- # The class observed by default is inferred from the observer's class name:
- # assert_equal Person, PersonObserver.observed_class
+ # Returns the class observed by default. It's inferred from the observer's
+ # class name.
+ #
+ # PersonObserver.observed_class # => Person
+ # AccountObserver.observed_class # => Account
def observed_class
name[/(.*)Observer/, 1].try :constantize
end
@@ -226,7 +337,7 @@ module ActiveModel
# Start observing the declared classes and their subclasses.
# Called automatically by the instance method.
- def initialize
+ def initialize #:nodoc:
observed_classes.each { |klass| add_observer!(klass) }
end
@@ -237,7 +348,7 @@ module ActiveModel
# Send observed_method(object) if the method exists and
# the observer is enabled for the given object's class.
def update(observed_method, object, *extra_args, &block) #:nodoc:
- return if !respond_to?(observed_method) || disabled_for?(object)
+ return if !respond_to?(observed_method) || disabled_for?(object)
send(observed_method, object, *extra_args, &block)
end
@@ -254,7 +365,7 @@ module ActiveModel
end
# Returns true if notifications are disabled for this object.
- def disabled_for?(object)
+ def disabled_for?(object) #:nodoc:
klass = object.class
return false unless klass.respond_to?(:observers)
klass.observers.disabled_for?(self)