Colm Troy
Colm Troy

Reputation: 1947

Ruby Exceptions in a loop

I have a ruby script that loops through a list of shortened urls (around 2,000 - 3,000 at a time). At the moment everything is peachy until a hit a url that is malformed, timedout etc. When an error occurs my script dies. How can I setup my loop to skip to the next record when/if such an error occurs.

my loop looks like this:

blah.foo do |barurl|
  mymethod(barurl)

my mymethod looks like this:

def mymethod(barurl)
  begin
    stuff
    ...
    return expandedurl
  rescue
    return "Problem expanding link"
  end
end

Should my begin/end logic be wrapped around my loop instead of the method?

Upvotes: 4

Views: 13615

Answers (5)

Derrell Durrett
Derrell Durrett

Reputation: 576

I found the existing answers unsatisfying, and reading the documentation suggests to me that the OP had something more like the example suggested there in mind:

[0, 1, 2].map do |i|
  10 / i
rescue ZeroDivisionError
  nil
end
#=> [nil, 10, 5]

The docs specifically note that a rescue block permits the loop to continue on a caught exception (as indicated by the example).

Upvotes: 3

keymone
keymone

Reputation: 8104

having exception handling within your method is proper way of doing it, so your implementation is fine

i can only point some ruby sytax sugar to you:

def some_method
  # here goes the code
rescue Exception => e
  # here goes specific exception/error handling
rescue
  # here goes error handling (not Exception handling though!)
else
  # do this block when no exceptions are raised
ensure
  # do this every time
end

btw you don't need return statements, last value of code block is always returned implicitly

ah i guess i misread your question in the "how to skip next record"

if you want to skip the record after current one that was incorrect you would have to return error code from your parsing method and set up skipping within your loop using break or next keywords

Upvotes: 1

megas
megas

Reputation: 21791

Because you need to skip the malformed url, you should use the exception message to control the loop

blah.foo do |barurl|
  begin
    mymethod(barurl)
  rescue YourTypeOfException
    next
  end
end

and inside the method raise the exception

def mymethod(barurl)
  stuff
  ...
  raise YourTypeOfException, "this url is not valid"
  ...
end

Upvotes: 12

Matheus Moreira
Matheus Moreira

Reputation: 17030

Yes. All your method does is consume the exception and return another arbitrary object in order to indicate an error.

Your method shouldn't handle its own exceptional conditions. It is just rude on its part to make assumptions about how the caller will react.

blah.foo do |url|
  begin
    my_method url
  rescue
    next
  end
end

Whether to skip to the next URL or print a message is not a decision the method should be making. Its only concern should be working with the URL.

With that said, you should simply let it propagate and only rescue from it when you can actually deal with it. Don't rescue from a TimeoutError if all you can do is return :timeout.

Do rescue when you need to clean up resources or simply let the user know an error occurred.

Also, rescuing from every possible error just to make them go away is a nice way to introduce bugs. Be as specific as possible.

Upvotes: 2

Dave Newton
Dave Newton

Reputation: 160311

It should be inside the loop, so the loop structure isn't exited on an exception. But it looks like it already is--if you're rescuing inside the method that causes the exception, the loop should already continue normally, because it shouldn't be seeing the exception.

Upvotes: 0

Related Questions