Module intercepts containing class's initialize method?

I'm wondering if something like this is possible:

  module Intercept
    def intercept_initialize
      puts "performing Intercept#intercept_initialize"
      # somehow call containing class's 'initialize' method here
    end
  end

  class Foo
    def initialize
      puts "performing Foo#initialize"
    end
  end

  class Bar
    include Intercept
    def initialize
      puts "performing Bar#initialize"
    end
  end

  puts "instatiating Foo"
  Foo.new
  puts "instatiating Bar"
  Bar.new
  puts "done"

Desired results:

  instantiating Foo
  performing Foo#initialize
  instantiating Bar
  performing Intercept#intercept_initialize
  performing Bar#initialize
  done
    
In other words, simply by including the "Intercept" module in a class,
I'd like to intercept that class's call to "initialize" and have the
Intercept module's code get invoked first, and _then_ the containing
class's "initialize" method should be called as it normally would.

Is this possible? If so, how?

Thanks in advance.

···

--
Lloyd Zusman
ljz@asfast.com
God bless you.

Lloyd Zusman wrote:

  class Bar
    include Intercept
    def initialize
      puts "performing Bar#initialize"
    end
  end

In other words, simply by including the "Intercept" module in a class,
I'd like to intercept that class's call to "initialize" and have the
Intercept module's code get invoked first, and _then_ the containing
class's "initialize" method should be called as it normally would.

I think the only way of doing that without putting the include() behind the initialize def would be using a method_added hook...

I'd also like there to be a better way of doing this and if I'm not completely wrong and confusing things matz is already thinking about this issue.

Lloyd Zusman wrote:

I'm wondering if something like this is possible:

  module Intercept
    def intercept_initialize
      puts "performing Intercept#intercept_initialize"
      # somehow call containing class's 'initialize' method here
    end
  end

  class Foo
    def initialize
      puts "performing Foo#initialize"
    end
  end

  class Bar
    include Intercept
    def initialize
      puts "performing Bar#initialize"
    end
  end

  puts "instatiating Foo"
  Foo.new
  puts "instatiating Bar"
  Bar.new
  puts "done"

Desired results:

  instantiating Foo
  performing Foo#initialize
  instantiating Bar
  performing Intercept#intercept_initialize
  performing Bar#initialize
  done

In other words, simply by including the "Intercept" module in a

class,

I'd like to intercept that class's call to "initialize" and have the
Intercept module's code get invoked first, and _then_ the containing
class's "initialize" method should be called as it normally would.

Simply redefine IncludingClass::new like this:

.. module Intercept
.. def self.included(mod)
.. super(mod)
.. def mod.intercept_initialize
.. puts "performing Intercept#intercept_initialize"
.. # somehow call containing class's 'initialize' method here
.. end
.. def mod.new *args
.. inst = super *args
.. intercept_initialize
.. inst
.. end
.. end
.. end
..
.. class Foo
.. def initialize
.. puts "performing Foo#initialize"
.. end
.. end
..
.. class Bar
.. include Intercept
.. def initialize
.. puts "performing Bar#initialize"
.. end
.. end
..
.. puts "instatiating Foo"
.. Foo.new
.. puts "instatiating Bar"
.. Bar.new
.. puts "done"

"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:m3vf968oa9.fsf@asfast.com...

I'm wondering if something like this is possible:

  module Intercept
    def intercept_initialize
      puts "performing Intercept#intercept_initialize"
      # somehow call containing class's 'initialize' method here
    end
  end

  class Foo
    def initialize
      puts "performing Foo#initialize"
    end
  end

  class Bar
    include Intercept
    def initialize
      puts "performing Bar#initialize"
    end
  end

  puts "instatiating Foo"
  Foo.new
  puts "instatiating Bar"
  Bar.new
  puts "done"

Desired results:

  instantiating Foo
  performing Foo#initialize
  instantiating Bar
  performing Intercept#intercept_initialize
  performing Bar#initialize
  done

In other words, simply by including the "Intercept" module in a class,
I'd like to intercept that class's call to "initialize" and have the
Intercept module's code get invoked first, and _then_ the containing
class's "initialize" method should be called as it normally would.

Is this possible? If so, how?

The proper way is to use super IMHO:

  module Intercept
    def initialize(*a,&b)
      super
      puts "performing Intercept#intercept_initialize"
      # somehow call containing class's 'initialize' method here
    end
  end

  class Foo
    def initialize
      super
      puts "performing Foo#initialize"
    end
  end

  class Bar
    include Intercept
    def initialize
      super
      puts "performing Bar#initialize"
    end
  end

All other suggested approaches (changing a class's new or using a hook)
are more complicated than necessary IMHO.

Kind regards

    robert

Florian Gross <flgr@ccan.de> writes:

Lloyd Zusman wrote:

  class Bar
    include Intercept
    def initialize
      puts "performing Bar#initialize"
    end
  end

In other words, simply by including the "Intercept" module in a class,
I'd like to intercept that class's call to "initialize" and have the
Intercept module's code get invoked first, and _then_ the containing
class's "initialize" method should be called as it normally would.

I think the only way of doing that without putting the include() behind
the initialize def would be using a method_added hook...

Could you explain how this could be done with a method_added hook?

I'd also like there to be a better way of doing this and if I'm not
completely wrong and confusing things matz is already thinking about
this issue.

Yes, that would be great.

Thank you very much.

···

--
Lloyd Zusman
ljz@asfast.com
God bless you.

Lloyd Zusman wrote:

class Bar
   include Intercept
   def initialize
     puts "performing Bar#initialize"
   end
end

In other words, simply by including the "Intercept" module in a class,
I'd like to intercept that class's call to "initialize" and have the
Intercept module's code get invoked first, and _then_ the containing
class's "initialize" method should be called as it normally would.

I think the only way of doing that without putting the include() behind
the initialize def would be using a method_added hook...

Could you explain how this could be done with a method_added hook?

Like this:

   require 'thread'

   module Intercept
     def self.included(other)
       install_initialize = lambda do
         other.class_eval do
           alias :old_initialize :initialize

           def initialize(*args, &block)
             intercept_initialize
             old_initialize(*args, &block)
           end
         end
       end

       class << other; self; end.class_eval do
         alias :old_method_added :method_added

         ignore = false
         define_method(:method_added) do |name|
           return if ignore

           case name
             when :initialize then
               Thread.exclusive do
                 ignore = true
                 install_initialize.call
                 ignore = false
               end
             else
               old_method_added(name)
           end
         end
       end

       install_initialize.call
       super
     end

     def intercept_initialize
       puts "performing Intercept#intercept_initialize"
     end
   end

   class Bar
     include Intercept
     def initialize
       puts "performing Bar#initialize"
     end
   end

   Bar.new

But note that in that case the user could still redefine Bar.method_added() and circumvent the restore logic. I think adding a singleton_method_added handler would fix that.

I'm also not sure if the Thread.exclusive stuff can be done in a cleaner way...