On Wed, 07 May 2003 09:33:31 +0900, Florian G. Pflug wrote:

> On Wed, May 07, 2003 at 07:53:05AM +0900, Simon Strandgaard wrote:
>> I want to capture all output from [ruby, child_processes].
>> How can I do this ?
 

> You need to use $stdout.reopen(buf) here. Same for $stderr.
> 
> But since IO::reopen seems to be a quite special function (it actually
> _replaces_ its receiver - it's the only ruby function I know of that does
> this), it might be that the argument has to be of a special class (maybe
> derived from IO?).

Yes.. 


The problem is *almost* solved -  I found this (thanks paul brannan):
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&threadm=20020807095619.D4512%40atdesk.com&rnum=12&prev=/groups%3Fq%3Druby%2Bstringio%26hl%3Den%26lr%3D%26ie%3DUTF-8%26start%3D10%26sa%3DN

There seems to be some glitches where it does'nt capture all output.
I get 2 different kinds of output.. here is the first output:

> ruby main.rb
OK 1
OK stderrstdout
OK defout
OK
OK 2
OK stderr
OK stdout
OK defout
OK 3
>

The line "OK stderrstdout" is buggy..

The second output:
> ruby main.rb
OK 1
OK stderr
OK stdout
OK defout
OK 2
OK stderr
OK stdout
OK defout
OK 3
>

Running the code several times, then you will see
that it varies between first&second output.. Why ???


> cat main.rb
require 'stringio'

class Redirector
    def initialize(from, to)
        tmp = from.dup
        r, w = IO.pipe
        from.reopen(w)
        @t = Thread.new do
            begin
                loop do
                    s = r.read(1) # TODO: can I make this buffered?
                    to.write(s)
                end
            ensure
                from.reopen(tmp)
            end
        end
    end
    def stop
        @t.kill
    end
    def self.redirect(from, to)
        s = self.new(from, to)
        begin
            yield
        ensure
            s.stop
        end
    end
end

def capture
    raise unless block_given?
    a, b, c = $defout, $stderr, $stdout
    buf = StringIO.new(s = "", "w")
    rdr_serr = Redirector.new($stderr, buf)
    rdr_sout = Redirector.new($stdout, buf)
    begin
        $defout = buf
        yield
    ensure
        $defout, $stderr, $stdout = a, b, c
        rdr_serr.stop
        rdr_sout.stop
        buf.close
    end
    s.split(/\n/)
end

res = capture {
    puts "1"
    system("ruby output.rb")
    puts "2"
    puts `ruby output.rb`
    puts "3"
}
puts res.collect{|s| "OK "+s }.join("\n")
> cat output.rb
$stderr.puts "stderr"
$stdout.puts "stdout"
$defout.puts "defout"
>



The remaining question: Why does the output differs when
I run the program several times ???

--
Simon Strandgaard