Skip to content

Ruby Metaprograming

May 25, 2009

The very hot and controversial topic I would say in the dynamic language world is Metaprograming. I am saying controversial, coz if not used properly it may lead to too many magics happening all across your application and it might become a nightmare to maintain it.

Definition : “The phenomenon of a piece of code writing another piece of code on the fly at the run time is metaprograming”

Definition seems to be very simple, but the implementation is not that simple, at least for me 🙂

I am just introduced to this (metaprogramming) world. Learnt about it, because I started following Dave Thomas, the pragmatic programmer. I watched the seven videos presented by him about the ruby metaprgramming, mixins, bindings, lamda, procs etc. I would say the videos are worth watching and so is the book Agile web Development with Rails by him. It’s very well written !! I must say.

So, I got exited after the videos and the book and couldn’t stop myself from penning down a few words about, what made me mad the most :  “Metaprograming”.

To start with lemme ask you a question “Have you ever wondered how come the things like att_reader or attr_accessor allow you to access the attributes of a particular modle in Ruby?“. Although Ruby as a language says that all the attributes of a model are inherently private. For example, let’s say I have a class

class Vehicle
attr_accessor :no_of_wheels
def initialize(no_of_wheels)
@no_of_wheels = no_of_wheels
end
end

vehicle = Vehicle.new(2)
puts “The vehicle has #{vehicle.no_of_wheels} wheels”
vehicle.no_of_wheels = 4
puts “The vehicle has #{vehicle.no_of_wheels} wheels”

Running the above program gives you the following output :

The vehicle has 2 wheels
The vehicle has 4 wheels

How is that possible!!! If you are a JAVA guy (like me), you will definately start pulling your hair when this is working inspite of not finding any getter or setter defind for the same in the class hirarchy any where. What is this magic. How come I am not getting the error on accessing the private instance variable @no_of_wheels in the Vehicle class. Hmmm… thats insane.

Here is Metaprogramming coming to play. In fact, what just happened here is that as soon as you say attr_accessor :instance_var_name, ruby inserts the gettetrs and setters as two instance methods on the fly in the Vehicle class for you. so in effect that single line of code makes the ruby class look like this:

class Vehicle
def initialize(no_of_wheels)
@no_of_wheels = no_of_wheels
end
def no_of_wheels() #getter
@no_of_wheels
end
def no_of_wheels=(no_of_wheels) #setter
@no_of_wheels = no_of_wheels
end
end

So at the run time, the no_of_wheels is available on the instances of the Vehicle class!! This is metaprogramming!

Now this also doesn’t happen out of the thin air. The code for the attr_accessor is present in Module class an is implemented in such a way that it generates the getters and setters for you.

OK, let’s do this. Let’s write our own implementation of the attribuet accessors. You will find mostly this example lying around all over the internet and the reason is probably that this is the most simply explained and makes most sense as the ruby newbie’s, like me, already see a lot of’em lying around as soon as they start with this monster language.

So here we go. In this example I’ll try to open the class Module and add my attribute accessor to it. Let’s call our attribute accessor as : access_vars

class Module
def getter_setter_for(*vars)
vars.each do |var|
class_eval
“def #{var}”
“@#{var}”
“end”
“def #{m}=(val)”
“@#{m}” = val”
“end”
end
end
end

And now in our class we can just say :

class Vehicle
getter_setter_for :no_of_wheels
def initialize(no_of_wheels)
@no_of_wheels = no_of_wheels
end
end

And this will just get us the getters and setters inserted on the fly when the class is loaded.
So here, the one line of code getter_setter_for or attr_accessor can write code on the fly. This is what metaprograming is!!

That’s it.

Advertisements
No comments yet

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: