meta-programming

R

Rajinder Yadav

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
 
B

Brian Candler

Rajinder said:
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.
 
J

Jesús Gabriel y Galán

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.
 
R

Rajinder Yadav

Jesús Gabriel y Galán said:
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
 
R

Rajinder Yadav

Brian said:
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


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
 
B

Brian Candler

Jesús Gabriel y Galán said:
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)
 
R

Rajinder Yadav

Brian said:
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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

#meta 15
class_eval 4
deep cloning, how? 28
Meta-Meta-Programming 29
Enumerating and mixin. 7
Meta-Meta-Programming, revisited 21
Beginning meta-programming question 1
integers and floats 15

Members online

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top