Added gitorious-hosted repos to repository list.
[merb_radiant.git] / lib / method_observer.rb
blobe8ad1d34a170677a1418c41e474ad07e6fc2ef42
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 end