Learning ruby - metaprogramming question [from poignant guide]

Hello all,

I started learning Ruby not long ago and I'd really like to understand
concepts behind it.
Poignant Guide to ruby (http://poignantguide.net/ruby/chapter-6.html)
is a very usefull book for this.
Below example is extracted from this book and some things remain quite
magical for me.

···

----------------------------------------------------------------------
# The guts of life force within Dwemthy's Array
class Creature

   # Get a metaclass for this class
   def self.metaclass; class << self; self; end; end

   # Advanced metaprogramming code for nice, clean traits
   def self.traits( *arr )
     return @traits if arr.empty?

     # 1. Set up accessors for each variable
     attr_accessor *arr

     # 2. Add a new class method to for each trait.
     arr.each do |a|
       metaclass.instance_eval do
         define_method( a ) do |val|
           @traits ||= {}
           @traits[a] = val
         end
       end
     end

     # 3. For each monster, the `initialize' method
     # should use the default number for each trait.
     class_eval do
       define_method( :initialize ) do
         self.class.traits.each do |k,v|
           instance_variable_set("@#{k}", v)
         end
       end
     end

   end

---------------------
class Creature
   traits :life, :strength, :charisma, :weapon
end
---------------------

--------- generated Creature class ----------
class Creature

   # 1. set up reader and writer methods
   attr_accessor :life, :strength, :charisma, :weapon

   # 2. add new class methods to use in creature
   def self.life( val )
     @traits ||= {}
     @traits['life'] = val
   end

   def self.strength( val )
     @traits ||= {}
     @traits['strength'] = val
   end

   def self.charisma( val )
     @traits ||= {}
     @traits['charisma'] = val
   end

   def self.weapon( val )
     @traits ||= {}
     @traits['weapon'] = val
   end

   # 3. initialize sets the default points for
   # each trait
   def initialize
     self.class.traits.each do |k,v|
       instance_variable_set("@#{k}", v)
     end
   end

end
----------------------------------

The thing I do not really understand is the instance_eval and
class_eval in the self.traits method.
It seems that metaclass.instance_eval define_method create a Class
method in the Creature class. Creating a method in the singleton class
of a Class class always define a Class method? can the Singleton class
can also be used to create an instance method of Creature ? Is the way
presented in this example is what is commonly done to dynamically
define Class and instance method of a Class or are there any other
possible syntaxes ?

The self.traits method also define accessors methods: attr_accessor
*arr, how come this is not done within a define_method statement?

Well.... I hope I am not getting to confusing....
I would really appreciate your help as I'd really like to understand
how that's working.
I have already read several article on metaprogramming but some things
remain quite obscure to me :slight_smile:

Thanks a lot,
Luc

Hi --

The thing I do not really understand is the instance_eval and
class_eval in the self.traits method.
It seems that metaclass.instance_eval define_method create a Class
method in the Creature class. Creating a method in the singleton class
of a Class class always define a Class method?

Yes.

can the Singleton class can also be used to create an instance
method of Creature ?

No, those methods will not be visible to instances of Creature. Think
of it from the object's perspective. Every object has a method
look-up path, consisting of classes (including its singleton class)
and modules. The whole point of a singleton class is that it lies on
the look-up path of only one object. (There's one exception to this;
see below.) Therefore, if the class object Creature has a method in
its singleton class, and you do: c = Creature.new, c is a different
object from Creature, and the methods defined in Creature's singleton
class are not visible to it.

The exception is subclasses. If you subclass Creature, the new class
will be able to call Creature's singleton methods. It's a special
arrangement so that class methods can be inherited.

Is the way presented in this example is what is commonly done to
dynamically define Class and instance method of a Class or are there
any other possible syntaxes ?

You can use eval("def #{method_name}...") but it's fragile and
inadvisable.

The self.traits method also define accessors methods: attr_accessor
*arr, how come this is not done within a define_method statement?

The attr_* family of methods are basically wrappers around method
definitions. They're just shorter and more convenient, but the effect
is the same.

David

···

On Mon, 23 Oct 2006, Luc Juggery wrote:

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

Thanks a lot David,
that clarified a lot of things in my head :slight_smile:

Luc

···

On 10/23/06, dblack@wobblini.net <dblack@wobblini.net> wrote:

Hi --

On Mon, 23 Oct 2006, Luc Juggery wrote:

> The thing I do not really understand is the instance_eval and
> class_eval in the self.traits method.
> It seems that metaclass.instance_eval define_method create a Class
> method in the Creature class. Creating a method in the singleton class
> of a Class class always define a Class method?

Yes.

> can the Singleton class can also be used to create an instance
> method of Creature ?

No, those methods will not be visible to instances of Creature. Think
of it from the object's perspective. Every object has a method
look-up path, consisting of classes (including its singleton class)
and modules. The whole point of a singleton class is that it lies on
the look-up path of only one object. (There's one exception to this;
see below.) Therefore, if the class object Creature has a method in
its singleton class, and you do: c = Creature.new, c is a different
object from Creature, and the methods defined in Creature's singleton
class are not visible to it.

The exception is subclasses. If you subclass Creature, the new class
will be able to call Creature's singleton methods. It's a special
arrangement so that class methods can be inherited.

> Is the way presented in this example is what is commonly done to
> dynamically define Class and instance method of a Class or are there
> any other possible syntaxes ?

You can use eval("def #{method_name}...") but it's fragile and
inadvisable.

> The self.traits method also define accessors methods: attr_accessor
> *arr, how come this is not done within a define_method statement?

The attr_* family of methods are basically wrappers around method
definitions. They're just shorter and more convenient, but the effect
is the same.

David

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

Hi David,

Do you know where I could find some interesting doc on this, something
like "Ruby Metaprogramming for "REAL" dummy" :slight_smile: ?

Thanks a lot,

Luc

···

On 10/23/06, dblack@wobblini.net <dblack@wobblini.net> wrote:

Hi --

On Mon, 23 Oct 2006, Luc Juggery wrote:

> The thing I do not really understand is the instance_eval and
> class_eval in the self.traits method.
> It seems that metaclass.instance_eval define_method create a Class
> method in the Creature class. Creating a method in the singleton class
> of a Class class always define a Class method?

Yes.

> can the Singleton class can also be used to create an instance
> method of Creature ?

No, those methods will not be visible to instances of Creature. Think
of it from the object's perspective. Every object has a method
look-up path, consisting of classes (including its singleton class)
and modules. The whole point of a singleton class is that it lies on
the look-up path of only one object. (There's one exception to this;
see below.) Therefore, if the class object Creature has a method in
its singleton class, and you do: c = Creature.new, c is a different
object from Creature, and the methods defined in Creature's singleton
class are not visible to it.

The exception is subclasses. If you subclass Creature, the new class
will be able to call Creature's singleton methods. It's a special
arrangement so that class methods can be inherited.

> Is the way presented in this example is what is commonly done to
> dynamically define Class and instance method of a Class or are there
> any other possible syntaxes ?

You can use eval("def #{method_name}...") but it's fragile and
inadvisable.

> The self.traits method also define accessors methods: attr_accessor
> *arr, how come this is not done within a define_method statement?

The attr_* family of methods are basically wrappers around method
definitions. They're just shorter and more convenient, but the effect
is the same.

David

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

--
@bientot,
Luc

Luc Juggery wrote:

Hi David,

Do you know where I could find some interesting doc on this, something
like "Ruby Metaprogramming for "REAL" dummy" :slight_smile: ?

Thanks a lot,

Luc

Hi Luc,

I have found Chapter 13, Ruby Dynamics, in Ruby for Rails by David A.
Black, to be a great resource for getting your head around
metaprogramming. I got started with Hal Fulton's The Ruby Way, which I
recommend as well (the 2nd edition comes out shortly, I think).

cheers,

Brian

···

--
Posted via http://www.ruby-forum.com/\.

Thanks a lot Brian,
I'll check this !!!!!

Luc

···

On 10/24/06, Brian Neal <rbneal@alltel.net> wrote:

Luc Juggery wrote:
> Hi David,
>
> Do you know where I could find some interesting doc on this, something
> like "Ruby Metaprogramming for "REAL" dummy" :slight_smile: ?
>
> Thanks a lot,
>
> Luc

Hi Luc,

I have found Chapter 13, Ruby Dynamics, in Ruby for Rails by David A.
Black, to be a great resource for getting your head around
metaprogramming. I got started with Hal Fulton's The Ruby Way, which I
recommend as well (the 2nd edition comes out shortly, I think).

cheers,

Brian

--
Posted via http://www.ruby-forum.com/\.