Ruby’s self keyword is probably one of the most basic yet interesting ideas in ruby programming language. self is an globally accessible keyword: ruby makes sure that there is always a self that can be accessed in any context. The value of self, however, will change based on the current context.

It’s important for a comprehensive understanding of ruby and ruby object model to understand when and how does self change. self is such an important keyword, that some may argue that all Metaprogramming is based on knowing what self in the current context is.

At the Top-Level context self will point to main, a special instance of object. self will keep pointing to main until the parser faces a class or a def keyword.

self after class keyword

When ruby faces a class keyword, it changes the value of self. Inside the boundaries of a class, that is between class and end, self will point to the class object.

class SomeUsefulClass
  puts self
end

The above example outputs SomeUsefulClass since self will point to that class.

We can also use class keyword to extend an object’s metaclass. When inside the metaclass, self will point to that metaclass object.

class SomeUsefulClass
  class << self
    puts self
  end
end

As expected the above will print #<Class:SomeUsefulClass> which is the singleton class of SomeUsefulClass

self after def keyword

self inside a method will always point to the receiver instance of that method call. Lets check the following example:

class SomeUsefulClass
  def test
    puts self
  end
end

obj = SomeUsefulClass.new
puts obj

obj.test

Both puts self and puts obj will print #<SomeUsefulClass:0x007fb7428b9f10>; that is because ruby will set self to be obj before calling test, and it will then revert it to what it was after returning from test.

The same concept stands for singleton methods:

class SomeUsefulClass
  def self.test_singleton
    puts self
  end
end

puts SomeUsefulClass
puts SomeUsefulClass.test_singleton

The last two puts will both print SomeUsefulClass. As with instance method, ruby will set self to the receiver, SomeUsefulClass, before calling test_singleton method.

Wether its an instance method or singleton method, the value of self inside them will always be the receiver of that method call.

self inside a block

Normally, self inside and outside the block will point to object, I mean, this is the main idea of a closure: to capture the current context.

puts self
l = proc { puts self }
l.call

Bot of the puts above, unsurprisingly, will print main.
The same assumption holds if we pass the block to a method:

class SomeUsefulClass
  def call_block(block)
    block.call
  end
end

puts self
l = proc { puts self }
SomeUsefulClass.new.call_block l

Running the above will also yield two main lines in the console.

However, self inside the block, will be changed when the block is called form instance_eval or class_eval. Ruby will set the self to be the value of the receiver object. To make it more clear, lets consider this example:

class SomeUsefulClass
  def call_block(block)
    instance_eval(&block)
  end
end

l = proc { puts self }
SomeUsefulClass.new.call_block l

The above example is using the same proc block used above, however, in this example the block will print #<SomeUsefulClass:0x007fd72b033fe0> which is the instance of SomeUsefulClass. instance_eval changes the value of self to be the receiver of the method before calling the block. In the above example, self inside the block was changed to be the instance of SomeUsefulClass

Likewise, if we executed SomeUsefulClass.class_eval(&l), the value of self inside the block will be SomeUsefulClass; As with instance_eval, class_eval assigned SomeUsefulClass to self before calling the block.

DSLs and self

The two evals method explained above are crucial to support dynamic, flexible DSL (domain specific languages).
Lets consider a simple HTMLBuilder class. This class will help us with the trivial task of building a correct html document. The builder contains add_head_open_tag, add_head_close_tag, add_tag, and build (full source). build can be implemented as a factory method that takes a block and yields an instance of HTMLBuilder. build will be used as:

class HTMLBuilder
  def self.build
    yield(self.new)
  end
  ... Most of class omitted
end

HTMLBuilder.build do |h|
  h.add_head_open_tag
  h.add_body_open_tag
  h.add_tag("br")
  h.add_body_close_tag
  h.add_head_close_tag
end

The above is a good starting DSL, however, h variable is repeated on every row.
By understanding that instance_eval will set self inside the block to be the instance that called instance_eval, we can rewrite the above and remove h:

class HTMLBuilder
  def self.build2(&b)
    self.new.instance_eval(&b)
  end
  ... Most of class omitted
end

HTMLBuilder.build2 do
  add_head_open_tag
  add_body_open_tag
  add_tag("br")
  add_body_close_tag
  add_head_close_tag
end

build2 method creates a new instance of HTMLBuilder and calls instance_eval on it. This will execute the block passed with self set to the value of the newly created instance.

We can argue that build2 looks more like a DSL than build, however, we could even go a step further and eliminate the whole ruby syntax around our DSL.

In our last attempt of a DSL, we will create a text file, test.hbuilder, with the following inside it:

 add_head_open_tag
 add_body_open_tag
 add_tag("br")
 add_body_close_tag
 add_head_close_tag

This text file will contain the DSL commands that we want to execute. We need to execute the block with self set to an instance of HTMLBuilder, the following code will just do that:

HTMLBuilder.new.instance_eval(File.read("test.hbuilder"))

The full source can be found here

DSLs are a very large topics, hence, are outside this post. I suggest, for further understanding on this subject, Eloquent Ruby, Metaprogramming Ruby 2, or This video.