1 class MethodObserver
2
3 attr_reader :target
4 attr_accessor :result
5
6 class ObserverCannotObserveTwiceError < StandardError
7 def initialize(message = 'observer cannot observe twice')
8 super
9 end
10 end
11
12 def observe(target)
13 raise ObserverCannotObserveTwiceError if @target
14 @target = target
15 make_observable(target)
16 end
17
18 def self.instances
19 @instances ||= {}
20 end
21
22 def self.new(*args)
23 o = super
24 instances[o.object_id] = o
25 o
26 end
27
28 private
29 def make_observable(target)
30 methods_to_observe.each do |method|
31 target.instance_eval %{
32 def #{method}(*args, &block)
33 observer = #{self.class}.instances[#{self.object_id}]
34 observer.send(:before_#{method}, *args, &block) if observer.respond_to? :before_#{method}
35 observer.result = super
36 observer.send(:after_#{method}, *args, &block) if observer.respond_to? :after_#{method}
37 observer.result
38 end
39 }
40 end
41 end
42
43 def methods_to_observe
44 (methods_for(:before) + methods_for(:after)).uniq
45 end
46
47 def methods_for(name)
48 methods.grep(/^#{name}_/).map { |n| n.to_s.gsub(/^#{name}_/, '').intern }
49 end
50 en