Rescue error?


#1

I’m creating a gem and have been testing it on MRI, JRuby, and Rubinius.

I have a section of code which checks to see if the Linux/Unix cli
command ‘factor’ exists on the platform the gem is installed on. If it
exists I wrap some ruby around it and use it. If ‘factor’ doesn’t exists
then I create pure ruby versions of the same methods.

To do this, I invoke the ‘factor’ command. If it exists I create the
methods I want using it. If it doesn’t exists, an error is thrown which
I use a ‘rescue’ section to resolve to create pure ruby versions.

Below is code to show the use of ‘rescue’:

If the system is a RUBY_PlATFORM which has ‘factor’ (Linux/Unix)

then the line: factor 10.split(’ ') != []

will be performed with no error, and the code will proceed in sequence.

If the system doesn’t have ‘factor’ a sys error is thrown and ‘rescued’.

I test this on my Linux system by running it with the correct spelling
of ‘factor’, which outputs ‘OS versions’.

I then create a false cli command ‘factorz’ and run the code, and for
MRI (2.2.1 and 2.1.2) and Rubinius (2.5.2) a sys error is thrown and the
‘rescue’ section is invoked correctly and ‘Ruby versions’ is shown.

However, on JRuby 1.7.19, in both cases I get ‘OS versions’.

So apparently, JRuby isn’t throwing a system error when it attempts to
run a non-existent cli command, which doesn’t conform to MRI (2.2; 2.1).

1)Is this a bug in JRuby, or is this allowed behavior?

2)Is there a ‘better’ more universally transferable way to do this?

begin

# Test Operating Systems if *nix cli command 'factor' exists

`factor 10`.split(' ') != []
#`factorz 10'.split(' ') != []  # mimic nonexistent on system

# code would go here to create 'factor' coded methods

puts 'OS versions'

rescue # if ‘factor’ not in system use pure ruby versions

# code would go here to create pure ruby coded methods

puts 'Ruby versions'

end


#2

If you don’t want to do the test on Windows, then I believe you can rely
on the existence of the ‘which’ command. In that case:

system(‘which factor’)

…will return true if it’s available, and false if it’s not. This is
from my Mac, which does not have factor:

2.1.2 :003 > system(‘which ls’)
/bin/ls
=> true
2.1.2 :004 > system(‘which factor’)
=> false

Of course, this does not guarantee that the ‘factor’ executable found is
the one you want.

You could do something like this:

def factor_available?
RUBY_PLATFORM != ‘mswin’ && system(‘which factor’)
end

You might need to tweak the platform test; there are other values of
RUBY_PLATFORM that are Windows, but some of them (e.g. ‘cygwin’, and
maybe ‘mingw’?) simulate Unix so may not need to be excluded.

  • Keith

#3

Hey Keith, thanks.

Doing something like this:

if system(‘which factor’); puts ‘Yes factor’ else ‘No factor’ end

is much cleaner and transportable.

I tested it on my system with MIR (1.8.7, 2.1.2, 2.2.1), JRuby-1.7.19
and Rubinius-2.5.2, and there were no problems. I’ll try it later on my
Win7 system with Rubyinstaller rubies.

FYI, I started out using the RUBY_PLATFORM value to check against, but
soon realized I would have to know if ‘factor’ runs on all the possible
ruby platforms to make if universally transportable, so I started
checking directly for ‘factor’ being on a platform. In Unix ‘factor’ has
been standard since 1974, and in Linux and BSD since their inception, so
I’m not too concerned about possible false positives on other platforms.

https://en.wikipedia.org/wiki/Factor_(Unix)

The still open question, though, is JRuby’s non-conformist to MRI
behavior handling rescue in the original example. This can obviously
have catastrophic consequences for people expecting their MRI code to
operate the same on JRuby.


#4

open4 (gem on mri, native on jruby) will raise an error if it doesn’t
find
the executable. try something like this:

if IO.respond_to?(:popen4) #jruby
def open4(*args)
IO.popen4(*args)
end
else # mri
require ‘open4’
end

begin
open4(“monkey”)
rescue
print “monkey not available”
end