Hal Fulton wrote:

> For example, I'll name this method "action"; suppose that in
> general, it just calls do_this and do_that.
> 
>   def action
>     do_this
>     do_that
>   end
> 
> But now suppose we enable things like a debug mode and a
> trace mode and logging and a configurable delay and such:
> 
>   def action
>     STDERR.puts "Entering action" if @trace
>     STDERR.puts "before do_this: foo = #@foo" if @debug
>     @log.puts "#{Time.now}: Useful info" if @log
>     sleep(@delay) if @delay
>     do_this
>     STDERR.puts "Returned from do_this" if @trace
>     STDERR.puts "after do_this: foo = #@foo" if @debug
>     @log.puts "#{Time.now}: More useful info" if @log
>     do_that
>     STDERR.puts "Returned from do_that" if @trace
>     STDERR.puts "after do_that: foo = #@foo" if @debug
>     @log.puts "#{Time.now}: Still more useful info" if @log
>   end
> 
> Here we've added ten if-statements. If #action is called
> frequently, performance will degrade even if these special
> attributes are not set.

Maybe something like this will work reasonably?

   def initialize
     @action_hooks = Hash.new do |hash, method|
       hash[method] = Hash.new do |type_hash, type|
         type_hash[type] = Array.new
       end
     end
   end

   def call_hook(method, type, *more)
     @action_hooks[method][type].each { |hook| hook.call(*more) }
   end

   def register_hook(method, type, &block)
     @action_hooks[method][type] << block
   end

   def action
     call_hook(:action, :before_do_this)
     do_this
     call_hook(:action, :before_do_that)
     do_that
     call_hook(:action, :before_end)
   end

I suppose that someway it could be factored out to a reusable Mix-In.

Regards,
Florian Gross