Ruby Blocks Tutorial

Sometimes we need to make our code more expressive and tidy but at the same time flexible and easier to use. Learning how to use Ruby blocks appropriately will level you up as a Ruby programmer.

Sometimes we like to “sandwich” boilerplate code for various tasks. Maybe we want to keep track of the value or a variable within a block of code. The simplest example are HTML tags:

We might also duplicate code with similar if-else statements, especially checking boolean values. With blocks, we could separate the concerns a bit and even add the flexibility of performing additional tasks from our result.

So yield basically runs the code in the block and returns its value. That’s the basic concept. Now with this we could run code under a specific context.

One example of this are the Rails environments: development, test, production. When we run code in the context of one of these environments, we want it to automatically switch us back to our default environment, whether an exception has occurred or not. Here are a few other examples:

  • Silence warnings, logs, etc.
  • Changing drivers temporarily
  • Changing defaults for testing (wait times, values, etc)
  • Changing locale, currency, etc.
  • Temporarily funneling results to a file

In my example we’ll use a broker’s trading platform. Most of them allow you to trade virtually or on a live interface:

Once you have to toggle between different contexts, that usually means you could simplify with blocks:

As you could see, the original method is prone to errors while the block pattern encapsulates the toggling in one place and ensures the environment is switched back to the original, even after an exception has occurred.

You get the sense you could do a bit more with this, like managing authentication, a database connection, opening a FTP connection, a URL, opening files, etc. With blocks you could have the code manage its own life cycle. In Ruby, a lot of these blocks are performed with class methods (as opposed to instance methods in the previous examples).

Imagine we want to call an API to make trades for us. A lot of third-party app developers would want this feature. Obviously I need to be authenticated and a connection has to be made. Then my orders will hopefully execute and that connection will close.

Pay special attention to the class method. I no longer have to instantiate an object in order to perform actions on this service. Obviously you would include real authentication rather than a username but this should shed some light on the common Ruby idioms you’ll see.

Finally, you’ve probably noticed that some objects are instantiated with a block instead of passing in variables. We see this in ActiveRecord, Rake tasks, and Gemfiles. If you think about how yield works, you’ll get an idea of how that happens. When calling new, Ruby allocates the memory and calls initialize. In initialize we could actually pass the object to the block as a block parameter and instantiate the instance variables that way:

I hope this tutorial has helped demystify Ruby blocks in a way where you could apply this to your own code.

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *