$stderr.reopen bug?

Hi,
I'm working through what seems like it should be a simple operation,
re-routing STDERR to point elsewhere. I can do the following

$stderr.reopen("/dev/null")

which works fine. But what I'd like to do is capture that output, so I
figured StringIO would be the way to go. According to the docs for IO#reopen
it can take an IO object as it's only parameter, and use that to re-open,
but when I do the following

require 'stringio'
str_io = StringIO.new
$stderr.reopen(str_io)

I get

TypeError: can't convert StringIO into String

any ideas? Is the documentation just wrong, and it can only take a string
arg? Or will it take only a File IO object?

···

--
===Tanner Burson===
tanner.burson@gmail.com
http://tannerburson.com <---Might even work one day...

Tanner Burson wrote:

Hi,
I'm working through what seems like it should be a simple operation,
re-routing STDERR to point elsewhere. I can do the following

$stderr.reopen("/dev/null")

which works fine. But what I'd like to do is capture that output, so I
figured StringIO would be the way to go. According to the docs for IO#reopen
it can take an IO object as it's only parameter, and use that to re-open,
but when I do the following

require 'stringio'
str_io = StringIO.new
$stderr.reopen(str_io)

I get

TypeError: can't convert StringIO into String

any ideas? Is the documentation just wrong, and it can only take a string
arg? Or will it take only a File IO object?

You'll need an IO object because, behind the scenes, IO.reopen grabs the fileno from the object and uses the dup2() function (at least, on *nix).

The StringIO#fileno method exists, but returns nil, since there is no associated fileno with a StringIO object. Actually, I don't even think it gets that far. I suspect it's choking on the rb_io_get_io() internal function.

Whether or not this could be made to work with StringIO, I'm not sure.

Regards,

Dan

$stderr = str_io

$stderr.puts 'hi'
warn 'warning'

$stderr.rewind
puts $stderr.read

···

On Oct 24, 2005, at 1:16 PM, Tanner Burson wrote:

Hi,
I'm working through what seems like it should be a simple operation,
re-routing STDERR to point elsewhere. I can do the following

$stderr.reopen("/dev/null")

which works fine. But what I'd like to do is capture that output, so I
figured StringIO would be the way to go. According to the docs for IO#reopen
it can take an IO object as it's only parameter, and use that to re-open,
but when I do the following

require 'stringio'
str_io = StringIO.new
$stderr.reopen(str_io)

I get

TypeError: can't convert StringIO into String

any ideas?

--
Eric Hodel - drbrain@segment7.net - http://segment7.net
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

Tanner Burson wrote:
> Hi,
> I'm working through what seems like it should be a simple operation,
> re-routing STDERR to point elsewhere. I can do the following
>
> $stderr.reopen("/dev/null")
>
> which works fine. But what I'd like to do is capture that output, so I
> figured StringIO would be the way to go. According to the docs for
IO#reopen
> it can take an IO object as it's only parameter, and use that to
re-open,
> but when I do the following
>
> require 'stringio'
> str_io = StringIO.new
> $stderr.reopen(str_io)
>
> I get
>
> TypeError: can't convert StringIO into String
>
> any ideas? Is the documentation just wrong, and it can only take a
string
> arg? Or will it take only a File IO object?

You'll need an IO object because, behind the scenes, IO.reopen grabs the
fileno
from the object and uses the dup2() function (at least, on *nix).

The StringIO#fileno method exists, but returns nil, since there is no
associated fileno with a StringIO object. Actually, I don't even think it
gets
that far. I suspect it's choking on the rb_io_get_io() internal function.

I think its passing rb_io_get_io() clean, but returning that StringIO isn't
a "true" enough IO object, so it trys to treat the StringIO parameter as a
filename to reopen with. I was hoping there was a way around this.

Whether or not this could be made to work with StringIO, I'm not sure.

Well thanks anyway :slight_smile: Good to know it wasn't something I was doing anyway.

Regards,

···

On 10/24/05, Daniel Berger <Daniel.Berger@qwest.com> wrote:

Dan

--
===Tanner Burson===
tanner.burson@gmail.com
http://tannerburson.com <---Might even work one day...

I tried this approach first, and it didn't seem to accomplish anything (IRB
dump below)

irb(main):007:0> require 'stringio'
=> false
irb(main):008:0> str_io = StringIO.new("")
=> #<StringIO:0x402f8df8>
irb(main):009:0> $stderr = str_io
=> #<StringIO:0x402f8df8>
irb(main):010:0> `asdf` #bad command, dumps to stderr
(irb):10: command not found: asdf
=> ""
irb(main):011:0> $stderr.rewind
=> 0
irb(main):012:0> puts $stderr.read

=> nil
irb(main):013:0>

as compared to the version reopening as file:

irb(main):001:0> require 'stringio'
=> true
irb(main):002:0> $stderr.reopen('/dev/null','w+')
=> #<IO:/dev/null>
irb(main):003:0> `asdf` #bad command again
=> ""

any idea why there is such a difference between the two?

···

On 10/24/05, Eric Hodel <drbrain@segment7.net> wrote:

On Oct 24, 2005, at 1:16 PM, Tanner Burson wrote:

> Hi,
> I'm working through what seems like it should be a simple operation,
> re-routing STDERR to point elsewhere. I can do the following
>
> $stderr.reopen("/dev/null")
>
> which works fine. But what I'd like to do is capture that output, so I
> figured StringIO would be the way to go. According to the docs for
> IO#reopen
> it can take an IO object as it's only parameter, and use that to re-
> open,
> but when I do the following
>
> require 'stringio'
> str_io = StringIO.new
> $stderr.reopen(str_io)
>
> I get
>
> TypeError: can't convert StringIO into String
>
> any ideas?

$stderr = str_io

$stderr.puts 'hi'
warn 'warning'

$stderr.rewind
puts $stderr.read

--

Eric Hodel - drbrain@segment7.net - http://segment7.net
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

--
===Tanner Burson===
tanner.burson@gmail.com
http://tannerburson.com <---Might even work one day...

Tanner Burson wrote:

I tried this approach first, and it didn't seem to accomplish anything (IRB
dump below)

irb(main):007:0> require 'stringio'
=> false
irb(main):008:0> str_io = StringIO.new("")
=> #<StringIO:0x402f8df8>
irb(main):009:0> $stderr = str_io
=> #<StringIO:0x402f8df8>
irb(main):010:0> `asdf` #bad command, dumps to stderr
(irb):10: command not found: asdf
=> ""
irb(main):011:0> $stderr.rewind
=> 0
irb(main):012:0> puts $stderr.read

=> nil
irb(main):013:0>

as compared to the version reopening as file:

irb(main):001:0> require 'stringio'
=> true
irb(main):002:0> $stderr.reopen('/dev/null','w+')
=> #<IO:/dev/null>
irb(main):003:0> `asdf` #bad command again
=> ""

any idea why there is such a difference between the two?

I have not a complete answer (I'd need to look a irb source), but an hint:

irb(main):001:0> warn 'bouh'
bouh
=> nil
irb(main):002:0> `bouh`
(irb):2: command not found: bouh
=> ""

The two messages are not formated the same way, so I suspect
they are not sent to the same "stderr".
Actually, the line "command not found: bouh" is the answer
from the shell, and the warning is processed inside Ruby.
Maybe $stderr assignment is only valid for ruby output.
If I'm not wrong:
  * if you reopen $stderr, you manipulate the original *file*
    in /dev/stderr, therefore the shell will send its error
    to the same file as Ruby
  * but if you assign $stderr, the file /dev/stderr doesn't
    change, only the "file" Ruby errors are sent to does.
I'm not completely sure it works that way, though...

Hi,

At Tue, 25 Oct 2005 06:24:04 +0900,
Tanner Burson wrote in [ruby-talk:162357]:

I tried this approach first, and it didn't seem to accomplish anything (IRB
dump below)

First of all, StringIO is a process internal object, so it
can't be passed to other processes.

unless f = IO.popen("-")
  STDERR.reopen(STDOUT)
  exec "nosuchcommand"
end
p f.read #=> "-e:1:in `exec': No such file or directory - nosuchcommand (Errno::ENOENT)\n\tfrom -e:1\n"

···

--
Nobu Nakada

You really want open3:

require 'open3'

stdin, stdout, stderr = Open3.popen3('your command')

···

On Oct 24, 2005, at 2:24 PM, Tanner Burson wrote:

On 10/24/05, Eric Hodel <drbrain@segment7.net> wrote:

$stderr = str_io

$stderr.puts 'hi'
warn 'warning'

$stderr.rewind
puts $stderr.read

I tried this approach first, and it didn't seem to accomplish anything (IRB
dump below)

irb(main):007:0> require 'stringio'
=> false
irb(main):008:0> str_io = StringIO.new("")
=> #<StringIO:0x402f8df8>
irb(main):009:0> $stderr = str_io
=> #<StringIO:0x402f8df8>
irb(main):010:0> `asdf` #bad command, dumps to stderr
(irb):10: command not found: asdf
=> ""
irb(main):011:0> $stderr.rewind
=> 0
irb(main):012:0> puts $stderr.read

=> nil
irb(main):013:0>

as compared to the version reopening as file:

irb(main):001:0> require 'stringio'
=> true
irb(main):002:0> $stderr.reopen('/dev/null','w+')
=> #<IO:/dev/null>
irb(main):003:0> `asdf` #bad command again
=> ""

any idea why there is such a difference between the two?

--
Eric Hodel - drbrain@segment7.net - http://segment7.net
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

Hi,

At Tue, 25 Oct 2005 06:24:04 +0900,
Tanner Burson wrote in [ruby-talk:162357]:
> I tried this approach first, and it didn't seem to accomplish anything (IRB
> dump below)

First of all, StringIO is a process internal object, so it
can't be passed to other processes.

Makes perfect sense. I wasn't aware that I was re-assigning the
STDERR for all processes and not just the current Ruby process.
Thanks.

···

On 10/24/05, nobu.nokada@softhome.net <nobu.nokada@softhome.net> wrote:

unless f = IO.popen("-")
  STDERR.reopen(STDOUT)
  exec "nosuchcommand"
end
p f.read #=> "-e:1:in `exec': No such file or directory - nosuchcommand (Errno::ENOENT)\n\tfrom -e:1\n"

--
Nobu Nakada

--
===Tanner Burson===
tanner.burson@gmail.com
http://tannerburson.com <---Might even work one day...