Forum: Ruby I want to redirect stderr to StringIO.

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
6a83f8cb125a8dfdbe544b0e5ee32f45?d=identicon&s=25 ErMaker (Guest)
on 2009-05-20 06:31
(Received via mailing list)
>> 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.
58479f76374a3ba3c69b9804163f39f4?d=identicon&s=25 Eric Hodel (Guest)
on 2009-05-20 06:39
(Received via mailing list)
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/stdou...
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2009-05-20 08:15
(Received via mailing list)
2009/5/20 Eric Hodel <drbrain@segment7.net>:
>> => #<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/stdou...

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
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2009-05-20 12:29
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.
58479f76374a3ba3c69b9804163f39f4?d=identicon&s=25 Eric Hodel (Guest)
on 2009-05-20 21:02
(Received via mailing list)
On May 19, 2009, at 23:14, Robert Klemme 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
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2009-05-22 06:28
(Received via mailing list)
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>:

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

Kind regards

  robert
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2009-05-22 09:35
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.
58479f76374a3ba3c69b9804163f39f4?d=identicon&s=25 Eric Hodel (Guest)
on 2009-05-22 17:59
(Received via mailing list)
On May 21, 2009, at 21:27, 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.

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

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);
58479f76374a3ba3c69b9804163f39f4?d=identicon&s=25 Eric Hodel (Guest)
on 2009-05-22 18:01
(Received via mailing list)
On May 22, 2009, at 00:35, Brian Candler 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.
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2009-05-24 17:30
(Received via mailing list)
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:

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

Kind regards

  robert
This topic is locked and can not be replied to.