I want to be notified when certain things happen in some of my classes. I want to set this up in such a way that the implementation of my methods in those classes doesn\'t c
I imagine you could use an alias method chain.
Something like this:
def notify_when(method)  
  alias_method "#{method}_without_notification", method
  define_method method do |*args|
    puts "#{method} called"
    send "#{method}_without_notification", args
  end
end
You do not have to modify methods yourself with this approach.
It has been quite a while since this question here has been active, but there is another possibility to wrap methods by an included (or extended) Module.
Since 2.0 you can prepend a Module, effectively making it a proxy for the prepending class.
In the example below, a method of an extended module module is called, passing the names of the methods you want to be wrapped. For each of the method names, a new Module is created and prepended. This is for code simplicity. You can also append multiple methods to a single proxy.
An important difference to the solutions using alias_method and instance_method which is later bound on self is that you can define the methods to be wrapped before the methods themselves are defined.
module Prepender
  def wrap_me(*method_names)
    method_names.each do |m|
      proxy = Module.new do
        define_method(m) do |*args|
          puts "the method '#{m}' is about to be called"
          super *args
        end
      end
      self.prepend proxy
    end
  end
end
Use:
class Dogbert
  extend Prepender
  wrap_me :bark, :deny
  def bark
    puts 'Bah!'
  end
  def deny
    puts 'You have no proof!'
  end
end
Dogbert.new.deny
# => the method 'deny' is about to be called
# => You have no proof!
                                                                        I can think of two approaches:
(1) Decorate the Foo methods to include a notification.
(2) Use a proxy object that intercepts method calls to Foo and notifies you when they happen
The first solution is the approach taken by Jakub, though the alias_method solution is not the best way to achieve this, use this instead:
def notify_when(meth)  
  orig_meth = instance_method(meth)
  define_method(meth) do |*args, &block|
    puts "#{meth} called"
    orig_meth.bind(self).call *args, &block
  end
end
The second solution requires you to use method_missing in combination with a proxy:
class Interceptor
  def initialize(target)
    @target = target
  end
  def method_missing(name, *args, &block)
    if @target.respond_to?(name)
      puts "about to run #{name}"
      @target.send(name, *args, &block)
    else
      super
    end
  end
end
class Hello; def hello; puts "hello!"; end; end
i = Interceptor.new(Hello.new)
i.hello #=> "about to run hello"
        #=> "hello!"
The first method requires modifying the methods (something you said you didn't want) and the second method requires using a proxy, maybe something you do not want. There is no easy solution I'm sorry.