"ahoward" <ahoward / fsl.noaa.gov> schrieb im Newsbeitrag
news:Pine.LNX.4.53.0305021534540.25362 / eli.fsl.noaa.gov...
> i am more confused than usual ;-)

I seems so... :-)

> ~ > cat foo.rb
> #!/usr/bin/env ruby
>
> def dump s, binding=nil
>   case s
>   when Symbol
>     STDERR.puts %Q(\t#{s} => #{eval(s.to_s, binding).inspect})
>   when String
>     STDERR.puts "\t#{s}"
>   end
> end
>
> File.open("output","w") { |f|
>
>   dump '(ORIGINAL)'
>   [:f,:$defout,:$stdout,:STDOUT].map{|sym| dump sym, binding}
>
>   puts("To the screen")
>
>   $defout.reopen f
>   dump '(REDIRECTED TO FILE)'
>   [:f,:$defout,:$stdout,:STDOUT].map{|sym| dump sym, binding}
>
>   puts("To the file")
>
>   $defout.reopen STDOUT
>   dump '(RESTORED)'
>   [:f,:$defout,:$stdout,:STDOUT].map{|sym| dump sym, binding}
>
>
>   puts("To the screen again")
> }
>
>
> > ruby foo.rb
>         (ORIGINAL)
>         f => #<File:0x40182b2c>
>         $defout => #<IO:0x401880a4>
>         $stdout => #<IO:0x401880a4>
>         STDOUT => #<IO:0x401880a4>
> To the screen
>         (REDIRECTED TO FILE)
>         f => #<File:0x40182b2c>
>         $defout => #<File:0x401880a4>
>         $stdout => #<File:0x401880a4>
>         STDOUT => #<File:0x401880a4>
>         (RESTORED)
>         f => #<File:0x40182b2c>
>         $defout => #<File:0x401880a4>
>         $stdout => #<File:0x401880a4>
>         STDOUT => #<File:0x401880a4>
>
>
> so it appears that reopening even $defout results in STDOUT and $stdout
also
> being reopened to point to a file.  in otherwords, you will never be able
to
> restore unless a copy is made prior to this.  this works like it reads:

Err, why are you surprised?  This is exactly what I would have expected
since $defout, $stdout and STDOUT initially point to the same instance.  So
it doesn't really matter on which of the instances you do issue 'reopen',
they "all" get redirected.

Redirecting should be done by assignment:

File.open("output","w") do |f|
  old_defout = $defout

  begin
    puts "to the screen"

    # redirect
    $defout = f

    puts "to the file"
  ensure
    $defout = old_defout
  end
end

This is much simpler than your solution and works without adding code to IO
classes:

> > cat redirect.rb && ruby redirect.rb && echo 'output:' && cat output
> #!/usr/bin/env ruby
>
> class IO
>   def redirect io
>     (@__self ||= []) << (clone = self.clone)
>     reopen io
>     clone
>   end
>   def restore
>     raise 'NOT REDIRECTED' unless
>       defined? @__self and not @__self.empty?
>     reopen @__self.pop
>   end
> end
>
> File.open("output","w") { |f|
>   puts("To the screen")
>
>   STDOUT.redirect f
>   puts("To the file")
>
>   STDOUT.restore
>   puts("To the screen again")
> }
>
> To the screen
> To the screen again
> output:
> To the file

Regards

    robert