Implement 'rescue' without 'next' - ruby

I have this example to handle errors and continue code execution:
begin
p '-' * 100
request_builder.new(env: tested_env).submit!
rescue => error
error_logs << "#{error}\n#{error.backtrace.first(5).join("\n")}"
next
end
How can I rewrite the code without next?
I found this example:
%w(1 2).each do |x|
p x
begin
raise 'something'
rescue => error
p error
end
end
=>
"1"
#<RuntimeError: something>
"2"
#<RuntimeError: something>
How can it be used to implement the code?

The next in you example has nothing to do, with a normal rescue block. It just tells to go to the next iteration. So remove your next statement and you are find.
begin
p '-' * 100
request_builder.new(env: tested_env).submit!
rescue => error
error_logs << "#{error}\n#{error.backtrace.first(5).join("\n")}"
# next # removing next, removes you error,
# you just put whatever you want in your rescue block,
# the application continues in this block
end

Related

rescue / exeception marked as red in editor? Were Am I going wrong

I have just started test automation project in ruby, however, am only used to java so trying to get the hang of ruby and I cant see where my syntax is going wrong.
rescue Watir::Exception::TimeOutException => e
is underlined in red, why? Unexpected keyword rescue?
def check(UpTimer)
limit = 0
begin
#browser.alert.wait_until_present(UpTimer)
if code
code
rescue Watir::Exception::TimeOutException => e
limit += 1
retry if limit <= 3
#Add in Message for HTML Report?
end
end
end
Your rescue should be at the end of the begin block, since that's the block you're rescuing exceptions within. You're seeing an error because it can't rescue in the middle of the if block.
def check(up_timer)
limit = 0
begin
#browser.alert.wait_until_present(up_timer)
code if code
rescue Watir::Exception::TimeOutException => e
limit += 1
retry if limit <= 3
#Add in Message for HTML Report?
end
end
Another issue in your code is the UpTimer variable - Ruby is seeing that as a constant instead of a variable due to your casing. That should be up_timer.

ruby: finish loop iteration before raising Interrupt

I'm looping through a lot of items and I want to periodically interrupt the loop to save and continue at a later time like this:
begin
big_list.each do |i|
# sensitive stuff
sensitive_method(i)
# other sensitive stuff
end
rescue Interrupt
# finish the current iteration
# then do something else (save)
# don't raise (print done)
end
By sensitive I mean that, if Interrupt is raised in the middle of an iteration, data will be corrupted so I need to guarantee that the iteration finishes before exiting.
Also, if another exception is raised, it should still finish the loop but raise it afterwards
EDIT:
Using the answer by mudasobwa in a test scenario:
while true
result = begin
puts "start"
sleep 1
puts "halfway"
sleep 1
puts "done\n\n"
nil
rescue Exception => e
e
end
case result
when Interrupt
puts "STOPPED"
break
when Exception then raise result
end
end
I get:
start
halfway
done
start
^C: /...
STOPPED
which is my exact problem, I need it to finish the loop (sleep, print halfway, sleep, print done) and only then break out (wrapping the puts, sleep... in a method does not help)
TL;DR: There is no way to continue the execution of the method from inside the middle of it.
big_list.each do |i|
# sensitive stuff
result = begin
sensitive_method(i)
nil
rescue Exception => e
e
end
# other sensitive stuff
case result
when Interrupt
puts "done"
break "done"
when Exception then raise result
end
end
Sidenote: you probably don’t want to rescue the topmost Exception, but some subclass that makes sense to rescue.
To make it possible to finish the chunk of operations:
operations = [
-> { puts "start" },
-> { sleep 1 },
-> { puts "halfway" },
-> { sleep 1 },
-> { puts "done\n\n" }
]
def safe_chunk(operations, index = 0)
result = operations[index..-1].each_with_index(index) do |op, idx|
begin
op.()
rescue Exception => e
safe_chunk(operations, idx) # or idx + 1
break e
end
end
result.is_a?(Array) ? nil : result
end
The Interrupt exception is raised in the main thread. If you use a worker thread to process the list it will never be interrupted. You will need a way to tell the worker thread to terminate though. Rescuing Interrupt in the main thread and setting a flag that's checked by the child can accomplish this.
BigList = (1..100)
def sensitive_method(item)
puts "start #{item}"
sleep 1
puts "halfway #{item}"
sleep 1
puts "done #{item}"
puts
end
#done = false
thread = Thread.new do
begin
BigList.each do |item|
break if #done
sensitive_method item
end
end
end
begin
thread.join
rescue Interrupt
#done = true
thread.join
end
The keyword ensure, used in rescue clauses, is available for situation such as this one, where code must be executed after an exception occurs.
[-1, 0, 1].each do |i|
begin
puts "i=#{i} before exception"
# <additional code>
n = 1/i
rescue ZeroDivisionError => e
puts "Exception: #{e}"
exit
ensure
puts "Just executed 1/#{i}"
# <additional code>
end
end
i=-1 before exception
Just executed 1/-1
i=0 before exception
Exception: divided by 0
Just executed 1/0
Notice that begin/rescue/ensure/end must be inside the loop and that the code after ensure is executed for each i regardless of whether a zero-divide exception occurs.

In Ruby, can you create a rescue for twitter for when there is an error it will continue the loop?

I'm trying to create a rescue that if and when there is an Twitter::Error::NotFound error (such as does not exist) it will just keep going through the loop. Please help, thanks.
Below is the code,
begin
File.open("user_ids.txt") do |file|
file.each do |id|
puts client.user("#{id}").screen_name
rescue Twitter::Error::NotFound => error
next # skip this item
end
end
end
Instead of the retry method is there a a method that can skip and keep moving on to the next item in the loop?
I'm pretty sure the error.rate_limit does not apply (I copied this code from a different rescue call), is there another method to call? like error.notfound.continue_with_loop
I would like to create a rescue that if and when there is an error such as does not exist so it will just keep going through the loop. Please help, thanks.
yes next will continue and retry the next item in a loop.
retry will retry the loop with the same item.
Note: you don't have enough ends for all the do that are in that method. So I'd try:
begin
File.open("user_ids.txt") do |file|
file.each do |id|
puts client.user("#{id}").screen_name
rescue Twitter::Error::NotFound => error
sleep error.rate_limit.reset_in + 1
next # skip this item
end
end
end
Note: see how proper indentation makes it clear when you're missing an end ?
You may need to shift the begin/end block that is currently around the lot - to just be around the code that you want to rescue-from (or it'll default to the outside begin/end rather than your loop)
File.open("user_ids.txt") do |file|
file.each do |id|
begin
puts client.user("#{id}").screen_name
rescue Twitter::Error::NotFound => error
sleep error.rate_limit.reset_in + 1
next # skip this item
end
end
end

ruby rescue block -- respond with more than just one command

I'm running a script with an API that often times out. I'm using begin/rescue blocks to get it to redo when this happens, but want to log what is happening to the command line before I run the redo command.
begin
#...api query...
rescue ErrorClass
puts("retrying #{id}") && redo
end
Unfortunately the above script doesn't work. Only the first command is run.
I would like to force the rescue block to run multiple lines of code like so:
begin
# api query
rescue ErrorClass do ###or:# rescue ErrorClass do |e|
puts "retrying #{id}"
redo
end
but those don't work either.
I've had luck creating a separate method to run like so:
def example
id = 34314
begin
5/0
rescue ZeroDivisionError
eval(handle_zerodiv_error(id))
end
end
def handle_zerodiv_error(id)
puts "retrying #{id}"
"redo"
end
...that actually works. But it requires too many lines of code in my opinion and it uses eval which is not kosher by any means according to my mentor(s).
You are unnecessarily complicating things by using && or do. The && version does not work because puts returns nil, so by shortcut evaluation of &&, the part to follow is not evaluated. If you use || or ; instead, then it will work:
begin
...
rescue ErrorClass
puts("retrying #{id}") || redo
end
begin
...
rescue ErrorClass
puts("retrying #{id}"); redo
end
but even this is not necessary. You somehow seem to believe that you need a block within rescue to write multiple lines, but that does not make sense because you are not using a block with single line. There is no Ruby construction that requires a block only when you have multiple lines. So, just put them in multiple lines:
begin
...
rescue ErrorClass
puts("retrying #{id}")
redo
end
There is a retry built in. This example is from "The Ruby Programming Language" pg 162.
require "open-uri"
tries = 0
begin
tries +=1
open("http://www.example.com/"){|f| puts f.readlines}
rescue OpenURI::HTTPError => e
puts e.message
if (tries < 4)
sleep (2**tries) # wait for 2, 4 or 8 seconds
retry # and try again
end
end

Ruby: Continue a loop after catching an exception

Basically, I want to do something like this (in Python, or similar imperative languages):
for i in xrange(1, 5):
try:
do_something_that_might_raise_exceptions(i)
except:
continue # continue the loop at i = i + 1
How do I do this in Ruby? I know there are the redo and retry keywords, but they seem to re-execute the "try" block, instead of continuing the loop:
for i in 1..5
begin
do_something_that_might_raise_exceptions(i)
rescue
retry # do_something_* again, with same i
end
end
In Ruby, continue is spelt next.
for i in 1..5
begin
do_something_that_might_raise_exceptions(i)
rescue
next # do_something_* again, with the next i
end
end
to print the exception:
rescue
puts $!, $#
next # do_something_* again, with the next i
end

Resources