What is yield self in Ruby

A question that arises almost every week on #ruby-lang is this:

I know how to create code blocks for my methods, but what is this yield self?

After trying to explain it every time, I started to use this gist. And now I’m writing a blog post about it. Yeah, it’s that recurrent.

I’m going to assume you know what a code block is - a piece of code that receives an |argument| as parameter and does some computation, like in Array#each or String#each_line. But iterators like these aren’t the only use for them.

In my post about IO in Ruby, I showed how File::open accepts a code block:

File.open("_posts/2012-10-03-what-is-yield-self-in-ruby.md", 'r') do |file|
  puts file
end

# => #<File:0x007fa141185878>

As you can see, the file variable is in fact the opened object inside the block. After calling the code block, file.close is called before passing control back to your code, avoiding “Oh, I forgot to close this file” kind of errors. (the operating system won’t let you open more files if you don’t close the ones you already used)

Let’s create the Pokemon class:

class Pokemon
  def initialize(move)
    @move = move
  end

  def battle
    yield self
  end

  def use_move
    puts "used #{@move}!"
  end
end

mewtwo = Pokemon.new "Psychic"

mewtwo.battle do |m2|
  m2.use_move
end

# => used Psychic!

arceus = Pokemon.new "Judgement"

arceus.battle do |arc|
  arc.use_move
end

# => used Judgement!

As you can see, inside the code block you can call the method use_move on the argument passed to it. This means that when you call yield self inside your method, you’re passing the object as a parameter.

It’s a parameter like any other object. And why is this useful? Well, house-keeping like calling a method after the block, but before control is returned to the program (logging is a nice example) and configuration, like in ActiveRecord.

class CreateProducts < ActiveRecord::Migration
  def up
    create_table :products do |t|
      t.string :name
      t.text :description

      t.timestamps
    end
  end

  def down
    drop_table :products
  end
end

In this migration, look at the create_table method, receiving a code block in which t is a parameter - it’s the table being created. And all the methods called on it - string, text, timestamps - are used to generate columns.

I hope that this blog post helps people understand what yield self means. Truly.

Further reading

How to write a method that uses code blocks