Ruby: Unwanted context in exceptions raised within an eval - ruby

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)

Related

Could we rescue, raise and rescue the same error again using exception hierarchy syntax in ruby?

I would like the exceptions to be rescued, raised and rescued again using exception hierarchy syntax like the below snippet..
class InnerCustomError < StandardError
def initialize(msg = "inner")
super
end
end
class OuterCustomError < StandardError
def initialize(msg = "outer")
super
end
end
begin
raise InnerCustomError
rescue InnerCustomError
raise OuterCustomError
rescue OuterCustomError, StandardError => e
e.message
end
but this raises ==> OuterCustomError (outer)
why is this behaviour? Instead I would like it to be rescued ..
I understand nested begin end blocks like below is used to achieve the same,
begin
begin
raise InnerCustomError
rescue InnerCustomError
raise OuterCustomError
end
rescue OuterCustomError, StandardError => e
e.message
end
also I understand there are performance impacts with this idea but I would like to understand how is the former interpreted?
but this raises OuterCustomError. Why is this behaviour?
Because that's how this construct works. The first matching rescue is selected as a handler for the exception and the result of this handling will be the result of the begin/rescue. If the handler raises and you want to catch that new exception, you need to add another layer of begin/rescue, exactly like you show in the last snippet.
It is described in the documentation here.

What is the significance of the provided code in Ruby?

I am new to Ruby. What I understood from below code that a New class MyClass is created with in the ABC module. What #1 to #4 is doing. Is this throwing different exceptions which is a subtype of CommonError?
class ABC::MyClass
class AException < CommonError; end #1
class BException < CommonError; end #2
class CFailure < CommonError; end #3
class DException < CommonError; end #4
include ABC::Something
# ::::::::::::::::::::::::::::::::::::
end
class CommonError < Exception
end
That's just defining specific exceptions that can, presumably, be used within the code somewhere else, as in:
raise AException, "Something went wrong!"
This means you can rescue those later:
begin
do_stuff!
rescue AException => e
puts "Uh oh, AException went off! Those are super bad!"
puts e # The message supplied in the raise call
end
The reason for CommonError is to act as a base-class for all these other exceptions. The argument to rescue is actually not a specific class, but a class and all subclasses, so if you rescue CommonError you get to capture all of these and potentially others defined elsewhere.

Ruby - Proc.call - catching exceptions

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.

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

Rescue given anonymous module instead of exception class

We can put a class or module after a rescue statement, but in the code below, I see a method following rescue, which does not fit into this pattern. How is it working and how is it producing the output it has been designed to show?
def errors_with_message(pattern)
# Generate an anonymous "matcher module" with a custom threequals
m = Module.new
(class << m; self; end).instance_eval do
define_method(:===) do |e|
pattern === e.message
end
end
m
end
puts "About to raise"
begin
raise "Timeout while reading from socket"
rescue errors_with_message(/socket/)
puts "Ignoring socket error"
end
puts "Continuing..."
Output
About to raise
Ignoring socket error
Continuing...
Rescue requires a class or a module, true. So, that method creates an anonymous module with special behaviour. You see, when rescue searches for a handler, it applies === operator to exception classes/modules you provided, passing as an argument the actual exception.
begin
# do something
rescue MyCustomError
# process your error
rescue StandardError
# process standard error
end
So, if StandardError (or one of its descendants) was raised, the first handler will be skipped and second handler will be matched.
Now, the module from errors_with_message is special. It redefines threequals operator to match on exception message. So, if an error was raised and its message contains word "socket", this handler will match. Cool trick, huh?

Resources