How to intercept all function calls of a object?


#1

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.


#2

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

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


#3

uncutstone wu wrote:

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


#4

2006/5/21, uncutstone wu removed_email_address@domain.invalid:

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


#5

Robert K. wrote:

2006/5/21, uncutstone wu removed_email_address@domain.invalid:

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.


#6

2006/5/21, Simen removed_email_address@domain.invalid:

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.

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


#7

Simen wrote:

Robert K. wrote:

2006/5/21, uncutstone wu removed_email_address@domain.invalid:

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.