The following code works:
collection.each do |i|
begin
next if i > 10
i += 1
rescue
puts "could not process #{ i }"
end
end
However, when we refactor:
collection.each do |i|
begin
increment i
rescue
puts "could not process #{ i }"
end
end
def increment i
next if i > 10
i += 1
end
I get invalid next error. Is this a limitation of Ruby (1.9.3)?
Does the begin rescue block work the same way if there is an exception in the increment method?
Your next statement must occur inside a loop. There's no loop inside your increment method.
Exceptions will 'bubble up', so if there's an exception in your increment method, it will be caught by the rescue section of the calling method.
Related
my code here...
require 'thread'
$temp = Thread.new do
loop do
puts 'loop me'
begin
puts "try thread"
raise Exception.new('QwQ') if rand > 0.5
puts "skip try"
rescue
puts "QwQ"
end
sleep(0.5)
end
puts '...WTF'
end
loop do
puts "runner #{Thread.list.length} #{$temp.status}"
sleep(2)
end
how to keep runner and loop thread running? and how to fix it like this code?
I tried like Thread.abort_on_exception , but it will kill the process...
Catch the exception inside the thread, and set the error in a variable accessible by the main thread (for testing you could use a global variable like so: $thread_error).
If the error-variable exists, then raise it from the main thread.
You could also use a queue to communicate between the threads, but then it wouldn't be able to utilize multiple threads.
require 'thread'
$temp = Thread.new do
begin
loop do
puts 'loop me'
begin
puts "try thread"
raise Exception.new('QwQ') if rand > 0.5
puts "skip try"
rescue
puts "QwQ"
end
sleep(0.5)
end
puts '...WTF'
rescue Exception => e
$thread_error = e
raise e
end
end
loop do
puts "runner #{Thread.list.length} #{$temp.status}"
raise $thread_error if $thread_error
sleep(2)
end
How can I write resuming into loops in Ruby? Here is a sample code.
#!/usr/bin/ruby
#
a = [1,2,3,4,5]
begin
a.each{|i|
puts i
if( i==4 ) then raise StandardError end # Dummy exception case
}
rescue =>e
# Do error handling here
next # Resume into the next item in 'begin' clause
end
However, when running, Ruby returns the error message
test1.rb:13: Invalid next
test1.rb: compile error (SyntaxError)
I'm using Ruby 1.9.3.
You should use retry instead of next; But this will cause infinite loop (retry restart from the beginning of the begin)
a = [1,2,3,4,5]
begin
a.each{|i|
puts i
if i == 4 then raise StandardError end
}
rescue =>e
retry # <----
end
If you want skip an item, and continue to next item, catch the exception inside the loop.
a = [1,2,3,4,5]
a.each{|i|
begin
puts i
if i == 4 then raise StandardError end
rescue => e
end
}
Move your exception catching into the each block e.g:
a = [1,2,3,4,5]
a.each do |i|
puts i
begin
# Dummy exception case
if( i==4 ) then raise StandardError end
rescue =>e
# Do error handling here
end
end
begin
#some routine
rescue
retry
#on third retry, output "no dice!"
end
I want to make it so that on the "third" retry, print a message.
Possibly not the best solution, but a simple way is just to make a tries variable.
tries = 0
begin
# some routine
rescue
tries += 1
retry if tries <= 3
puts "no dice!"
end
loop do |i|
begin
do_stuff
break
rescue
raise if i == 2
end
end
or
k = 0
begin
do_stuff
rescue
k += 1
k < 3 ? retry : raise
end
begin
#your code
rescue
retry if (_r = (_r || 0) + 1) and _r < 4 # Needs parenthesis for the assignment
raise
end
There is another gem named retry-this that helps with such a thing.
ruby-1.9.2-p0 > require 'retry-this'
ruby-1.9.2-p0 > RetryThis.retry_this(:times => 3) do |attempt|
ruby-1.9.2-p0 > if attempt == 3
ruby-1.9.2-p0 ?> puts "no dice!"
ruby-1.9.2-p0 ?> else
ruby-1.9.2-p0 > puts "trying something..."
ruby-1.9.2-p0 ?> raise 'an error happens' # faking a consistent error
ruby-1.9.2-p0 ?> end
ruby-1.9.2-p0 ?> end
trying something...
trying something...
no dice!
=> nil
The good thing about such a gem as opposed to raw begin..rescue..retry is that we can avoid an infinite loop or introducing a variable just for this purpose.
class Integer
def times_try
n = self
begin
n -= 1
yield
rescue
raise if n < 0
retry
end
end
end
begin
3.times_try do
#some routine
end
rescue
puts 'no dice!'
end
The gem attempt is designed for this, and provides the option of waiting between attempts. I haven't used it myself, but it seems to be a great idea.
Otherwise, it's the kind of thing blocks excel at, as other people have demonstrated.
def method(params={})
tries ||= 3
# code to execute
rescue Exception => e
retry unless (tries -= 1).zero?
puts "no dice!"
end
Proc.class_eval do
def rescue number_of_attempts=0
#n = number_of_attempts
begin
self.call
rescue => message
yield message, #n if block_given?
#n -= 1
retry if #n > 0
end
end
end
And then you can use it as:
-> { raise 'hi' }.rescue(3)
-> { raise 'hi' }.rescue(3) { |m, n| puts "message: #{m},
number of attempts left: #{n}" }
I know of the standard technique of having a begin rescue end
How does one just use the rescue block on its own.
How does it work and how does it know which code is being monitored?
A method "def" can serve as a "begin" statement:
def foo
...
rescue
...
end
You can also rescue inline:
1 + "str" rescue "EXCEPTION!"
will print out "EXCEPTION!" since 'String can't be coerced into Fixnum'
I'm using the def / rescue combination a lot with ActiveRecord validations:
def create
#person = Person.new(params[:person])
#person.save!
redirect_to #person
rescue ActiveRecord::RecordInvalid
render :action => :new
end
I think this is very lean code!
Example:
begin
# something which might raise an exception
rescue SomeExceptionClass => some_variable
# code that deals with some exception
ensure
# ensure that this code always runs
end
Here, def as a begin statement:
def
# something which might raise an exception
rescue SomeExceptionClass => some_variable
# code that deals with some exception
ensure
# ensure that this code always runs
end
Bonus! You can also do this with other sorts of blocks. E.g.:
[1, 2, 3].each do |i|
if i == 2
raise
else
puts i
end
rescue
puts 'got an exception'
end
Outputs this in irb:
1
got an exception
3
=> [1, 2, 3]
Here is Bar#do_things:
class Bar
def do_things
Foo.some_method(x) do |x|
y = x.do_something
return y_is_bad if y.bad? # how do i tell it to stop and return do_things?
y.do_something_else
end
keep_doing_more_things
end
end
And here is Foo#some_method:
class Foo
def self.some_method(targets, &block)
targets.each do |target|
begin
r = yield(target)
rescue
failed << target
end
end
end
end
I thought about using raise, but I am trying to make it generic, so I don't want to put anything any specific in Foo.
Use the keyword next. If you do not want to continue to the next item, use break.
When next is used within a block, it causes the block to exit immediately, returning control to the iterator method, which may then begin a new iteration by invoking the block again:
f.each do |line| # Iterate over the lines in file f
next if line[0,1] == "#" # If this line is a comment, go to the next
puts eval(line)
end
When used in a block, break transfers control out of the block, out of the iterator that invoked the block, and to the first expression following the invocation of the iterator:
f.each do |line| # Iterate over the lines in file f
break if line == "quit\n" # If this break statement is executed...
puts eval(line)
end
puts "Good bye" # ...then control is transferred here
And finally, the usage of return in a block:
return always causes the enclosing method to return, regardless of how deeply nested within blocks it is (except in the case of lambdas):
def find(array, target)
array.each_with_index do |element,index|
return index if (element == target) # return from find
end
nil # If we didn't find the element, return nil
end
I wanted to just be able to break out of a block - sort of like a forward goto, not really related to a loop. In fact, I want to break of of a block that is in a loop without terminating the loop. To do that, I made the block a one-iteration loop:
for b in 1..2 do
puts b
begin
puts 'want this to run'
break
puts 'but not this'
end while false
puts 'also want this to run'
end
Hope this helps the next googler that lands here based on the subject line.
If you want your block to return a useful value (e.g. when using #map, #inject, etc.), next and break also accept an argument.
Consider the following:
def contrived_example(numbers)
numbers.inject(0) do |count, x|
if x % 3 == 0
count + 2
elsif x.odd?
count + 1
else
count
end
end
end
The equivalent using next:
def contrived_example(numbers)
numbers.inject(0) do |count, x|
next count if x.even?
next (count + 2) if x % 3 == 0
count + 1
end
end
Of course, you could always extract the logic needed into a method and call that from inside your block:
def contrived_example(numbers)
numbers.inject(0) { |count, x| count + extracted_logic(x) }
end
def extracted_logic(x)
return 0 if x.even?
return 2 if x % 3 == 0
1
end
use the keyword break instead of return
Perhaps you can use the built-in methods for finding particular items in an Array, instead of each-ing targets and doing everything by hand. A few examples:
class Array
def first_frog
detect {|i| i =~ /frog/ }
end
def last_frog
select {|i| i =~ /frog/ }.last
end
end
p ["dog", "cat", "godzilla", "dogfrog", "woot", "catfrog"].first_frog
# => "dogfrog"
p ["hats", "coats"].first_frog
# => nil
p ["houses", "frogcars", "bottles", "superfrogs"].last_frog
# => "superfrogs"
One example would be doing something like this:
class Bar
def do_things
Foo.some_method(x) do |i|
# only valid `targets` here, yay.
end
end
end
class Foo
def self.failed
#failed ||= []
end
def self.some_method(targets, &block)
targets.reject {|t| t.do_something.bad? }.each(&block)
end
end
next and break seem to do the correct thing in this simplified example!
class Bar
def self.do_things
Foo.some_method(1..10) do |x|
next if x == 2
break if x == 9
print "#{x} "
end
end
end
class Foo
def self.some_method(targets, &block)
targets.each do |target|
begin
r = yield(target)
rescue => x
puts "rescue #{x}"
end
end
end
end
Bar.do_things
output: 1 3 4 5 6 7 8
You have four ways to unwind the stack in 'non-exceptional' ways: next, break, return, and throw.
next will cause the block to return.
break will cause the method that yielded to the block to return.
return will cause the method where the block is defined to return.
throw will traverse up the stack until it finds a catch with a matching symbol, and cause that to return. This is much like a 'lightweight' exception for non-exceptional situations.
All of them can take a return value that will be returned by whatever they caused to return instead of the value their last expression which they would return normally.
Here are some examples:
def doSomething
puts "> doSomething"
yield
puts "< doSomething"
end
def withNext
puts "> withNext"
doSomething do
puts "> block"
puts "* NEXT! causes the block to return to doSomething"
next
puts "< block"
end
puts "< withNext"
end
def withBreak
puts "> withBreak"
doSomething do
puts "> block"
puts "* BREAK! causes doSomething to return to withBreak"
break
puts "< block"
end
puts "< withBreak"
end
def withReturn
puts "> withReturn"
doSomething do
puts "> block"
puts "* RETURN! causes withReturn to return"
return
puts "< block"
end
puts "< withReturn"
end
def withThrow
puts "> withThrow"
catch :label do
puts "> catch :label"
doSomething do
puts "> block 1"
doSomething do
puts "> block 2"
puts "* THROW! causes catch :label to return to withThrow"
throw :label
puts "< block 2"
end
puts "< block 1"
end
puts "< catch :label"
end
puts "< withThrow"
end
withNext
puts "* Done"
puts
withBreak
puts "* Done"
puts
withReturn
puts "* Done"
puts
withThrow
puts "* Done"
output:
> withNext
> doSomething
> block
* NEXT! causes the block to return to doSomething
< doSomething
< withNext
* Done
> withBreak
> doSomething
> block
* BREAK! causes doSomething to return to withBreak
< withBreak
* Done
> withReturn
> doSomething
> block
* RETURN! causes withReturn to return
* Done
> withThrow
> catch :label
> doSomething
> block 1
> doSomething
> block 2
* THROW! causes catch :label to return to withThrow
< withThrow
* Done
To break out from a ruby block simply use return keyword return if value.nil? next.
next terminates lambda, block, or proc it is in.
break terminates the method that yielded to the block or invoked the proc or lambda it is in.
Credit to: Ruby block return, break, next