# Puzzle...cleaner way to redefine a method?

**URL:** <https://www.ruby-forum.com/t/puzzle-cleaner-way-to-redefine-a-method/117743>\
**Category:** Ruby\
**Created:** [October 19, 2007, 9:08pm UTC](https://www.ruby-forum.com/t/puzzle-cleaner-way-to-redefine-a-method/117743 "2007-10-19T21:08:20Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![blackie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8491ac/32.png) [@blackie](https://www.ruby-forum.com/u/blackie)\
**Post date:** [October 19, 2007, 9:08pm UTC](https://www.ruby-forum.com/t/puzzle-cleaner-way-to-redefine-a-method/117743/1 "2007-10-19T21:08:20Z")

</div>

Here’s a puzzle. There must be a cleaner way to do this.

I would like to have users of this class be able to call “set\_wrapper”  
and define pre and post behavior on the “working” method. The only  
simple way I’ve found is evaling a string the redefines “working”.  
Searching threads on instance and class\_eval tends to turn up an oil  
slick of arguments and misinformation. Help is apprecaited!

```auto
class Thing
  def set_wrapper(string)
    eval(string)
  end

  def working
    yield
  end

  def main
    working do
      p 'test'
    end
  end
end

a = Thing.new

a.main

a.set_wrapper("def working; p 'pre'; yield; p 'post'; end")

a.main
```

---

<div class="post-metadata">

**Author:** ![blackie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8491ac/32.png) [@blackie](https://www.ruby-forum.com/u/blackie)\
**Post date:** [October 19, 2007, 9:20pm UTC](https://www.ruby-forum.com/t/puzzle-cleaner-way-to-redefine-a-method/117743/2 "2007-10-19T21:20:04Z")

</div>

Blackie wrote:

> def set\_wrapper(string)  
> end  
> end  
> end
> 
> a = Thing.new
> 
> a.main
> 
> a.set\_wrapper(“def working; p ‘pre’; yield; p ‘post’; end”)
> 
> a.main

Try this (untested):

class Thing  
def add\_pre\_call(&prc)  
(@pre\_procs ||= []) \<\< prc  
end  
def add\_post\_call(&prc)  
(@post\_procs ||= []) \<\< prc  
end  
def working  
@pre\_procs.each {|p| p.call} if @pre\_procs  
yield  
@post\_procs.each{|p| p.call} if @post\_procs  
end  
end

a = Thing.new  
a.main  
a.add\_pre\_call { p ‘pre’ }  
a.add\_post\_call { p ‘post’ }  
a.main

---

<div class="post-metadata">

**Author:** ![blackie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8491ac/32.png) [@blackie](https://www.ruby-forum.com/u/blackie)\
**Post date:** [October 19, 2007, 11:59pm UTC](https://www.ruby-forum.com/t/puzzle-cleaner-way-to-redefine-a-method/117743/3 "2007-10-19T23:59:12Z")

</div>

I have to go to dinner now, but here’s something quick you should  
look at:

Aquarium, for aspect oriented programming  
[http://aquarium.rubyforge.org/](http://aquarium.rubyforge.org/)

Aspect Oriented Programming is definitely what your looking for 🙂

--------------------------------------------|  
If you’re not living on the edge,  
then you’re just wasting space.

---

<div class="post-metadata">

**Author:** ![blackie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8491ac/32.png) [@blackie](https://www.ruby-forum.com/u/blackie)\
**Post date:** [October 20, 2007, 12:39am UTC](https://www.ruby-forum.com/t/puzzle-cleaner-way-to-redefine-a-method/117743/4 "2007-10-20T00:39:37Z")

</div>

Hi,

maybe this is slightly cleaner in interface (in that you pass in pre and  
post procs rather than a string) but you still need to use eval  
somewhere  
(in Ruby 1.8 anyway) to be able to use ‘def’ so you can pass on the  
block.  
Shows the principle anyway.

module Wrapper  
def wrap(meth, pre\_block, post\_block)  
m = Module.new do  
define\_method “pre\_#{meth}”, &pre\_block  
define\_method “post\_#{meth}”, &post\_block  
eval %[  
def #{meth}(\*a, &b)  
pre\_#{meth}  
rv = super(\*a, &b)  
post\_#{meth}  
rv  
end  
]  
end  
self.extend m  
end  
end

class Thing  
include Wrapper

def working  
yield  
end

def main  
working do  
p ‘test’  
end  
end  
end

a = Thing.new  
a.main  
a.wrap :working, proc { p ‘pre’ }, proc { p ‘post’ }  
a.main  
**END**  
“test”  
“pre”  
“test”  
“post”

If you don’t want to include Wrapper in the class, you could use  
a.extend(Wrapper)  
instead.

Regards,  
Sean

---

<div class="post-metadata">

**Author:** ![blackie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8491ac/32.png) [@blackie](https://www.ruby-forum.com/u/blackie)\
**Post date:** [October 20, 2007, 1:01am UTC](https://www.ruby-forum.com/t/puzzle-cleaner-way-to-redefine-a-method/117743/5 "2007-10-20T01:01:15Z")

</div>

Whoops - apologies for top posting
