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.

Always use reopen as a last resort.

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

···

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.

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.

···

--
Posted via http://www.ruby-forum.com/\.

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

···

2009/5/20 Eric Hodel <drbrain@segment7.net>:

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

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

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

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

···

On May 19, 2009, at 23:14, Robert Klemme wrote:

2009/5/20 Eric Hodel <drbrain@segment7.net>:

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

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

Yes - until you reassign any of them. :slight_smile:

Kind regards

  robert

···

On 20.05.2009 21:01, Eric Hodel wrote:

On May 19, 2009, at 23:14, Robert Klemme wrote:

2009/5/20 Eric Hodel <drbrain@segment7.net>:

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

Robert Klemme 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.

···

--
Posted via http://www.ruby-forum.com/\.

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.

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

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 21, 2009, at 21:27, Robert Klemme wrote:

On 20.05.2009 21:01, Eric Hodel wrote:

On May 19, 2009, at 23:14, Robert Klemme wrote:

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

···

On May 22, 2009, at 00:35, Brian Candler wrote:

Robert Klemme 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.

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

Kind regards

  robert

···

On 22.05.2009 17:57, Eric Hodel wrote:

On May 21, 2009, at 21:27, Robert Klemme wrote:

On 20.05.2009 21:01, Eric Hodel wrote:

They happen to be the same object though:
$ ruby -e 'p $stdout.object_id, $defout.object_id'
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>]

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