Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/branches/2-1-caching/activemodel/lib/active_model/observing.rb

Revision 8118, 2.8 kB (checked in by rick, 1 year ago)

initial experimental commit of active_model

Line 
1 require 'observer'
2
3 module ActiveModel
4   module Observing
5     module ClassMethods
6       def observers
7         @observers ||= []
8       end
9      
10       def observers=(*values)
11         @observers = values.flatten
12       end
13      
14       def instantiate_observers
15         observers.each { |o| instantiate_observer(o) }
16       end
17    
18     protected
19       def instantiate_observer(observer)
20         # string/symbol
21         if observer.respond_to?(:to_sym)
22           observer = observer.to_s.camelize.constantize.instance
23         elsif observer.respond_to?(:instance)
24           observer.instance
25         else
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"
27         end
28       end
29      
30       # Notify observers when the observed class is subclassed.
31       def inherited(subclass)
32         super
33         changed
34         notify_observers :observed_class_inherited, subclass
35       end
36     end
37    
38     def self.included(receiver)
39       receiver.extend Observable, ClassMethods
40     end
41   end
42
43   class Observer
44     include Singleton
45     attr_writer :observed_classes
46
47     class << self
48       attr_accessor :models
49       # Attaches the observer to the supplied model classes.
50       def observe(*models)
51         @models = models.flatten
52         @models.collect! { |model| model.respond_to?(:to_sym) ? model.to_s.camelize.constantize : model }
53       end
54
55       def observed_class_name
56         @observed_class_name ||=
57           if guessed_name = name.scan(/(.*)Observer/)[0]
58             @observed_class_name = guessed_name[0]
59           end
60       end
61
62       # The class observed by default is inferred from the observer's class name:
63       #   assert_equal [Person], PersonObserver.observed_class
64       def observed_class
65         if observed_class_name
66           observed_class_name.constantize
67         else
68           nil
69         end
70       end
71     end
72
73     # Start observing the declared classes and their subclasses.
74     def initialize
75       self.observed_classes = self.class.models if self.class.models
76       observed_classes.each { |klass| add_observer! klass }
77     end
78
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)
82     end
83
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)
89     end
90
91     protected
92       def observed_classes
93         @observed_classes ||= [self.class.observed_class]
94       end
95
96       def add_observer!(klass)
97         klass.add_observer(self)
98       end
99   end
100 end
Note: See TracBrowser for help on using the browser.