I want to redirect stderr to StringIO

IO.new(2).reopen(StringIO.new)
TypeError: can’t convert StringIO into String
from (irb):1:in `reopen’
from (irb):1

IO.new(2).reopen(IO.new(1))
=> #IO:0x2a81630

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

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

On May 19, 2009, at 21:30, ErMaker wrote:

IO.new(2).reopen(StringIO.new)
TypeError: can’t convert StringIO into String
from (irb):1:in `reopen’
from (irb):1
IO.new(2).reopen(IO.new(1))
=> #IO:0x2a81630

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

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

Always use reopen as a last resort.

http://blog.segment7.net/articles/2006/08/17/stdout-vs-stdout

2009/5/20 Eric H. [email protected]:

=> #IO:0x2a81630

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

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

Always use reopen as a last resort.

http://blog.segment7.net/articles/2006/08/17/stdout-vs-stdout

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=StringIO.new; puts 2’
1
-e:1: warning: $defout is obsolete; use $stdout instead
08:13:30 ~$

Cheers

robert

On May 19, 2009, at 23:14, Robert K. wrote:

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

On 20.05.2009 21:01, Eric H. wrote:

On May 19, 2009, at 23:14, Robert K. wrote:

2009/5/20 Eric H. [email protected]:

http://blog.segment7.net/articles/2006/08/17/stdout-vs-stdout
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.

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

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.

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. :slight_smile:

Kind regards

robert

Robert K. wrote:

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.

ErMaker wrote:

IO.new(2).reopen(StringIO.new)
TypeError: can’t convert StringIO into String
from (irb):1:in `reopen’
from (irb):1

IO.new(2).reopen(IO.new(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.

On May 21, 2009, at 21:27, Robert K. wrote:

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.

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. :slight_smile:

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);

On May 22, 2009, at 00:35, Brian C. wrote:

$

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.

On 22.05.2009 17:57, Eric H. wrote:

On May 21, 2009, at 21:27, Robert K. wrote:

On 20.05.2009 21:01, Eric H. wrote:

[#StringIO:0x28a50, #StringIO:0x28a50]
Oh, I wasn’t aware of this. Thank you for the education!

Kind regards

robert