When I use IO::popen with a non-existent command, I get an error message printed to the screen:
irb> IO.popen "fakefake"
#=> #<IO:0x187dec>
irb> (irb):1: command not found: fakefake
Is there any way I can capture this error, so I can examine from within my script?
Yes: Upgrade to ruby 1.9. If you run that in 1.9, an Errno::ENOENT will be raised instead, and you will be able to rescue it.
(Edit) Here is a hackish way of doing it in 1.8:
error = IO.pipe
$stderr.reopen error[1]
pipe = IO.popen 'qwe' # <- not a real command
$stderr.reopen IO.new(2)
error[1].close
if !select([error[0]], nil, nil, 0.1)
# The command was found. Use `pipe' here.
puts 'found'
else
# The command could not be found.
puts 'not found'
end
Related
I am going through "Ruby the Hard Way". Typing in the exercises as instructed. Got to Exercise 17 and as far as i can tell typed in correctly but when i run it get this error:
ex17.rb:5:in open': no implicit conversion of nil into String (TypeError) from ex17.rb:5:in '
Can anyone tell me what is wrong here?
put the 5 in the code below to show line 5. I think the error means it is in line 5.
This is the exercise:
from_file, to_file = ARGV
puts "Copying from #{from_file} to #{to_file}"
5 in_file = open(from_file)
indata = in_file.read
puts "The input file is #{indata.length} bytes long"
puts "Does the output file exist? #{Fileexist?(to_file)}"
puts "Ready , hit RETURN to continue, CTRL-C to abort."
$stdin.gets
out_file = open(to_file, 'w')
out_file.write(indata)
puts "Alright, all done."
out_file.close
in_file.close
I was running this on the Terminal, I ran it as >ruby ex17.rb, without submitting a filename afterwards. So, on the prompt, I should have submitted it as >ruby ex17.rb with a file name.
I'm using the Tika jar to extract metadata from Microsoft Word doc files but in the case Tika encounters a problem my rescue is not catching the error, instead the scripts exits. I'm on windows 7 with MRI Ruby 1.9.3
I could adapt the doc file but I want to avoid having this problem with future files.
How can I capture this error ?
JARPATH = "jar/tika-app-1.6.jar"
def metadata
return #metadata if defined? #metadata
switch = '-m -j'
begin
command = %Q{java -Djava.awt.headless=true -jar #{JARPATH} #{switch} "#{#path}"}
output = IO.popen(command+" 2>&1") do |io|
io.read
end
if output.respond_to?(:to_str)
#metadata = JSON.parse(output)
else
#metadata = nil
end
rescue => e
puts e
puts e.backtrace
end
end
This is the output I get
c:/Ruby193/lib/ruby/gems/1.9.1/gems/json-1.8.2/lib/json/common.rb:155:in `parse': 757: unexpected token at 'Exception in thread "main" org.apache.tika.exception.TikaException: TIKA-198: Illegal IOExce
ption from org.apache.tika.parser.microsoft.OfficeParser#1006d75 (JSON::ParserError)
at org.apache.tika.parser.CompositeParser.parse(CompositeParser.java:250)
at org.apache.tika.parser.CompositeParser.parse(CompositeParser.java:244)
at org.apache.tika.parser.AutoDetectParser.parse(AutoDetectParser.java:121)
at org.apache.tika.cli.TikaCLI$OutputType.process(TikaCLI.java:143)
at org.apache.tika.cli.TikaCLI.process(TikaCLI.java:422)
at org.apache.tika.cli.TikaCLI.main(TikaCLI.java:113)
Caused by: java.io.IOException: Invalid header signature; read 0x04090000002DA5DB, expected 0xE11AB1A1E011CFD0 - Your file appears not to be a valid OLE2 document
at org.apache.poi.poifs.storage.HeaderBlock.<init>(HeaderBlock.java:140)
at org.apache.poi.poifs.storage.HeaderBlock.<init>(HeaderBlock.java:115)
at org.apache.poi.poifs.filesystem.NPOIFSFileSystem.<init>(NPOIFSFileSystem.java:204)
at org.apache.poi.poifs.filesystem.NPOIFSFileSystem.<init>(NPOIFSFileSystem.java:163)
at org.apache.tika.parser.microsoft.OfficeParser.parse(OfficeParser.java:162)
at org.apache.tika.parser.CompositeParser.parse(CompositeParser.java:244)
... 5 more
'
from c:/Ruby193/lib/ruby/gems/1.9.1/gems/json-1.8.2/lib/json/common.rb:155:in `parse'
from C:/Users/.../tika.rb:37:in `metadata'
from C:/Users/.../index_helpers.rb:55:in `index_doc'
from index.rb:39:in `block in <main>'
from index.rb:20:in `each'
from index.rb:20:in `each_with_index'
from index.rb:20:in `<main>'
After your call to IO.popen you are passing the output from the child program to JSON.parse, regardless of whether it is valid. The exception you see is the json parser trying to parse the Java exception method, which is captured because you redirect stderr with 2>&1.
You need to check that the child process completed successfully before continuing. The simplest way is probably to use the $? special variable, which indicates the status of the last executed child process, after the call to popen. This variable is an instance if Process::Status. You could do something like this:
output = IO.popen(command+" 2>&1") do |io|
io.read
end
unless $?.success?
# Handle the error however you feel is best, e.g.
puts "Tika had an error, the message was:\n#{output}"
raise "Tika error"
end
For more control you could look at the Open3 module in the standard library. Since Tika is a Java program, another possibility might be to look into using JRuby and call it directly.
I'm writing a vim plugin using the ruby interface.
When I execute VIM::command(...), how can I detect if vim raised an error during execution of this command, so that I can skip further commands and also present a better message to the user?
Vim's global variable v:errmsg will give you the last error. If you want to check whether an error occured, you can first set it to an empty string and then check for it:
let v:errmsg = ""
" issue your command
if v:errmsg != ""
" handle the error
endif;
I'll leave it up to you to transfer this to the Ruby API. Also see :h v:errmsg from inside Vim. Other useful global variables may be:
v:exception
v:throwpoint
Edit – this should work (caution: some magic involved):
module VIM
class Error < StandardError; end
class << self
def command_with_error *args
command('let v:errmsg=""')
command(*args)
msg = evaluate('v:errmsg')
raise ::VIM::Error, msg unless msg.empty?
end
end
end
# Usage
# use sil[ent]! or the error will bubble up to Vim
begin
VIM::command_with_error('sil! foobar')
rescue VIM::Error => e
puts 'Rescued from: ' + e.message;
end
# Output
Rescued from: E492: Not an editor command: sil! foobar
When I use IO::popen with a non-existent command, I get an error message printed to the screen:
irb> IO.popen "fakefake"
#=> #<IO:0x187dec>
irb> (irb):1: command not found: fakefake
Is there any way I can capture this error, so I can examine from within my script?
Yes: Upgrade to ruby 1.9. If you run that in 1.9, an Errno::ENOENT will be raised instead, and you will be able to rescue it.
(Edit) Here is a hackish way of doing it in 1.8:
error = IO.pipe
$stderr.reopen error[1]
pipe = IO.popen 'qwe' # <- not a real command
$stderr.reopen IO.new(2)
error[1].close
if !select([error[0]], nil, nil, 0.1)
# The command was found. Use `pipe' here.
puts 'found'
else
# The command could not be found.
puts 'not found'
end
I'm trying to get simple option handling in my ruby app. Looks like OptionParser does most of what I want, though I can't figure out a way to gracefully handle unexpected arguments.
If any unexpected arguments are provided I want to treat it as if the -h argument was passed (show usage and quit). I'm not seeing any way to handle that though.
If OptionParser can't do it, is there another library I could use for easily parsing command line arguments?
There's probably a slick way to do it, but I don't know it. I've done this:
opts = OptionParser.new
...
opts.on_tail("-h", "--help",
"Show this message") do
puts opts
exit
end
begin
opts.parse!(argv)
rescue OptionParser::InvalidOption => e
puts e
puts opts
exit(1)
end
if you save below as test.rb
#/usr/bin/env ruby
require 'optparse'
test = nil
help = nil
ARGV.options {|opt|
opt.on("--test=test") {|val| test=val}
help = opt.help
begin
opt.parse!
rescue OptionParser::InvalidOption => e
puts help
end
}
and execute below in the terminal,
$./test.rb --foo
you get below.
Usage: test [options]
--test=test