I have a custom Rakefile which calls different file tasks. Sometimes a file that is expected doesn't exist, and rake throws a RuntimeError and fails. However, I'd like to do a few things before it fails. So is there any way I could rescue a RuntimeError? Or is there some sort of a magic task which gets called before a complete fail?
I haven't run into this issue with rake myself, but you could try simply wrapping your call to the file tasks in a begin-rescue block, i.e.
begin
file_task
rescue RuntimeError => e
puts e
end
and then do your rescuing in the rescue block.
Related
I am seeing this pattern in someone else's Rakefile:
begin
sh "..."
rescue
abort
end
What's the author doing here? Why rescue if I'm going to abort anyway? Do I understand correctly that this mutes the potential shell error?
I am new to ruby and rake. As far as I understand, the sh is rake's shorthand for FileUtils.sh() (ref). And FileUtils.sh() may raise a RuntimeError (ref).
Does this mean that we are effectively throwing away the information/message in the RuntimeError and exiting rake with an error status, but without a specific error message? Is this a rake/ruby pattern? Any recommended reading?
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)
I want to avoid an error, if a require is not successfull.
I can do it with:
begin
require 'unexisting_script'
rescue LoadError
end
I tried to do the same with a one-line condition:
require 'unexisting_script' rescue LoadError
and get the error no such file to load -- unexisting_script (LoadError)
With other exceptions/commands I have no problem with a one line rescue, this works:
1 / 0 rescue ZeroDivisionError
I also tried to bracket the command, but withous success:
(require 'unexisting_script') rescue LoadError
I can put everything in one line with ;:
begin require 'unexisting_script'; rescue LoadError; end
but I'm still wondering, why the shortest version does not work.
I found some related questions, but none of them is mentioning a problem with require and rescue:
Why does this rescue syntax work?
How does one use rescue in Ruby without the begin and end block
My question:
Can I use rescue in a one-line condition with require? If yes: how? If no: Why?
You cannot specify the error class when you use rescue in postfix/oneliner notation. What rescue LoadError or rescue ZeroDivisionError means is that it will rescue a (subclass of) StandardError, and in such case, evaluate LoadError or ZeroDivisionError, which has no effect. Since ZeroDivisionError is a subclass of StandardError, it was captured, but LoadError is not, and it was not captured.
By the way, I cannot think of a use case where you want to not raise an error when a required file does not exist. Required files are dependencies, and if requiring them fails, then the program will not work correctly anyway. I feel a code smell in what you are doing. When failure of loading a file does not mess the program, that is usually when you should be using load instead of require.
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
I have this task:
task :all => ['foo', 'bar', 'announce_success']
If foo and bar don't raise exceptions, then announce_success happens. How can I have a particular task or code block execute if they do raise exceptions?
The way you have defined your tasks will cause rake to exit as soon as one of the dependencies fails/raises and exception. This is the core functionality of rake.
One way to work around though is to do something like
task :all do
task :tmp => ['foo','bar']
begin
Rake::Task[:tmp].invoke
rescue
#do something with the exception
end
end
Unfortunately that goes against the grain of Rake.
Ruby has an at_exit hook you can add a block of code to, if you want to run a bit of cleanup when Rake terminates. You can combine rake-tasks and at_exit hook like this:
task :cleanup do
at_exit {
# cleanup code here
}
end
Just make sure :cleanup is executed early in the list of dependencies.