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
Ruby Class Instance Variables and Inheritance
Ruby: No Such File or Directory @ Rb_Sysopen - Testfile (Errno::Enoent)
Singleton Method VS. Class Method
Using the Value of a Variable as Another Variables Name in Ruby
Can't Convert Symbol into String
How to Save Dates in Local Timezone to Db with Rails3
How to Change the Zone Offset for a Time in Ruby on Rails
Ruby Bundle Install Require: No Such Files to Load Error
Rails - Displaying Foreign Key References in a Form
Ruby on Rails: Yielding Specific Views in a Specific Places in the Layout
How to Extract the Sign of an Integer in Ruby
Ruby: Write Escaped String to Yaml
Ruby: "&& Return" VS "And Return"