How to Rescue an Eval in Ruby

How to rescue an eval in Ruby?

Well, that was easy...

It turns out that, by default, the "rescue" statement does not catch all exceptions, but only those that are subclasses of StandardError. SyntaxError is a sibling/cousin of StandardError, not a subclass of it, so the rescue statement doesn't capture it unless explicitly told to.

To have the rescue block capture all exceptions, you need to change the code to the following:

#!/usr/bin/ruby

good_str = "(1+1)"
bad_str = "(1+1" # syntax error: missing closing paren

begin
puts eval(good_str)
puts eval(bad_str)
rescue Exception => exc
puts "RESCUED!"
end

Note the change in the "rescue" line, from "rescue => exc" to "rescue Exception => exc".

Now, when you run the code, you get the desired results:

2
RESCUED!

Not able to do Class(argument) with eval in ruby

This is how I have ended up solving my problem

def check_if_correct_type(type, value)
!!eval("#{type.classify}(value)") rescue return false
true
end

Sample output for this function is below incase you are wondering if it words or not

[25] pry(main)> value = "1"
=> "1"
[26] pry(main)> !!eval("#{type.classify}(value)")
=> true
[27] pry(main)> value = "a"
=> "a"
[28] pry(main)> !!eval("#{type.classify}(value)")
ArgumentError: invalid value for Float(): "a"
from (pry):28:in `eval'
[29] pry(main)> value = "1.4"
=> "1.4"
[30] pry(main)> type = "integer"
=> "integer"
[31] pry(main)> !!eval("#{type.classify}(value)")
ArgumentError: invalid value for Integer(): "1.4"
from (pry):31:in `eval'

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

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

Ruby: Unwanted context in exceptions raised within an eval

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)

When is `eval` in Ruby justified?

The only case I know of (other than "I have this string and I want to execute it") is dynamically dealing with local and global variables. Ruby has methods to get the names of local and global variables, but it lacks methods to get or set their values based on these names. The only way to do AFAIK is with eval.

Any other use is almost certainly wrong. I'm no guru and can't state categorically that there are no others, but every other use case I've ever seen where somebody said "You need eval for this," I've found a solution that didn't.

Note that I'm talking about string eval here, by the way. Ruby also has instance_eval, which can take either a string or a block to execute in the context of the receiver. The block form of this method is fast, safe and very useful.



Related Topics



Leave a reply



Submit