Learning ruby - metaprogramming question [from poignant guide]

Discussion in 'Ruby' started by Luc Juggery, Oct 23, 2006.

  1. Luc Juggery

    Luc Juggery Guest

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

    Thanks a lot,
    Luc
     
    Luc Juggery, Oct 23, 2006
    #1
    1. Advertising

  2. Luc Juggery

    Guest

    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 |
    Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
    DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
    [1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
    [2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
     
    , Oct 23, 2006
    #2
    1. Advertising

  3. Luc Juggery

    Luc Juggery Guest

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

    Luc

    On 10/23/06, <> 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 |
    > Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
    > DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
    > [1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
    > [2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
    >
    >
     
    Luc Juggery, Oct 23, 2006
    #3
  4. Luc Juggery

    Luc Juggery Guest

    Hi David,

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

    Thanks a lot,

    Luc

    On 10/23/06, <> 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 |
    > Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
    > DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
    > [1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
    > [2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
    >
    >



    --
    @bientot,
    Luc
     
    Luc Juggery, Oct 23, 2006
    #4
  5. Luc Juggery

    Brian Neal Guest

    Re: Learning ruby - metaprogramming question

    Luc Juggery wrote:
    > Hi David,
    >
    > Do you know where I could find some interesting doc on this, something
    > like "Ruby Metaprogramming for "REAL" dummy" :) ?
    >
    > 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/.
     
    Brian Neal, Oct 24, 2006
    #5
  6. Luc Juggery

    Luc Juggery Guest

    Re: Learning ruby - metaprogramming question

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

    Luc

    On 10/24/06, Brian Neal <> 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" :) ?
    > >
    > > 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/.
    >
    >
     
    Luc Juggery, Oct 24, 2006
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. why the lucky stiff
    Replies:
    22
    Views:
    334
    Sean Russell
    Feb 20, 2004
  2. why the lucky stiff
    Replies:
    12
    Views:
    197
    Josef 'Jupp' SCHUGT
    Mar 4, 2004
  3. why the lucky stiff
    Replies:
    26
    Views:
    391
    Curt Hibbs
    Aug 22, 2004
  4. why the lucky stiff
    Replies:
    5
    Views:
    153
    why the lucky stiff
    Sep 22, 2004
  5. Richard Dale
    Replies:
    59
    Views:
    620
    Gavri Fernandez
    Feb 16, 2005
Loading...

Share This Page