Rescue error?

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

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

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.

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.

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