Ruby - Proc.call - catching exceptions - ruby

I have problem with catching exceptions and errors from calling Proc object. See my code:
def method1
.. do something ...
end
def method2
.. do something ...
end
def run_method_safely(proc_obj)
begin
proc_obj.call
rescue => e
puts "Error man!"
... do something ...
end
end
I have few methods (here I have just method1, method2 but in code i have much more methods) which are run by method run_method_safely. I'm doing that this way because I don't want to have every method in begin-rescue block so I wrote method what takes care about that. See:
.
run_method_safely(Proc.new { method1 })
run_method_safely(Proc.new { method2 })
.
The problem is when proc_obj.call is executed with error (method is missing, Webdriver - no such element found or whatever) rescue block is not executed, program is running like nothing happened.
Does anybody know how to catch errors and exceptions from Proc code?

Are you sure your sample is correct?
def safe(proc)
begin
proc.call
rescue
puts "error"
end
end
def m1
puts "m1"
raise
end
def m2
puts "m2"
end
safe(Proc.new { m1 })
safe(Proc.new { m2 })
Prints
m1
error
m2
for me.
Btw: you do not need to wrap the call in a Proc, you can pass the Method object directly.
safe(method(:m1))

I think it should be
rescue Exception => e
The default for rescue is not to catch all errors, but only those which are derived from StandardError.
Side note: I was not aware that the syntax
rescue => e
is valid. => is a binary operator, and you don't provide a left argument for this.

Related

rspec yield block, but call original

So I have the following:
foo.each do |f|
f.begin
do_stuff
do_more_stuff
end
end
And I mock the f object with an and_yield() call. I want to be able to test the begin method by passing it the original block { do_stuff do_more_stuff }, not a mock implementation.... I cant just let the begin method be called on the mock without at least stubbing it, so what do I do?
Again, an undocumented feature that i found:
allow(thing).to receive(:foo) do |_, &block|
block.call
end
le sigh....
The following worked for me:
original = thing.method(:foo)
expect(thing).to receive(:foo) do |_params|
# check params
expect(params).to include(something)
# then
original.call(params)
end

How to catch all errors in a class?

Here's what I'm trying to do:
class Foo
def foo
raise "lol noob"
end
# ... many other methods here ...
rescue StandardError => e
puts "error caught: #{e}"
end
Foo.new.foo
RuntimeError: lol noob
from (pry):45:in `foo'
As you can see, this does not work.
What I'm trying to avoid is to put a rescue block into every single method, given that they're many. Is it possible? If not, what's the best practice?
TL;DR
In Ruby, you generally have to wrap the caller with rescue, rather than the receiver.
Explanation
It's likely that you're finding this behavior surprising because you're not thinking of classes as executable code. A rescue clause in a class definition will capture exceptions raised while the class is being interpreted. Consider the following example:
class Foo
raise 'bar'
rescue
'Rescued!'
end
#=> "Rescued!"
Here, the rescue clause works because the exception is raised while the class code is executing. However, some Foo#bar method wouldn't normally get rescued by this clause (except possibly while being defined) because Foo is no longer the caller, it's the receiver.
A rescue clause on the class will catch exceptions raised when the class itself is being defined. However, to rescue within a method at run-time, you need to rescue within the caller (in this case, the #bar method) as follows:
class Foo
def bar
raise 'method exception'
rescue
'Rescued method exception.'
end
end
Foo.new.bar
#=> "Rescued method exception."
It would make no sense to have a common rescue block for a class, each method does different things right? How would you handle the variety of errors all in the same way? Error handling is just as much part of the logic as the "main" part of the method(s).
There's no silver bullet here, you rescue where you need to, and do what is needed when it is needed.
The Exceptional Ruby book may be of interest if you want to learn some common best practices.
If you're absolutely sure that the only error handling you need to do is log out errors, you can abstract away some of the repetitive error logging by defining a helper method that takes in a block and do your error handling there.
For example,
class Foo
def foo
handle_exception do
raise "lol noob"
end
end
def bar
handle_exception do
raise "rofl"
end
end
def handle_exception
yield
rescue => e
puts "error caught: #{e}"
end
end
Foo.new.foo # error caught: lol noob
Foo.new.bar # error caught: rofl
This has the benefit that later on you decide that want some alternate behavior, ie adding in a backtrace, you only have to touch one line of code:
def handle_exception
yield
rescue => e
puts "error caught: #{e}\n#{e.backtrace.join("\n")}"
end

rescuing errors in EventMachine::Deferrable

I am trying to figure out how to make the EventMachine::Deferrable callbacks not raise any exceptions. Instead of having begin ... rescue in every callback block, I am trying to wrap the block somehow with a method call so that the method rescues the exceptions:
require 'eventmachine'
def to_proc
proc
rescue Exception => e
puts "e=#{e}"
end
EventMachine::run {
d = EventMachine::DefaultDeferrable.new
f = to_proc {raise 'error'}
d.callback &f
EventMachine.next_tick {d.succeed}
}
this does not work of course. I would appreciate any help.
At the statement d.callback &f, to_proc is called. The exception you're trying to catch down at d.succeed can't be caught, because we are already outside the context of your exception handling.
I'm not actually sure what error you're trying to catch. If it's an error in what you have EventMachine doing, you can create an #errBack to catch them. If you are really trying to catch exceptions that only happen in your callbacks, then you should probably just write the exception handlers in the callbacks (for the specific exceptions you expect!).
However, if you really want to catch all errors in all procs, you need to override call in class Proc:
# Note this code hasn't been tested and is only provided as an example
class Proc
alias_method :old_call, :call
def call(*args)
begin
old_call(*args)
rescue Exception => e
# Handle exception
end
end
end
I do not recommend this approach however

Using 'return' in a Ruby block

I'm trying to use Ruby 1.9.1 for an embedded scripting language, so that "end-user" code gets written in a Ruby block. One issue with this is that I'd like the users to be able to use the 'return' keyword in the blocks, so they don't need to worry about implicit return values. With this in mind, this is the kind of thing I'd like to be able to do:
def thing(*args, &block)
value = block.call
puts "value=#{value}"
end
thing {
return 6 * 7
}
If I use 'return' in the above example, I get a LocalJumpError. I'm aware that this is because the block in question is a Proc and not a lambda. The code works if I remove 'return', but I'd really prefer to be able to use 'return' in this scenario. Is this possible? I've tried converting the block to a lambda, but the result is the same.
Simply use next in this context:
$ irb
irb(main):001:0> def thing(*args, &block)
irb(main):002:1> value = block.call
irb(main):003:1> puts "value=#{value}"
irb(main):004:1> end
=> nil
irb(main):005:0>
irb(main):006:0* thing {
irb(main):007:1* return 6 * 7
irb(main):008:1> }
LocalJumpError: unexpected return
from (irb):7:in `block in irb_binding'
from (irb):2:in `call'
from (irb):2:in `thing'
from (irb):6
from /home/mirko/.rvm/rubies/ruby-1.9.1-p378/bin/irb:15:in `<main>'
irb(main):009:0> thing { break 6 * 7 }
=> 42
irb(main):011:0> thing { next 6 * 7 }
value=42
=> nil
return always returns from method, but if you test this snippet in irb you don't have method, that's why you have LocalJumpError
break returns value from block and ends its call. If your block was called by yield or .call, then break breaks from this iterator too
next returns value from block and ends its call. If your block was called by yield or .call, then next returns value to line where yield was called
You cannot do that in Ruby.
The return keyword always returns from the method or lambda in the current context. In blocks, it will return from the method in which the closure was defined. It cannot be made to return from the calling method or lambda.
The Rubyspec demonstrates that this is indeed the correct behaviour for Ruby (admittedly not a real implementation, but aims full compatibility with C Ruby):
describe "The return keyword" do
# ...
describe "within a block" do
# ...
it "causes the method that lexically encloses the block to return" do
# ...
it "returns from the lexically enclosing method even in case of chained calls" do
# ...
I admire the answer of s12chung. Here is my little improvement of his answer. It lets avoid cluttering the context with method __thing.
def thing(*args, &block)
o = Object.new
o.define_singleton_method(:__thing, block)
puts "value=#{o.__thing}"
end
thing { return 6 * 7 }
You are looking it from the wrong point of view.
This is an issue of thing, not the lambda.
def thing(*args, &block)
block.call.tap do |value|
puts "value=#{value}"
end
end
thing {
6 * 7
}
I had the same issue writing a DSL for a web framework in ruby... (the web framework Anorexic will rock!)...
anyway, I dug into the ruby internals and found a simple solution using the LocalJumpError returned when a Proc calls return... it runs well in the tests so far, but I'm not sure it's full-proof:
def thing(*args, &block)
if block
block_response = nil
begin
block_response = block.call
rescue Exception => e
if e.message == "unexpected return"
block_response = e.exit_value
else
raise e
end
end
puts "value=#{block_response}"
else
puts "no block given"
end
end
the if statement in the rescue segment could probably look something like this:
if e.is_a? LocalJumpError
but it's uncharted territory for me, so I'll stick to what I tested so far.
I found a way, but it involves defining a method as an intermediate step:
def thing(*args, &block)
define_method(:__thing, &block)
puts "value=#{__thing}"
end
thing { return 6 * 7 }
Where is thing invoked? Are you inside a class?
You may consider using something like this:
class MyThing
def ret b
#retval = b
end
def thing(*args, &block)
implicit = block.call
value = #retval || implicit
puts "value=#{value}"
end
def example1
thing do
ret 5 * 6
4
end
end
def example2
thing do
5 * 6
end
end
end
I believe this is the correct answer, despite the drawbacks:
def return_wrap(&block)
Thread.new { return yield }.join
rescue LocalJumpError => ex
ex.exit_value
end
def thing(*args, &block)
value = return_wrap(&block)
puts "value=#{value}"
end
thing {
return 6 * 7
}
This hack allows users to use return in their procs without consequences, self is preserved, etc.
The advantage of using Thread here is that in some cases you won't get the LocalJumpError - and the return will happen in the most unexpected place (onside a top-level method, unexpectedly skipping the rest of it's body).
The main disadvantage is the potential overhead (you can replace the Thread+join with just the yield if that's enough in your scenario).

Ruby: Unwanted context in exceptions raised within an eval

There seems to be an odd discrepancy between the messages contained in Ruby Exceptions raised directly and raised from within evals. For instance, the following code:
def foo
raise "Help!"
end
puts "\nRescue foo"
begin
foo
rescue RuntimeError => e
puts e.message
end
puts "\nRescue eval 'foo'"
begin
eval "foo"
rescue RuntimeError => e
puts e.message
end
Produces the following output:
Rescue foo
Help!
Rescue eval 'foo'
./temp.rb:2:in `foo': Help!
Short of using regexps to sub it out, is there any way I can raise the exception without the context in the second case?
Thanks. I was defining my own error anyway, so that's an easy fix.
I've made a slight change, so that the superclass is initialized as well:
class MyException < RuntimeError
attr_accessor :my_message
def initialize(m)
#my_message = String.new(m)
super
end
end
(the String.new call seems to be needed to avoid getting the old behaviour again; presumably Exception.new modifies the message in-place.)
That is unusual, I've not come across that before. I can't see a way of persuading eval not to add that information, so either you do the regexp munging you mentioned, or you can define your own error type:
class MyError < RuntimeError
attr_accessor :my_message
def initialize(m)
#my_message = m.dup
super
end
end
def foo
raise MyError.new("Help!")
end
puts "\nRescue eval 'foo'"
begin
eval "foo"
rescue RuntimeError => e
puts e.my_message
end
With output:
Rescue eval 'foo'
Help!
In anything larger than a simple script, defining your own error types is good practice anyway.
(updated to fix code in line with what Chris said in his answer)

Resources