# Metaprogramming and module question

**URL:** <https://www.ruby-forum.com/t/metaprogramming-and-module-question/87919>\
**Category:** Ruby\
**Created:** [March 6, 2007, 10:24pm UTC](https://www.ruby-forum.com/t/metaprogramming-and-module-question/87919 "2007-03-06T22:24:34Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![pedro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/919ad9/32.png) [@pedro](https://www.ruby-forum.com/u/pedro)\
**Post date:** [March 6, 2007, 10:24pm UTC](https://www.ruby-forum.com/t/metaprogramming-and-module-question/87919/1 "2007-03-06T22:24:34Z")

</div>

Hi

Yesterday , i’d made an example for fun, after read [1]. that let me  
introduce pre o post behavior to an method with this easy sintax

class Foo  
pre(:my\_method) { #some\_code}  
end

but i ve a proble when i try to move the pre and post method to a  
module. Can anyone explainme why the pre methods is undefined in the  
class ?

thanks in advance.

[1] :  
[http://split-s.blogspot.com/2006/02/design-by-contract-for-ruby.html](http://split-s.blogspot.com/2006/02/design-by-contract-for-ruby.html)

## My code :

Pre and Post method implemented in Song class

class Song  
attr\_accessor :title  
def play  
puts “#{@title}”  
end  
end

class Song  
def self.pre (name\_method, &condition)  
old\_method = instance\_method(name\_method)

```
define_method(name_method) { |*args|
   condition.call
   old_method.bind(self).call(*args)
}

```

end

def self.post (name\_method, &condition)  
old\_method = instance\_method(name\_method)

```
define_method(name_method) { |*args|
   condition.call
}

```

end  
end

class Song  
pre (:play ) { puts “Playing …” }  
end

song = Song.new  
song.title= “Hola song”  
song.play

* * *

Als module implementation : not work undefined method `pre’ for  
Song:Class (NoMethodError)

class Song  
attr\_accessor :title  
def play  
puts “#{@title}”  
end  
end

module MetaTest

def self.included(mod)  
puts “and now MetaTest has been used by #{mod.inspect}…”  
end

def self.pre (name\_method, &condition)  
old\_method = instance\_method(name\_method)

```
define_method(name_method) { |*args|
   condition.call
   old_method.bind(self).call(*args)
}

```

end

def self.post (name\_method, &condition)  
old\_method = instance\_method(name\_method)

```
define_method(name_method) { |*args|
   condition.call
}

```

end  
end

class Song  
include MetaTest  
end

class Song  
pre (:play ) { puts “Playing …” }  
end

## song = Song.new song.title= “Hola caracola” song.play

* * *

Pedro Del G.

Email : removed\_email\_address@domain.invalid

---

<div class="post-metadata">

**Author:** ![pedro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/919ad9/32.png) [@pedro](https://www.ruby-forum.com/u/pedro)\
**Post date:** [March 6, 2007, 10:36pm UTC](https://www.ruby-forum.com/t/metaprogramming-and-module-question/87919/2 "2007-03-06T22:36:35Z")

</div>

On Mar 6, 2:24 pm, “Pedro Del G.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> but i ve a proble when i try to move the pre and post method to a  
> module. Can anyone explainme why the pre methods is undefined in the  
> class ?  
> [snip]

Including a Module into a Class only links in the ‘instance’ methods  
of that module as instance methods of the class. Module methods (def  
self.foo) are not inherited as ‘class’ methods.

See [http://phrogz.net/RubyLibs/RubyMethodLookupFlow.png](http://phrogz.net/RubyLibs/RubyMethodLookupFlow.png) for a visual  
explanation.

The easiest thing to do is make those methods instance methods of the  
module, and extend your Song class with them:

module Foo  
def bar; puts “#bar called on #{self}”; end  
end

class Cat  
include Foo  
end

class Dog  
extend Foo  
end

Cat.bar rescue puts “No Cat.bar method!”  
Cat.new.bar rescue puts “No Cat#bar method!”  
Dog.bar rescue puts “No Dog.bar method!”  
Dog.new.bar rescue puts “No Dog#bar method!”

#=\> No Cat.bar method!  
#=\> #bar called on #Cat:0x28347b0  
#=\> #bar called on Dog  
#=\> No Dog#bar method!

---

<div class="post-metadata">

**Author:** ![pedro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/919ad9/32.png) [@pedro](https://www.ruby-forum.com/u/pedro)\
**Post date:** [March 6, 2007, 10:58pm UTC](https://www.ruby-forum.com/t/metaprogramming-and-module-question/87919/3 "2007-03-06T22:58:38Z")

</div>

> See [http://phrogz.net/RubyLibs/RubyMethodLookupFlow.png](http://phrogz.net/RubyLibs/RubyMethodLookupFlow.png) for a visual  
> explanation.

Good, i think i get it. Good example

## –

Pedro Del G.

Email : removed\_email\_address@domain.invalid

---

<div class="post-metadata">

**Author:** ![pedro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/919ad9/32.png) [@pedro](https://www.ruby-forum.com/u/pedro)\
**Post date:** [March 6, 2007, 10:59pm UTC](https://www.ruby-forum.com/t/metaprogramming-and-module-question/87919/4 "2007-03-06T22:59:38Z")

</div>

On 3/6/07, Phrogz [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> See [http://phrogz.net/RubyLibs/RubyMethodLookupFlow.png](http://phrogz.net/RubyLibs/RubyMethodLookupFlow.png) for a visual  
> explanation.
> 
> The easiest thing to do is make those methods instance methods of the  
> module, and extend your Song class with them

And a good way to do this automatically and make including the  
MetaTest module do what the OP expects is something like:

module MetaTest

def self.included(mod)  
puts “and now MetaTest has been used by #{mod.inspect}…”  
mod.extend(ClassMethods)  
end

module ClassMethods

```
def pre (name_method, &condition)
  old_method = instance_method(name_method)

  define_method(name_method) { |*args|

```

condition.call  
old\_method.bind(self).call(\*args)  
}  
end

```
def post (name_method, &condition)
  old_method = instance_method(name_method)

  define_method(name_method) { |*args|

```

condition.call  
}  
end  
end  
end

–  
Rick DeNatale

My blog on Ruby  
[http://talklikeaduck.denhaven2.com/](http://talklikeaduck.denhaven2.com/)
