How does `rescue $!` work? - ruby

I know that the global variable $! holds the most recent exception object, but I am having confusion with the syntax below. Can anyone help me understand the following syntax?
rescue $!

This construct prevents exception from stopping your program and bubbling up the stack trace. It also returns that exception as a value, which can be useful.
a = get_me_data rescue $!
After this line, a will hold either requested data or an exception. You can then analyze that exception and act accordingly.
def get_me_data
raise 'No data for you'
end
a = get_me_data rescue $!
puts "Execution carries on"
p a
# >> Execution carries on
# >> #<RuntimeError: No data for you>
More realistic example
lines = File.readlines(filename) rescue $!
You either get the lines or the error (if file doesn't exist, you don't have permissions, etc). In any case, execution doesn't stop.

Related

What is block_singleton_method in ruby ? why am i getting this error while exiting

below is the code which is called by the gtk closing action -->
def on_main_window_destroy(object)
begin
$client.send(':exit')
Thread.kill $client.response
rescue
puts 'exiting'
end
Thread.kill $receiving_message
Gtk.main_quit()
exit
end
which results in this output.
app.rb:81:in `exit': exit
from app.rb:81:in `on_main_window_destroy'
from /home/user/.gem/ruby/2.4.0/gems/gobject-introspection-3.1.8/lib/gobject-introspection/loader.rb:110:in `invoke'
from /home/user/.gem/ruby/2.4.0/gems/gobject-introspection-3.1.8/lib/gobject-introspection/loader.rb:110:in `block in define_singleton_method'
from app.rb:97:in `<main>'
the program works fine .. and it doesn't create a mess for me .. but i want to know the reasons for these errors so that i can handle it.
The Kernel#exit raises an exception to terminate the program, that looks like be the exception message you're asking about:
Initiates the termination of the Ruby script by raising the SystemExit exception. This exception may be caught.
As for the "block in define_singleton_method" part of the stack trace, while ruby has a define_singleton_method, if you look at line 110 of that file specified, you'll see that the method you are in is also called define_singleton_method and you are inside a block in that method:
def define_singleton_method(klass, name, info)
# ...
singleton_class.__send__(:define_method, name) do |*arguments, &block|
arguments, block = prepare.call(arguments, &block) # <<< Line 110
# ...
end
end
I'm not sure why you're actually seeing that output instead of just exiting silently like you normally would, a possibility is that somewhere in the code, something is just rescuing the base Exception, instead of StandardError, which is generally a bad idea, though they may be just logging/outputting and re-raising it (which as seen in some of those answers, is OK), it's all just speculation without digging around a lot further into the code (it might not even be in this gem)

Ruby Programming: 'gets' execution expired Timeout.timeout error

I have constructed a very simple Ruby program whilst exploring the Timeoutmodule, using this site as a guide.
print "\nEnter Input:"
require 'timeout'
Timeout::timeout(5) do
input = gets.chomp
end
print "\nEXITING\n"
When I run the script, it prompts the user for input, however after 5 seconds, instead of simply printing "EXITING" and promptly terminating as it logically should, it instead crashes, returning the error:
'gets': execution expired (Timeout::Error)
I am wondering why this is, and how this error could be avoided whilst the script waits for user input for 5 seconds before terminating regardless.
Thanks in advance.
Please see the documentation for the Module Timeout
It clearly states that it performs an operation in a block, raising an error if it takes longer than sec seconds to complete.
To get your desired output, you can use a rescue block to rescue the Timeout::Error and then show your EXITING message:
require 'timeout'
print "\nEnter Input:"
begin
Timeout::timeout(5) do
input = gets.chomp
end
rescue Timeout::Error => e
print "\nEXITING\n"
end

Why is ensure clause not called when retrying? [duplicate]

This question already has answers here:
Ruby does not 'ensure' when I 'retry' in 'rescue'
(2 answers)
Closed 8 years ago.
Here's a snippet
def take_resource
puts "resource taken"
end
def free_resource source
puts "resource freed from #{source}"
end
def do_stuff
tries = 0
begin
take_resource
raise 'oops'
rescue
if tries < 3
tries += 1
free_resource 'rescue'
retry
end
raise
ensure
free_resource 'ensure'
end
end
do_stuff
# ~> -:13:in `do_stuff': oops (RuntimeError)
# ~> from -:28:in `<main>'
# >> resource taken
# >> resource freed from rescue
# >> resource taken
# >> resource freed from rescue
# >> resource taken
# >> resource freed from rescue
# >> resource taken
# >> resource freed from ensure
Here we see that ensure clause is not invoked when we retry the block. Why is that? Is there a logical explanation to this? I thought that ensure is called ensure for a reason: it always runs. Well, it turned out that I was wrong.
And while we're on it: do you know about other gotchas in this area (exception handling)?
ensure is called when the block is exited, whether via an exception or normally. retry merely transfers the execution point to the start of the block, hence you're still in the block, and ensure isn't called.
Consider that ensure exists to help with cleaning up resources when exiting the block. If you're still in the block, then presumably you're still using the resources.
This is the expected behaviour.
These keywords are described in detail in the Programming Ruby book (http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_exceptions.html)

Equivalent to Perl's END block in Ruby

Is there a Perl equivalent END block in Ruby? In Perl, if I specify an END block, the code in that block will get executed no matter where the program bails out. It is great functionality for closing open file handles. Does Ruby support similar functionality? I tried Ruby's "END{}" block but that doesnt seem to get called if I had an exit in the code due to an error.
Thanks!
Use at_exit, which will run regardless of whether an exception was raised or not:
at_exit { puts 'exited!' }
raise
prints "exited" as expected.
You should only consider this if you cannot use an ensure, as at_exit causes logic to reside far away from where the actual exit occurs.
Yes. A block may have an 'ensure' clause. Here's an example:
begin
# This will cause a divide by zero exception
puts 3 / 0
rescue Exception => e
puts "An error occurred: #{e}"
ensure
puts "I get run anyway"
end
Running this produces:
An error occurred: divided by 0
I get run anyway

How to create an exit message

Is there a one line function call that quits the program and displays a message? I know in Perl it's as simple as:
die("Message goes here")
I'm tired of typing this:
puts "Message goes here"
exit
The abort function does this. For example:
abort("Message goes here")
Note: the abort message will be written to STDERR as opposed to puts which will write to STDOUT.
If you want to denote an actual error in your code, you could raise a RuntimeError exception:
raise RuntimeError, 'Message goes here'
This will print a stacktrace, the type of the exception being raised and the message that you provided. Depending on your users, a stacktrace might be too scary, and the actual message might get lost in the noise. On the other hand, if you die because of an actual error, a stacktrace will give you additional information for debugging.
I got here searching for a way to execute some code whenever the program ends.
Found this:
Kernel.at_exit { puts "sayonara" }
# do whatever
# [...]
# call #exit or #abort or just let the program end
# calling #exit! will skip the call
Called multiple times will register multiple handlers.
I've never heard of such a function, but it would be trivial enough to implement...
def die(msg)
puts msg
exit
end
Then, if this is defined in some .rb file that you include in all your scripts, you are golden.... just because it's not built in doesn't mean you can't do it yourself ;-)

Resources