Meta-programming

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 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 :slight_smile: 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/\.

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.

···

On Tue, Dec 15, 2009 at 9:32 AM, Rajinder Yadav <devguy.ca@gmail.com> 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?

Jesús Gabriel y Galán wrote:

···

On Tue, Dec 15, 2009 at 9:32 AM, Rajinder Yadav <devguy.ca@gmail.com> 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

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

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:

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 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:
rails/activerecord/lib/active_record/attribute_methods/write.rb at main · rails/rails · GitHub

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