Ruby to the Rescue
18 Aug 2008
Ruby makes handling exceptions super simple. Lets assume you’re about to run a sketchy bit of code, like requesting a remote web site. It might look something like this:
require 'open-uri'
url = "http://slashdot.org/"
doc = open(url)Now, what if SlashDot is down for maintenance, overloaded with traffic, or has blocked your IP for scraping their site every 30 seconds? This code nugget will fail and your program will explode like a piñata during Puerto Rico Days. Let’s account for this and terminate our program gracefully:
require 'open-uri'
url = "http://slashdot.org/"
begin
doc = open(url)
rescue
puts "The request for a page at #{url} timed out...exiting."
exit
endAhh, that’s better! But what if we’re iterating a list of url’s and scraping pages? Maybe we don’t want to exit the program at all, but continue with the next url in the list. I’ll demo with 3 urls:
require 'open-uri'
urls = %w[ http://slashdot.org/ http://news.ycombinator.com/ http://www.techmeme.com/ ]
urls.each do |url|
begin
doc = open(url)
rescue
puts "The request for a page at #{url} timed out...skipping."
next
end
endNow we safely output the offending error and continue with the next value in the urls array. That’s naace!
The truth is that this will not catch all exceptions. The problem is that when using the open-uri class you can receive an OpenURI::Error if the site you’re trying to access returns a 404, 403, 500 or other “not good” response, and you can receive a Timeout::Error if the site simply doesn’t respond at all and the request times out. Let’s modify our nugget to handle both scenarios:
require 'open-uri'
urls = %w[ http://slashdot.org/ http://news.ycombinator.com/ http://www.techmeme.com/ ]
urls.each do |url|
begin
doc = open(url)
rescue Timeout::Error
puts "The request for a page at #{url} timed out...skipping."
next
rescue OpenURI::Error => e
puts "The request for a page at #{url} returned an error. #{e.message}"
next
end
endYou can use multiple rescue blocks to handle multiple exception classes. Now we should have a bullet-proof code nugget. See any chinks in the armor? Let me know in the comments.