I want to redirect stderr to StringIO.

E

ErMaker

[Note: parts of this message were removed to make it a legal post.]
TypeError: can't convert StringIO into String
from (irb):1:in `reopen'
from (irb):1=> #<IO:0x2a81630>

StringIO also do as IO, but IO#reopen fails.

I want to redirect stderr to StringIO, but it doesn't work.
 
R

Robert Klemme

2009/5/20 Eric Hodel said:

I am not sure I agree. Actually, if you want the redirection to be
permanent for sub processes you have to use $stdout.reopen. And this
is not a "last resort" but the proper solution.

Btw, in 1.8 there is also $defout - I believe _that- is the stream
used by Kernel#puts and the like in those versions:

08:13:00 ~$ ruby -r stringio -e 'puts 1; $defout=3DStringIO.new; puts 2'
1
-e:1: warning: $defout is obsolete; use $stdout instead
08:13:30 ~$

Cheers

robert


--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
B

Brian Candler

ErMaker said:
TypeError: can't convert StringIO into String
from (irb):1:in `reopen'
from (irb):1
=> #<IO:0x2a81630>

StringIO also do as IO, but IO#reopen fails.

I want to redirect stderr to StringIO, but it doesn't work.

The problem is that a StringIO cannot exist in the O/S's file descriptor
table. STDERR.reopen(...) at the low level does a dup() or dup2() to
copy one file descriptor to another.

You have two options:

(1) $stderr = StringIO.new

Then any program which writes to $stderr will be fine. But anything
which writes to STDERR will still go to file descriptor 2 (that is, your
process' stderr file)

(2) reopen STDERR with something which exists in the O/S file descriptor
table: e.g. a file or a pipe.

So for example, you can fork and connect a pipe to the child process'
STDERR, and then in the parent have a thread which reads from this and
copies all data read into a StringIO object. Anything written to STDERR
in the child process will be collected into the StringIO via the pipe.

See open3.rb in the standard library for an example of how to do this.
 
E

Eric Hodel

I am not sure I agree. Actually, if you want the redirection to be
permanent for sub processes you have to use $stdout.reopen. And this
is not a "last resort" but the proper solution.

Most of the time people capture IO from sub processes via Kernel#` or
IO::popen instead of handling the sub process themselves. Ruby's nice
features make use of #reopen an exceptional circumstance, but there
are times where it's appropriate.
Btw, in 1.8 there is also $defout - I believe _that- is the stream
used by Kernel#puts and the like in those versions:

08:13:00 ~$ ruby -r stringio -e 'puts 1; $defout=StringIO.new; puts 2'
1
-e:1: warning: $defout is obsolete; use $stdout instead

This warning says otherwise. They happen to be the same object though:

$ ruby -e 'p $stdout.object_id, $defout.object_id'
97260
97260
 
R

Robert Klemme

Most of the time people capture IO from sub processes via Kernel#` or
IO::popen instead of handling the sub process themselves. Ruby's nice
features make use of #reopen an exceptional circumstance, but there
are times where it's appropriate.

You do not make that point on the blog entry which provoked my remark.
(I wanted to place it there but comments are closed.)
This warning says otherwise.

Please do not let yourself be distracted by the warning. The crucial
point is that after $defout has been reassigned the "2" does not appear
any more on the screen => this is the object which is used by #puts.
They happen to be the same object though:

$ ruby -e 'p $stdout.object_id, $defout.object_id'
97260
97260

Yes - until you reassign any of them. :)

Kind regards

robert
 
B

Brian Candler

Robert said:
Please do not let yourself be distracted by the warning. The crucial
point is that after $defout has been reassigned the "2" does not appear
any more on the screen => this is the object which is used by #puts.

Just do what the warning says, and use $stdout instead of $defout:

$ ruby -r stringio -e 'puts 1; $stdout=StringIO.new; puts 2'
1
$

However this doesn't help the OP who wanted to redirect STDERR. You can
redirect $stderr, but lots of code writes to STDERR instead of $stderr.
 
E

Eric Hodel

Please do not let yourself be distracted by the warning. The
crucial point is that after $defout has been reassigned the "2" does
not appear any more on the screen => this is the object which is
used by #puts.

Other than the warning, the behavior is the same with $stdout and
$defout as they are the same variable.
Yes - until you reassign any of them. :)

If you reassign either of them they're still the same object:

$ ruby -r stringio -e '$stdout=StringIO.new; $stderr.puts [$stdout,
$defout].inspect'
[#<StringIO:0x28a50>, #<StringIO:0x28a50>]

From io.c:

rb_define_hooked_variable("$stdout", &rb_stdout, 0, stdout_setter);
[...]
rb_define_hooked_variable("$defout", &rb_stdout, 0, defout_setter);
 
E

Eric Hodel

Just do what the warning says, and use $stdout instead of $defout:

$ ruby -r stringio -e 'puts 1; $stdout=StringIO.new; puts 2'
1
$

However this doesn't help the OP who wanted to redirect STDERR. You
can
redirect $stderr, but lots of code writes to STDERR instead of
$stderr.

Per the URL in my earlier message, this software is wrong and bugs
should be filed.
 
R

Robert Klemme

On 20.05.2009 21:01, Eric Hodel wrote:
Yes - until you reassign any of them. :)

If you reassign either of them they're still the same object:

$ ruby -r stringio -e '$stdout=StringIO.new; $stderr.puts [$stdout,
$defout].inspect'
[#<StringIO:0x28a50>, #<StringIO:0x28a50>]

Oh, I wasn't aware of this. Thank you for the education!

Kind regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,818
Latest member
SapanaCarpetStudio

Latest Threads

Top