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.

Read more…

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.

Read more…

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.

Read more…