# How to intercept all function calls of a object?

**URL:** <https://rubytalk.org/t/how-to-intercept-all-function-calls-of-a-object/27606>\
**Category:** ruby-talk\
**Created:** [21 May 2006 07:25 UTC](https://rubytalk.org/t/how-to-intercept-all-function-calls-of-a-object/27606 "2006-05-21T07:25:47Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Uncutstone\_Wu](https://avatars.discourse-cdn.com/v4/letter/u/82dd89/32.png) [@Uncutstone\_Wu](https://rubytalk.org/u/Uncutstone_Wu)\
**Post date:** [21 May 2006 07:25 UTC](https://rubytalk.org/t/how-to-intercept-all-function-calls-of-a-object/27606/1 "2006-05-21T07:25:47Z")

</div>

What I want is something like this:

class HelloBye  
&nbsp;&nbsp;def hello  
&nbsp;&nbsp;&nbsp;&nbsp;puts "hello"  
&nbsp;&nbsp;end  
&nbsp;&nbsp;def bye  
&nbsp;&nbsp;&nbsp;&nbsp;puts "byebye"  
&nbsp;&nbsp;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/](http://www.ruby-forum.com/).

---

<div class="post-metadata">

**Author:** ![Joey](https://avatars.discourse-cdn.com/v4/letter/j/f14d63/32.png) [@Joey](https://rubytalk.org/u/Joey)\
**Post date:** [21 May 2006 07:34 UTC](https://rubytalk.org/t/how-to-intercept-all-function-calls-of-a-object/27606/2 "2006-05-21T07:34:45Z")

</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)

> **···**
>
> On 5/21/06, uncutstone wu \<uncutstone@sina.com\> wrote:
> 
> > What I want is something like this:
> > 
> > class HelloBye  
> > &nbsp;&nbsp;def hello  
> > &nbsp;&nbsp;&nbsp;&nbsp;puts "hello"  
> > &nbsp;&nbsp;end  
> > &nbsp;&nbsp;def bye  
> > &nbsp;&nbsp;&nbsp;&nbsp;puts "byebye"  
> > &nbsp;&nbsp;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/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Simon\_Kroger](https://avatars.discourse-cdn.com/v4/letter/s/49beb7/32.png) [@Simon\_Kroger](https://rubytalk.org/u/Simon_Kroger)\
**Post date:** [21 May 2006 10:56 UTC](https://rubytalk.org/t/how-to-intercept-all-function-calls-of-a-object/27606/3 "2006-05-21T10:56:52Z")

</div>

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  
> &nbsp;&nbsp;meth = obj.methods - %w{\_\_send\_\_ \_\_id\_\_}  
> &nbsp;&nbsp;klass, name = class \<\< obj; self; end, obj.class.name  
> &nbsp;&nbsp;meth.each do |m|  
> &nbsp;&nbsp;&nbsp;&nbsp;klass.module\_eval %[  
> &nbsp;&nbsp;&nbsp;&nbsp;def #{m} \*a,&b  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts 'in #{name}##{m}'  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts 'out #{name}##{m}'  
> &nbsp;&nbsp;&nbsp;&nbsp;end]  
> &nbsp;&nbsp;end  
> &nbsp;&nbsp;obj  
> end
> 
> class HelloBye  
> &nbsp;&nbsp;def hello  
> &nbsp;&nbsp;&nbsp;&nbsp;puts "hello"  
> &nbsp;&nbsp;end  
> &nbsp;&nbsp;def bye  
> &nbsp;&nbsp;&nbsp;&nbsp;puts "byebye"  
> &nbsp;&nbsp;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:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [21 May 2006 12:35 UTC](https://rubytalk.org/t/how-to-intercept-all-function-calls-of-a-object/27606/4 "2006-05-21T12:35:57Z")

</div>

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

> **···**
>
> 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](http://www.flickr.com/photos/fussel-foto/)

---

<div class="post-metadata">

**Author:** ![Guest20](https://avatars.discourse-cdn.com/v4/letter/g/ee7513/32.png) [@Guest20](https://rubytalk.org/u/Guest20)\
**Post date:** [21 May 2006 15:06 UTC](https://rubytalk.org/t/how-to-intercept-all-function-calls-of-a-object/27606/5 "2006-05-21T15:06:59Z")

</div>

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](http://wiki.rubygarden.org/Ruby/page/show/MethodHooks)
> 
> Kind regards
> 
> robert

I did something similar:

class Object

&nbsp;&nbsp;@@methods = {}  
&nbsp;&nbsp;@@pre = {}  
&nbsp;&nbsp;@@post = {}

&nbsp;&nbsp;def self.new\_method(m)  
&nbsp;&nbsp;&nbsp;&nbsp;define\_method(m) do |\*args|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call\_pres m, args  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = @@methods[m].bind(self).call \*args  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call\_posts m, args  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end

&nbsp;&nbsp;def self.wrap( method, wrapping\_method )  
&nbsp;&nbsp;&nbsp;&nbsp;@@methods[method] ||= instance\_method(method).clone  
&nbsp;&nbsp;&nbsp;&nbsp;define\_method(method) do |\*args|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send wrapping\_method, @@methods[method].bind(self), \*args  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end

&nbsp;&nbsp;def self.pre( method, pre\_method )  
&nbsp;&nbsp;&nbsp;&nbsp;@@methods[method] ||= instance\_method(method).clone  
&nbsp;&nbsp;&nbsp;&nbsp;(@@pre[method] ||= ) \<\< pre\_method  
&nbsp;&nbsp;&nbsp;&nbsp;new\_method method  
&nbsp;&nbsp;end

&nbsp;&nbsp;def self.post( method, post\_method )  
&nbsp;&nbsp;&nbsp;&nbsp;@@methods[method] ||= instance\_method(method).clone  
&nbsp;&nbsp;&nbsp;&nbsp;(@@post[method] ||= ) \<\< post\_method  
&nbsp;&nbsp;&nbsp;&nbsp;new\_method method  
&nbsp;&nbsp;end

&nbsp;&nbsp;def call\_pres( method, arguments )  
&nbsp;&nbsp;&nbsp;&nbsp;return unless @@pre[method]  
&nbsp;&nbsp;&nbsp;&nbsp;@@pre[method].each do |pre|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send pre, \*arguments  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end

&nbsp;&nbsp;def call\_posts( method, arguments )  
&nbsp;&nbsp;&nbsp;&nbsp;return unless @@post[method]  
&nbsp;&nbsp;&nbsp;&nbsp;@@post[method].each do |post|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send post, \*arguments  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end

end

You could hookup before and after methods:

class Test

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

&nbsp;&nbsp;pre :add, :pre\_add

&nbsp;&nbsp;def pre\_add one, two  
&nbsp;&nbsp;&nbsp;&nbsp;puts "adding #{one} and #{two}"  
&nbsp;&nbsp;end

&nbsp;&nbsp;post :add, :post\_add

&nbsp;&nbsp;def post\_add( one, two )  
&nbsp;&nbsp;&nbsp;&nbsp;puts "done adding #{one} and #{two}"  
&nbsp;&nbsp;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

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

&nbsp;&nbsp;wrap :subtract, :wrap\_subtract

&nbsp;&nbsp;def wrap\_subtract( subtracter, one, two )  
&nbsp;&nbsp;&nbsp;&nbsp;puts "about to subtract #{one} and #{two}..."  
&nbsp;&nbsp;&nbsp;&nbsp;subtracter.call one, two  
&nbsp;&nbsp;&nbsp;&nbsp;puts "done..."  
&nbsp;&nbsp;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/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Guest20](https://avatars.discourse-cdn.com/v4/letter/g/ee7513/32.png) [@Guest20](https://rubytalk.org/u/Guest20)\
**Post date:** [21 May 2006 15:10 UTC](https://rubytalk.org/t/how-to-intercept-all-function-calls-of-a-object/27606/6 "2006-05-21T15:10:05Z")

</div>

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](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/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [21 May 2006 15:45 UTC](https://rubytalk.org/t/how-to-intercept-all-function-calls-of-a-object/27606/7 "2006-05-21T15:45:35Z")

</div>

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](http://www.flickr.com/photos/fussel-foto/)
