meta-programming

Discussion in 'Ruby' started by Rajinder Yadav, Dec 15, 2009.

  1. I am just starting to expand my Ruby knowledge into the area of
    meta-programming.

    I want to be able to create a class dynamically. Lets call it, class
    Person, and then I want to add methods to it dynamically.

    From a static point I have managed to compile the following example:

    class Person
    def self.extend_me
    class_eval "def greet; puts 'hello'; end"
    instance_eval "def name; puts 'Person'; end"
    end
    end

    Person.extend_me

    Person.respond_to? :greet
    Person.respond_to? :name

    puts Person.name
    p = Person.new
    puts p.greet


    How would I declared a, 'class Person' dynamically and then add methods
    and attributes to it? Can someone point me to good documentation on this
    or show me some simple code example?

    --
    Kind Regards,
    Rajinder Yadav

    http://DevMentor.org

    Do Good! - Share Freely
     
    Rajinder Yadav, Dec 15, 2009
    #1
    1. Advertising

  2. Rajinder Yadav wrote:
    > How would I declared a, 'class Person' dynamically


    Option 1: since you're using string eval already, you could just do the
    same.

    eval "class Person; end"

    Option 2:

    Person = Class.new # superclass is Object
    Person = Class.new(Mammal) # superclass is Mammal

    I find this isn't often done in practice though. A program which doesn't
    know in advance which classes it has can be a bit too dynamic :) You
    would probably register your classes somewhere to be able to find them.
    In a Hash is one option; under a Module is another, so you can use

    MyModule.constants

    to find them all.

    You can make your classes anonymous if you don't bind them to a
    constant:

    my_klass = Class.new

    > and then add methods and attributes to it?


    As you've done before, using string eval, is one way.

    Another way:

    Person.class_eval { define_method:)greet) { puts "Hello" } }

    This means that the method is a closure, and can access variables
    outside (unlike 'def' which starts a fresh scope), and this can be
    useful sometimes.

    Another way: put the method(s) of interest in module(s), then include
    the relevant ones.

    Person.class_eval { include Greeter }

    ActiveRecord is a plentiful source of examples.
    --
    Posted via http://www.ruby-forum.com/.
     
    Brian Candler, Dec 15, 2009
    #2
    1. Advertising

  3. On Tue, Dec 15, 2009 at 9:32 AM, Rajinder Yadav <> wrote=
    :
    > I am just starting to expand my Ruby knowledge into the area of
    > meta-programming.
    >
    > I want to be able to create a class dynamically. Lets call it, class Pers=

    on,
    > and then I want to add methods to it dynamically.
    >
    > From a static point I have managed to compile the following example:
    >
    > class Person
    > =A0 def self.extend_me
    > =A0 class_eval "def greet; puts 'hello'; end"
    > =A0 instance_eval "def name; puts 'Person'; end"
    > =A0 end
    > end
    >
    > Person.extend_me
    >
    > Person.respond_to? :greet
    > Person.respond_to? :name
    >
    > puts Person.name
    > p =3D Person.new
    > puts p.greet
    >
    >
    > How would I declared a, 'class Person' dynamically and then add methods a=

    nd
    > attributes to it? Can someone point me to good documentation on this or s=

    how
    > me some simple code example?


    If you want to define the class dynamically, take a look at Class.new.
    This creates an anonymous class that you can assign to a constant
    directly or with const_set.
    To define methods I would use define_method. Adding attributes is done
    adding methods that set and get the attributes:

    irb(main):042:0> C =3D Class.new do
    irb(main):043:1* def self.add_method(name, &blk)
    irb(main):044:2> define_method(name, &blk)
    irb(main):045:2> end
    irb(main):046:1> end
    =3D> C

    irb(main):051:0> C.add_method:)name) {@name}
    =3D> #<Proc:0xb7cb9de8@(irb):51>
    irb(main):052:0> C.add_method:)name=3D) {|value| @name =3D value}
    =3D> #<Proc:0xb7cb3bf0@(irb):52>
    irb(main):053:0> c =3D C.new
    =3D> #<C:0xb7cb16d4>
    irb(main):054:0> c.name=3D3
    =3D> 3
    irb(main):055:0> c.name
    =3D> 3

    Hope this helps,

    Jesus.
     
    Jesús Gabriel y Galán, Dec 15, 2009
    #3
  4. Jesús Gabriel y Galán wrote:
    > On Tue, Dec 15, 2009 at 9:32 AM, Rajinder Yadav <> wrote:
    >> I am just starting to expand my Ruby knowledge into the area of
    >> meta-programming.
    >>
    >> I want to be able to create a class dynamically. Lets call it, class Person,
    >> and then I want to add methods to it dynamically.
    >>
    >> From a static point I have managed to compile the following example:
    >>
    >> class Person
    >> def self.extend_me
    >> class_eval "def greet; puts 'hello'; end"
    >> instance_eval "def name; puts 'Person'; end"
    >> end
    >> end
    >>
    >> Person.extend_me
    >>
    >> Person.respond_to? :greet
    >> Person.respond_to? :name
    >>
    >> puts Person.name
    >> p = Person.new
    >> puts p.greet
    >>
    >>
    >> How would I declared a, 'class Person' dynamically and then add methods and
    >> attributes to it? Can someone point me to good documentation on this or show
    >> me some simple code example?

    >
    > If you want to define the class dynamically, take a look at Class.new.
    > This creates an anonymous class that you can assign to a constant
    > directly or with const_set.
    > To define methods I would use define_method. Adding attributes is done
    > adding methods that set and get the attributes:
    >
    > irb(main):042:0> C = Class.new do
    > irb(main):043:1* def self.add_method(name, &blk)
    > irb(main):044:2> define_method(name, &blk)
    > irb(main):045:2> end
    > irb(main):046:1> end
    > => C
    >
    > irb(main):051:0> C.add_method:)name) {@name}
    > => #<Proc:0xb7cb9de8@(irb):51>
    > irb(main):052:0> C.add_method:)name=) {|value| @name = value}
    > => #<Proc:0xb7cb3bf0@(irb):52>
    > irb(main):053:0> c = C.new
    > => #<C:0xb7cb16d4>
    > irb(main):054:0> c.name=3
    > => 3
    > irb(main):055:0> c.name
    > => 3
    >
    > Hope this helps,
    >
    > Jesus.
    >
    >


    Hi Jesus, yes it does help and you answered the next question I was
    about to ask about adding variables after reading Brian's reply.

    --
    Kind Regards,
    Rajinder Yadav

    http://DevMentor.org

    Do Good! - Share Freely
     
    Rajinder Yadav, Dec 15, 2009
    #4
  5. Brian Candler wrote:
    > Rajinder Yadav wrote:
    >> How would I declared a, 'class Person' dynamically

    >
    > Option 1: since you're using string eval already, you could just do the
    > same.
    >
    > eval "class Person; end"
    >
    > Option 2:
    >
    > Person = Class.new # superclass is Object
    > Person = Class.new(Mammal) # superclass is Mammal
    >
    > I find this isn't often done in practice though. A program which doesn't
    > know in advance which classes it has can be a bit too dynamic :) You
    > would probably register your classes somewhere to be able to find them.
    > In a Hash is one option; under a Module is another, so you can use
    >
    > MyModule.constants
    >
    > to find them all.
    >
    > You can make your classes anonymous if you don't bind them to a
    > constant:
    >
    > my_klass = Class.new
    >
    >> and then add methods and attributes to it?

    >
    > As you've done before, using string eval, is one way.
    >
    > Another way:
    >
    > Person.class_eval { define_method:)greet) { puts "Hello" } }
    >
    > This means that the method is a closure, and can access variables
    > outside (unlike 'def' which starts a fresh scope), and this can be
    > useful sometimes.
    >
    > Another way: put the method(s) of interest in module(s), then include
    > the relevant ones.
    >
    > Person.class_eval { include Greeter }
    >
    > ActiveRecord is a plentiful source of examples.


    Hi Brian,

    thanks for the excellent examples and explanation =), I can't stop
    smiling about how beautiful and elegantly simple Ruby make things.

    --
    Kind Regards,
    Rajinder Yadav

    http://DevMentor.org

    Do Good! - Share Freely
     
    Rajinder Yadav, Dec 15, 2009
    #5
  6. Jesús Gabriel y Galán wrote:
    > irb(main):051:0> C.add_method:)name) {@name}
    > => #<Proc:0xb7cb9de8@(irb):51>
    > irb(main):052:0> C.add_method:)name=) {|value| @name = value}
    > => #<Proc:0xb7cb3bf0@(irb):52>
    > irb(main):053:0> c = C.new
    > => #<C:0xb7cb16d4>
    > irb(main):054:0> c.name=3
    > => 3
    > irb(main):055:0> c.name
    > => 3


    Of course, since 'name' is static here, you could just include a module.

    It gets more fun when the names of the accessors themselves are dynamic.
    At this point it really does make more sense to use string eval, rather
    than the alternative (instance_variable_get and instance_variable_set).

    Have a look at define_method_attribute= in the following:
    http://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_methods/write.rb

    Also see define_read_method in attribute_methods/read.rb, and
    method_missing in base.rb (this defines finder methods dynamically)
    --
    Posted via http://www.ruby-forum.com/.
     
    Brian Candler, Dec 15, 2009
    #6
  7. Brian Candler wrote:
    > Jesús Gabriel y Galán wrote:
    >> irb(main):051:0> C.add_method:)name) {@name}
    >> => #<Proc:0xb7cb9de8@(irb):51>
    >> irb(main):052:0> C.add_method:)name=) {|value| @name = value}
    >> => #<Proc:0xb7cb3bf0@(irb):52>
    >> irb(main):053:0> c = C.new
    >> => #<C:0xb7cb16d4>
    >> irb(main):054:0> c.name=3
    >> => 3
    >> irb(main):055:0> c.name
    >> => 3

    >
    > Of course, since 'name' is static here, you could just include a module.
    >
    > It gets more fun when the names of the accessors themselves are dynamic.
    > At this point it really does make more sense to use string eval, rather
    > than the alternative (instance_variable_get and instance_variable_set).
    >
    > Have a look at define_method_attribute= in the following:
    > http://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_methods/write.rb


    Thanks for pointing out the path to ActiveRecord, I haven't gotten use
    to browsing source code, this is really helpful!

    >
    > Also see define_read_method in attribute_methods/read.rb, and
    > method_missing in base.rb (this defines finder methods dynamically)


    cool I will do that =)


    --
    Kind Regards,
    Rajinder Yadav

    http://DevMentor.org

    Do Good! - Share Freely
     
    Rajinder Yadav, Dec 15, 2009
    #7
    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. Nym Pseudo

    META NAME and META HTTP-EQUIV

    Nym Pseudo, Sep 26, 2003, in forum: HTML
    Replies:
    1
    Views:
    563
    =?iso-8859-1?Q?brucie?=
    Sep 26, 2003
  2. Bruce Dickey

    Meta programming question

    Bruce Dickey, Sep 28, 2003, in forum: Python
    Replies:
    8
    Views:
    345
    Bruce Dickey
    Sep 29, 2003
  3. Duane Johnson

    Meta methods to govern meta data?

    Duane Johnson, Oct 25, 2005, in forum: Ruby
    Replies:
    6
    Views:
    245
    Adam Sanderson
    Oct 28, 2005
  4. Erik Veenstra

    Meta-Meta-Programming

    Erik Veenstra, Feb 7, 2006, in forum: Ruby
    Replies:
    29
    Views:
    395
    Erik Veenstra
    Feb 8, 2006
  5. Erik Veenstra

    Meta-Meta-Programming, revisited

    Erik Veenstra, Jul 21, 2006, in forum: Ruby
    Replies:
    21
    Views:
    444
    Erik Veenstra
    Jul 25, 2006
Loading...

Share This Page