Why Ruby blocks exist, part III

Never forget to clean up again!

Previous posts in this series used Ruby blocks to iterate over the items in a collection. We’re going to wrap up by showing a very different side of blocks – resource allocation and cleanup.

Close the door!

Here we have a Ruby class representing a refrigerator. Prior to accessing a refrigerator object’s contents via its contents method, you have to call its open method to open the door. (Sensible enough.)

We can create a new refrigerator instance, open its door, fill it with food, and close the door again.

If we try and access the contents with the door closed, we’ll get a warning, and will have to open the door before trying again.

Observant (and thrifty) readers probably noticed that the last code sample leaves the virtual refrigerator door hanging wide open. Food spoilage and energy waste! We can’t have that. We’ve got to remember to close the door again after we open it.

Let the door close itself!

…Or do we? Maybe we could add a method to automatically close the fridge again after we print its contents!

Of course, if we do that, we should probably add a similar method for adding items to the refrigerator:

…And maybe another method for removing items, and… Wow, there are a lot of operations where we have to open the fridge first, and close it again after! We can’t possibly write methods for all of them.

Previously, we learned that a Ruby method can hand control off to a block, and pass it a value as well. When the code within the block finishes executing, control returns to the method.

The above code prints:

Maybe we can use these features of blocks to write a version of open that will let us run whatever code we want on the refrigerator’s contents, then close it again when we’re done…

Let’s try it out!

This is great! We can use blocks to run any operations we need on the fridge contents, and we still don’t have to worry about calling the close method!

…Okay, knowing how to work with virtual refrigerators efficiently isn’t very useful, we admit. Let’s try something a little more practical…

Close the file!

No matter what programming language you’re coming from, if you’ve worked with reading or writing files before, you’ve (hopefully) been told the importance of remembering to close the file handles when you’re done with them.

Ruby supports this style of coding, like any other language. But Ruby’s File.open method also can take a block, to which it will yield the file handle as a parameter. And just like the open method on our Refrigerator class, File.open will automatically close the file for you when the block exits!

Any time you’ve got a process with a well-defined beginning and end (like allocating and deallocating a resource), but unknown steps in the middle, Ruby blocks are a great way to implement it. With blocks, you’ll never again forget to clean up after yourself!

tags: , , ,