# How to intercept all function calls of a object?

**URL:** <https://www.ruby-forum.com/t/how-to-intercept-all-function-calls-of-a-object/95071>\
**Category:** Ruby\
**Created:** [May 21, 2006, 9:25am UTC](https://www.ruby-forum.com/t/how-to-intercept-all-function-calls-of-a-object/95071 "2006-05-21T09:25:33Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![uncutstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/7993a0/32.png) [@uncutstone](https://www.ruby-forum.com/u/uncutstone)\
**Post date:** [May 21, 2006, 9:25am UTC](https://www.ruby-forum.com/t/how-to-intercept-all-function-calls-of-a-object/95071/1 "2006-05-21T09:25:33Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![uncutstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/7993a0/32.png) [@uncutstone](https://www.ruby-forum.com/u/uncutstone)\
**Post date:** [May 21, 2006, 9:36am UTC](https://www.ruby-forum.com/t/how-to-intercept-all-function-calls-of-a-object/95071/2 "2006-05-21T09:36:16Z")

</div>

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

j`ey  
[http://wwww.eachmapinject.com](http://wwww.eachmapinject.com)

---

<div class="post-metadata">

**Author:** ![uncutstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/7993a0/32.png) [@uncutstone](https://www.ruby-forum.com/u/uncutstone)\
**Post date:** [May 21, 2006, 12:59pm UTC](https://www.ruby-forum.com/t/how-to-intercept-all-function-calls-of-a-object/95071/3 "2006-05-21T12:59:22Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![uncutstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/7993a0/32.png) [@uncutstone](https://www.ruby-forum.com/u/uncutstone)\
**Post date:** [May 21, 2006, 2:36pm UTC](https://www.ruby-forum.com/t/how-to-intercept-all-function-calls-of-a-object/95071/4 "2006-05-21T14:36:57Z")

</div>

2006/5/21, uncutstone wu [removed\_email\_address@domain.invalid](mailto: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](http://wiki.rubygarden.org/Ruby/page/show/MethodHooks)

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![uncutstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/7993a0/32.png) [@uncutstone](https://www.ruby-forum.com/u/uncutstone)\
**Post date:** [May 21, 2006, 5:06pm UTC](https://www.ruby-forum.com/t/how-to-intercept-all-function-calls-of-a-object/95071/5 "2006-05-21T17:06:48Z")

</div>

Robert K. wrote:

> 2006/5/21, uncutstone wu [removed\_email\_address@domain.invalid](mailto: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](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.

---

<div class="post-metadata">

**Author:** ![uncutstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/7993a0/32.png) [@uncutstone](https://www.ruby-forum.com/u/uncutstone)\
**Post date:** [May 21, 2006, 5:46pm UTC](https://www.ruby-forum.com/t/how-to-intercept-all-function-calls-of-a-object/95071/6 "2006-05-21T17:46:51Z")

</div>

2006/5/21, Simen [removed\_email\_address@domain.invalid](mailto: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

---

<div class="post-metadata">

**Author:** ![uncutstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/7993a0/32.png) [@uncutstone](https://www.ruby-forum.com/u/uncutstone)\
**Post date:** [May 21, 2006, 5:09pm UTC](https://www.ruby-forum.com/t/how-to-intercept-all-function-calls-of-a-object/95071/7 "2006-05-21T17:09:59Z")

</div>

Simen wrote:

> Robert K. wrote:
> 
> > 2006/5/21, uncutstone wu [removed\_email\_address@domain.invalid](mailto: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](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.
