A collection of notes, codes and various further readings that accompanied the December 12th Hackday event.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Intro to Ruby Meta-Programming

A collection of notes, codes and various further readings that accompanied the December 12th Hackday event.

What is Ruby meta-programming?

Using one's understanding of the Ruby object model to create methods in the “right place” based on decisions made at runtime.

Using Ruby's interpreted environment to create code based on runtime decisions.

Object Model



  • State and the things that can be done to that state define an object.

  • Lots of Person objects can be created each with their own state.

  • Every Person has same set of methods.

  • Adding/changing a method on the Person class has to apply to all person instances.

  • Inefficient to put the methods in the instances.

  • Objects contain a pointer to its class that has a list of methods.

  • In order to call a method, Ruby looks up class then method.

  • Draw classes to the right, so first step to find a method is “go right”.



  • Self always references current object.

  • What is the “current object”?

  • The default receiver of method calls.

  • Location of instance variables.

  • “Every line of code is executed against a particular self.” - Katz

How does self get set?

One way is to call a method with an explicit receiver.

  1. Switch self to receiver

  2. Lookup method is self's class

  3. Invoke the method

“Go to the right.” gotascii/metaprogramming/blob/master/object_model/02.rb

  • Super contains a pointer to super class

  • Method resolution follows this until it finds the method

“Go to the right then up.” gotascii/metaprogramming/blob/master/object_model/03.rb

Metaclasses (anonymous, singleton, …)


  • Every object gets its own invisible class, called a metaclass.

  • We can get to the class using class << obj

  • def has a feature, when called with an object it adds the method to the metaclass.


  • Even with the presence of this metaclass, the above rules still apply!



  • Classes are instances of class Class.

  • Provide a place to store method implementation for instances.

  • Class names are constants that point to a class instances.


  • Class definition is another way to change self.

  • Inside class definition self changes to instance of the class.

  • Since classes are just instances, all of the method resolution rules we talked about apply.


  • Class methods are methods on a classes metaclass.

  • This means there are no “class methods” in ruby!




  • Can have no instances.

  • Can have no subclasses.

  • It is an instance of Module.

  • Switches self to current module instance, just like class.

  • Provides a place to store and share (mixin) methods.



  • Creates an invisible class that proxies method lookups to the module

  • Makes the class the receiver's immediate superclass.

  • Include is a private method.



  • Adds the invisible class to the receiver's metaclass.

  • Extend is a public method.

Callbacks & ClassMethods


  • Modules can define module methods that are called whenever they are included or used to extended.


  • In order to extend a class when you include a module use the ClassMethods technique.



  • Attr methods are defined on the Module class, can be used whenever.

  • Self is a class or module.

  • They 'look' like keywords, but are actually class methods used in class definition.

Create a macro through a class method


  • Since self.name is being defined on the class it can then be used as a macro within that class.

Create a macro through a module


  • Person class is being extended with Speech module, all instance level methods on Speech are now class methods on Person.


  • Speech module now has a hook method 'included' on it, this method will take the class including Speech and call extend ClassMethods on that class, thereby extending Person to have the class method say.

Macros defined in a parent class, are inherited on child classes



Calling a block, two ways


  • Blocks are chunks of code between { } or do end.

  • Blocks are like the body of code in an anonymous method.

  • Blocks can take args just like methods, passed differently using | |.

Creating a block

Creating a block that takes arguments



  • Iterators are methods that can invoke a block of code.

  • Blocks passed to methods have scope remembered before the method is entered.

Blocks, Procs, Lambdas, Methods

  • Blocks - Evaluated in the scope in which they’re defined.

  • Procs - Objects of class Proc. Like blocks, they are evaluated in the scope where they’re defined.

  • Lambdas — Objects of class Proc but subtly different from regular procs, they require the passing of the arguments they were defined with. They’re closures like blocks and procs, and as such they’re evaluated in the scope where they’re defined.

  • Methods - Bound to an object, they are evaluated in that object’s scope. They can also be unbound from their scope and rebound to the scope of another object.



  • Module#define_method

Example with arguments


  • Note, what we've done here is dynamically created macros

Let's make our own attr_accessor, called aa

  • Define a method called aa on Module, this method takes one argument and dynamically creates a getter and setter method based on the name of that argument.


NoMethodError example


  • Method lookup: Ruby goes into p's class and browses it's instance methods. Since it can't find it there, ruby goes up the ancestral chain into Object and finally Kernal. If it still cannot find the method, Ruby will raise an undefined method exception.

Overwriting method_missing example - 02.rb


  • There is an instance method on Kernel named method_missing, this is the last thing Ruby checks before raising an exception. If we overwrite this method in the Person class, we can intercept Ruby while it's doing it's method lookup.

ActiveRecord's dynamic find methods


  • ActiveRecord uses method_missing to intercept find_by_* and find_all_by_* calls. In order to reduce the cost of these expensive method missing calls, AR will dynamically define the find_by method after the first time it's called.

Further Reading

ruby-metaprogramming.heroku.com An online meta-programming course.

pragprog.com/screencasts/v-dtrubyom/the-ruby-object-model-and-metaprogramming Commercial screencasts on meta-programming by Dave Thomas.

pragprog.com/titles/ppmetr/metaprogramming-ruby A whole book on this stuff.

yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self A concise summary of meta-programming in Ruby by Yehuda Katz.