Jay McGavren
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.) Read more…
Ruby: The Unit Test-Friendly Language
Accelerate your tests with test doubles
Let’s say you have a Ruby class that retrieves the contents of web pages, and you need to write a unit test for it…
class Spider attr_accessor :address, :path def get_response response = Net::HTTP.get_response(@address, @path) end def get_body get_response.body end end
You’ve tested the get_response
method, and now you need to test get_body
. You’re using MiniTest, a unit testing framework that comes standard with Ruby.
class TestSpider < MiniTest::Unit::TestCase def test_get_body spider = Spider.new spider.address = 'programming.oreilly.com' spider.path = '/2014/02/why-ruby-blocks-exist.html' assert spider.get_body == '<h1>Hi!' end end
You create a Spider
instance, assign it a page to retrieve, and at the end of the test, assert that the HTTP response matches your expected value. Simple enough.
Two problems
But there’s two problems with this test:
- Your
Spider
instance is making a real network request for the page, slowing the test and incurring network overhead for both you and the host you visit. - The page could easily change on the remote side. You can use the current page contents in the test assertion, but it might need to be changed in the future.
In fact, the latter issue is causing your test to fail right now, because the real page doesn’t match the simplified HTML in your test.
Finished tests in 3.767214s, 0.2654 tests/s, 0.2654 assertions/s. 1) Failure: test_get_body(TestSpider) [-:26]: Failed assertion, no message given.
Why Ruby blocks exist, part II
Putting return values to work
Last time, we showed you how to use Ruby’s each
method with blocks to process the elements of an array, and how it can save you a lot of repetitive looping code. That was just an introduction, though.
In our previous examples, the block was a final destination. We passed data into blocks, but it never came back out (unless we printed it to the screen). Today we’re going to look at block return values, and how your methods can use them to manipulate your data in even more powerful ways.
Before we move on…
We should mention that there are two syntaxes for blocks in Ruby. In the earlier post, we used the do ... end
syntax:
my_method(my_argument) do |my_parameter| # Code here end
With blocks that fit on one code line, it’s often preferred (though not required) to use the alternate curly-brace syntax for blocks:
my_method(my_argument) {|my_parameter| # Code here }
We’ll be using the curly-brace style of blocks today.
Why Ruby blocks exist
Exploring Ruby's "each" method
It seems like more and more languages these days are getting support for closures in one form or another. (Even Java is getting in on the game, finally.) Ruby has had closure-like structures called blocks since its early days, though, and they’re central to the language. Used properly, they can reduce repetition and even make coding less error-prone. Understanding blocks can give you some great ideas to take home to your language of choice. (Or, who knows? Maybe you’ll decide you like coding in Ruby better!)
Today, we’re going to show you just one of the many Ruby methods that use blocks: each
. We’ll show you some repetitive code that, in most languages, would be hard to refactor. But using each
, we’ll quickly wring that repetition out.