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

http://DevMentor.org

Do Good! - Share Freely

Rajinder Y. 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.

On Tue, Dec 15, 2009 at 9:32 AM, Rajinder Y. [email protected]
wrote:

class_eval “def greet; puts ‘hello’; end”
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@:51(irb)
irb(main):052:0> C.add_method(:name=) {|value| @name = value}
=> #Proc:0xb7cb3bf0@:52(irb)
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.

Brian C. wrote:

Person = Class.new # superclass is Object

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

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@:51(irb)
irb(main):052:0> C.add_method(:name=) {|value| @name = value}
=> #Proc:0xb7cb3bf0@:52(irb)
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)

Brian C. wrote:

=> 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 Y.

http://DevMentor.org

Do Good! - Share Freely

Jesús Gabriel y Galán wrote:

def self.extend_me
puts Person.name
directly or with const_set.
irb(main):051:0> C.add_method(:name) {@name}
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 Y.

http://DevMentor.org

Do Good! - Share Freely