Forum: Ruby Metaprogramming and module question

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Pedro D. (Guest)
on 2007-03-06 23:24
(Received via mailing list)
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-cont...

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
Gavin K. (Guest)
on 2007-03-06 23:36
(Received via mailing list)
On Mar 6, 2:24 pm, "Pedro Del G." <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 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!
Pedro D. (Guest)
on 2007-03-06 23:58
(Received via mailing list)
> See 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
Rick D. (Guest)
on 2007-03-06 23:59
(Received via mailing list)
On 3/6/07, Phrogz <removed_email_address@domain.invalid> wrote:
>
> See 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/
This topic is locked and can not be replied to.