How to intercept all function calls of a object?

What I want is something like this:

class HelloBye
  def hello
    puts "hello"
  end
  def bye
    puts "byebye"
  end
end

a = HelloBye.new
a.extend #add an intercptor to a
a.hello

Then I can get this kind of result:

call method hello of class HelloBye
hello
return from method hello of class HelloBye

And similar thing for 'bye' and other methods if existed in object a.

···

--
Posted via http://www.ruby-forum.com/.

You could look at
http://onestepback.org/index.cgi/Tech/Ruby/BlankSlate.rdoc, this is a
good start.

j`ey
http://wwww.eachmapinject.com

···

On 5/21/06, uncutstone wu <uncutstone@sina.com> wrote:

What I want is something like this:

class HelloBye
  def hello
    puts "hello"
  end
  def bye
    puts "byebye"
  end
end

a = HelloBye.new
a.extend #add an intercptor to a
a.hello

Then I can get this kind of result:

call method hello of class HelloBye
hello
return from method hello of class HelloBye

And similar thing for 'bye' and other methods if existed in object a.

--
Posted via http://www.ruby-forum.com/\.

uncutstone wu wrote:

What I want is something like this:

[...code...]

Then I can get this kind of result:

call method hello of class HelloBye
hello
return from method hello of class HelloBye

And similar thing for 'bye' and other methods if existed in object a.

Some food for thoughts:

···

------------------------------------------------------------
def intercept obj
  meth = obj.methods - %w{__send__ __id__}
  klass, name = class << obj; self; end, obj.class.name
  meth.each do |m|
    klass.module_eval %[
    def #{m} *a,&b
      puts 'in #{name}##{m}'
      super
      puts 'out #{name}##{m}'
    end]
  end
  obj
end

class HelloBye
  def hello
    puts "hello"
  end
  def bye
    puts "byebye"
  end
end

a = HelloBye.new
intercept a #add an intercptor to a
a.hello
a.bye
------------------------------------------------------------

in HelloBye#hello
hello
out HelloBye#hello
in HelloBye#bye
byebye
out HelloBye#bye

method missing would also be an option of course, but wrapping an
object into another one has several drawbacks (e.g. dup and friends
don't work as expected anymore)

cheers

Simon

I once hacked something quite complex together that supports multiple
hooks and threads. The code is on the Wiki
http://wiki.rubygarden.org/Ruby/page/show/MethodHooks

Kind regards

robert

···

2006/5/21, uncutstone wu <uncutstone@sina.com>:

Then I can get this kind of result:

call method hello of class HelloBye
hello
return from method hello of class HelloBye

--
Have a look: Robert K. | Flickr

Robert Klemme wrote:

Then I can get this kind of result:

call method hello of class HelloBye
hello
return from method hello of class HelloBye

I once hacked something quite complex together that supports multiple
hooks and threads. The code is on the Wiki
http://wiki.rubygarden.org/Ruby/page/show/MethodHooks

Kind regards

robert

I did something similar:

class Object

  @@methods = {}
  @@pre = {}
  @@post = {}

  def self.new_method(m)
    define_method(m) do |*args|
      call_pres m, args
      result = @@methods[m].bind(self).call *args
      call_posts m, args
      result
    end
  end

  def self.wrap( method, wrapping_method )
    @@methods[method] ||= instance_method(method).clone
    define_method(method) do |*args|
      send wrapping_method, @@methods[method].bind(self), *args
    end
  end

  def self.pre( method, pre_method )
    @@methods[method] ||= instance_method(method).clone
    (@@pre[method] ||= ) << pre_method
    new_method method
  end

  def self.post( method, post_method )
    @@methods[method] ||= instance_method(method).clone
    (@@post[method] ||= ) << post_method
    new_method method
  end

  def call_pres( method, arguments )
    return unless @@pre[method]
    @@pre[method].each do |pre|
      send pre, *arguments
    end
  end

  def call_posts( method, arguments )
    return unless @@post[method]
    @@post[method].each do |post|
      send post, *arguments
    end
  end

end

You could hookup before and after methods:

class Test

  def add(one, two)
    result = one + two
    puts "#{one} + #{two} = #{result}"
    result
  end

  pre :add, :pre_add

  def pre_add one, two
    puts "adding #{one} and #{two}"
  end

  post :add, :post_add

  def post_add( one, two )
    puts "done adding #{one} and #{two}"
  end

end

Test.new.add 1, 2
# results in:
# adding 1 and 2
# 1 + 2 = 3
# done adding 1 and 2
# => 3

You can also wrap methods:

class Test

  def subtract( one, two )
    result = one - two
    puts "#{one} - #{two} = #{result}"
    result
  end

  wrap :subtract, :wrap_subtract

  def wrap_subtract( subtracter, one, two )
    puts "about to subtract #{one} and #{two}..."
    subtracter.call one, two
    puts "done..."
  end

end

Test.new.subtract 3, 2
# results in
# about to subtract 3 and 2...
# 3 - 2 = 1
# done...
# => nil

And off course hooking up on hooks places them inside the method chain.

···

2006/5/21, uncutstone wu <uncutstone@sina.com>:

--
Posted via http://www.ruby-forum.com/\.

Simen wrote:

Robert Klemme wrote:

Then I can get this kind of result:

call method hello of class HelloBye
hello
return from method hello of class HelloBye

I once hacked something quite complex together that supports multiple
hooks and threads. The code is on the Wiki
http://wiki.rubygarden.org/Ruby/page/show/MethodHooks

Kind regards

robert

I did something similar:
...

I should add, though, that it acts funny when you redefine hookups for
other classes. It obviously needs to be extended to work in practice.
Consider it an idea.

···

2006/5/21, uncutstone wu <uncutstone@sina.com>:

--
Posted via http://www.ruby-forum.com/\.

Same with my code - I never used it in production. But then again it's
probably not worth the effort to enhance it as it's planned to have
method hooking in one of the next major Ruby releases.

Kind regards

robert

···

2006/5/21, Simen <toalett@gmail.com>:

I should add, though, that it acts funny when you redefine hookups for
other classes. It obviously needs to be extended to work in practice.
Consider it an idea.

--
Have a look: Robert K. | Flickr