Capture failures when using Ruby open3 standard library - ruby

I'm running an external command using the Open3.popen2e function. The external command fails spectacularly halfway through. Unfortunately this also kills my ruby process that is using popen2e. What is the reason, and how can I avoid?
begin
Open3.popen2e("node mynode.js") do |i, oe|
oe.each do |ln|
puts ln.chomp
end
end
rescue => exception
puts exception.message
end
Using ruby 2.5.1 on Ubuntu

Not sure about the reason, but a non-StandardError may be raised. So, what about changing your rescue to:
rescue Exception => exception
That may give you more clues as to what is happening.

Related

Ruby rescue and abort

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?

Ruby closing program window on Windows 7

I've download Ruby using rubyinstaller. Apps closed itself after finishing executing, so i put gets at the end of it - it works, but if there is an error it closes, and I have problem with debugging. How can i prevent this?
Probably the best way is to run your Ruby program from console (command line).
An alternative hack is to wrap your main program in an exception handler:
begin
... your code here ...
rescue => exc
puts "#{exc.class}: #{exc}" # write exception message
puts exc.backtrace.join "\n" # write backtrace
gets # wait for Return
end

Using single line conditional with require/rescue

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.

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 rescue from a require "gem_name" when the gem is not installed

I'm writing a library that depend on a specific gem. I require the gem and use it in my code and everything is hunky-dory as long as the gem is installed on the user's machine. but what if it is not?!
I thought it's fine cause I can rescue from the require command and print a message to the output to inform the user about the lacking gem and finish it gracefully but I get an error!
Could you tell me how it should be done or what is wrong with this piece of code:
begin
require "some_gem"
rescue
puts "please install some_gem first!"
end
require raises a LoadError exception if it can't load the required library. However, you never rescue from LoadError anywhere, you rescue from StandardError.
If you want to rescue from LoadError, you have to say so:
begin
require 'some_gem'
rescue LoadError
puts 'please install some_gem first!'
end
Even better yet, make sure that you are actually printing the correct missing dependency:
begin
require 'some_gem'
rescue LoadError => e
raise unless e.message =~ /some_gem/
puts 'please install some_gem first!'
end
(This re-raises the exact same exception that was rescued from, in case that the exception was actually caused by some other missing library somewhere else. You wouldn't want to print misleading information, right?)
Depending on what the intended target audience for the library is and whether or not they might be scared away by a backtrace being dumped to their console, you might want to re-raise the exception in any case, instead of just swallowing it:
begin
require 'some_gem'
rescue LoadError => e
puts 'please install some_gem first!' if e.message =~ /some_gem/
raise
end
Or, you could skip the puts and instead raise an exception with the message set to what you want to say:
begin
require 'some_gem'
rescue LoadError => e
raise e.exception('please install some_gem first!') if e.message =~ /some_gem/
raise
end
Except now the exception is raised in the wrong place and thus has the wrong line number and stacktrace and thus is misleading, but that is easily fixed:
begin
require 'some_gem'
rescue LoadError => e
raise unless e.message =~ /some_gem/
friendly_ex = e.exception('please install some_gem first!')
friendly_ex.set_backtrace(e.backtrace)
raise friendly_ex
end
Now you print pretty much the same thing that you would have printed with the puts, but you have a "proper" exception that for example allows better debugging or allows a consumer of your library to rescue that exception and handle it their way, both of which would have been impossible or at least hard with your solution that just swallows the exception.
begin
require "some_gem"
rescue LoadError
puts "message"
end

Resources