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