forked from radiant/radiant
-
Notifications
You must be signed in to change notification settings - Fork 0
/
method_observer.rb
50 lines (42 loc) · 1.21 KB
/
method_observer.rb
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
class MethodObserver
attr_reader :target
attr_accessor :result
class ObserverCannotObserveTwiceError < StandardError
def initialize(message = 'observer cannot observe twice')
super
end
end
def observe(target)
raise ObserverCannotObserveTwiceError if @target
@target = target
make_observable(target)
end
def self.instances
@instances ||= {}
end
def self.new(*args)
o = super
instances[o.object_id] = o
o
end
private
def make_observable(target)
methods_to_observe.each do |method|
target.instance_eval %{
def #{method}(*args, &block)
observer = #{self.class}.instances[#{self.object_id}]
observer.send(:before_#{method}, *args, &block) if observer.respond_to? :before_#{method}
observer.result = super
observer.send(:after_#{method}, *args, &block) if observer.respond_to? :after_#{method}
observer.result
end
}
end
end
def methods_to_observe
(methods_for(:before) + methods_for(:after)).uniq
end
def methods_for(name)
methods.grep(/^#{name}_/).map { |n| n.to_s.gsub(/^#{name}_/, '').intern }
end
end