10 def observers=(*values)
11 @observers = values.flatten
14 def instantiate_observers
15 observers.each { |o| instantiate_observer(o) }
19 def instantiate_observer(observer)
21 if observer.respond_to?(:to_sym)
22 observer = observer.to_s.camelize.constantize.instance
23 elsif observer.respond_to?(:instance)
26 raise ArgumentError, "#{observer} must be a lowercase, underscored class name (or an instance of the class itself) responding to the instance method. Example: Person.observers = :big_brother # calls BigBrother.instance"
30 # Notify observers when the observed class is subclassed.
31 def inherited(subclass)
34 notify_observers :observed_class_inherited, subclass
38 def self.included(receiver)
39 receiver.extend Observable, ClassMethods
45 attr_writer :observed_classes
49 # Attaches the observer to the supplied model classes.
51 @models = models.flatten
52 @models.collect! { |model| model.respond_to?(:to_sym) ? model.to_s.camelize.constantize : model }
55 def observed_class_name
56 @observed_class_name ||=
57 if guessed_name = name.scan(/(.*)Observer/)[0]
58 @observed_class_name = guessed_name[0]
62 # The class observed by default is inferred from the observer's class name:
63 # assert_equal [Person], PersonObserver.observed_class
65 if observed_class_name
66 observed_class_name.constantize
73 # Start observing the declared classes and their subclasses.
75 self.observed_classes = self.class.models if self.class.models
76 observed_classes.each { |klass| add_observer! klass }
79 # Send observed_method(object) if the method exists.
80 def update(observed_method, object) #:nodoc:
81 send(observed_method, object) if respond_to?(observed_method)
84 # Special method sent by the observed class when it is inherited.
85 # Passes the new subclass.
86 def observed_class_inherited(subclass) #:nodoc:
87 self.class.observe(observed_classes + [subclass])
88 add_observer!(subclass)
93 @observed_classes ||= [self.class.observed_class]
96 def add_observer!(klass)
97 klass.add_observer(self)