Rails style meta programming in Ruby – part 1

December 13, 2007 at 11:39 pm 1 comment

For a long time now, I have pondered and wondered about just how Rails does what it does – surely such wizardy is well outside my basic Ruby skills – well not any more thanks to this presentation by Dave Thomas.

He explains all the concepts you need to know, so that you too can do things in your own code like:


Class Users < ActiveRecord::Base
  set_table_name :unconventional_name
  has_many :friends
end

Dave, I am sure, explains it much better than me, but the video is an hour long, and I had to watch it twice, so here, hopefully is the 10 (or 20) minute summary.

Everything is a method

First things first – every method you call in Ruby is run by sending a message to an object – even at the top level when you wouldn’t have though so:


puts "hello, world!"

In the above code, puts is a method with is executed by sending a message to an object. Infact, no matter which method you call on any object in your code, it is always executed by sending a message to the same object, ‘self’.


puts self.to_s
puts self.class

prints


main
Object

So, at the top level, all messages are sent to an object contained in the variable self that is called ‘main’ and is of class Object.

When you type something like


  a = Array.new
  puts a.class

It prints ‘Array’, as the variable ‘a’ contains an instance of an Array object. The trick to remember here is that the ‘a.’ says, set the value of self to the object a, and then execute the method on self. This means that everytime you execute a method, it is always executed as a message passed to ‘self’, which will have been set to the correct object.

That is why this works:


class Foo
  def hello
    there          # a method call with no receiver?
    puts " there"
  end
  def there
    puts "hello"
  end
end

b = Foo.new
b.hello

When you are inside an instance method, executing another method without a class or object prefix invokes the method on the object self. Ruby arranges so that the value of self inside an instance method is the correct thing – ie set to the instance of the object the original method was invoked on, in this case the instance of Foo stored in ‘b’.

The following code is equivalent to the above, but self is explicity specified.


class Foo
  def hello
    self.there          # a method call with a receiver?
    puts " there"
  end
  def there
    puts "hello"
  end
end

b = Foo.new
b.hello

I know this seems trivial, but its very important, so I will say it again – a method is always executed by sending a message to self – self is always changing so it contains different objects however.

Class definitions are executable code

Big deal – what has this got to do with this spiffy ‘has_many’ Rails style directives. Well, the next thing you need to learn, is that class defintions are executable code. Remember that any method that is executed, must be executed on self …


class Foo
  puts "hello"

  def bar
  end
end

Classes are just objects

Runnning the above code prints “hello” – we know its doing this because class definitions are executable code, but also that puts is invoked against self, so what is self?


class Foo
  puts self
  puts self.class

  def bar
  end
end

Which outputs


Foo
Class

So inside a class definition, the current object is set to an object with the same name as your class, that is of type Class. This leads to the second thing you need to remember – a class is nothing but an object – yes its a little special, but its an object none the less.

Ruby is even sneakier – when you define a class ‘Foo’, Ruby creates a constant called Foo, and places an object of type Class into it which contains the definition of your klass. Don’t believe me? Run this code –


class Foo
end

puts Foo
puts Foo.class

Which produces


Foo
Class

ie, the contents of a constant, ‘Foo’, (because in Ruby any variable starting with an uppercase letter is a constant) is an instance of Class, called ‘Foo’.

Phew – thats enough for now – next time, I will introduce metaclasses and the other bits and pieces that allow these Rails like ‘has_many’ directives to actually work …

Advertisements

Entry filed under: metaprogramming, rails, ruby, Uncategorized. Tags: , , .

Four things hotel 1.0 and web app 1.0 have in common Rails style meta programming in Ruby – part 2

1 Comment Add your own

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

Trackback this post  |  Subscribe to the comments via RSS Feed


Feeds


%d bloggers like this: