Redirecting stdout to a String

I wrote a unit test for a method that writes to stdout. I got it to
work, but I'm not sure my approach was the best. Is there a more
recommended way to do this?

    # Create a String with a singleton write method
    # that allows it to take the place of stdout.
    actual = '''
    def actual.write(data); self << data; end
    old_stdout, $stdout = $stdout, actual

    # Invoke method to test that writes to stdout.

    $stdout = old_stdout # restore stdout

···

--
R. Mark Volkmann
Object Computing, Inc.

See the standard library, StringIO.

James Edward Gray II

···

On Mar 24, 2006, at 7:50 AM, Mark Volkmann wrote:

I wrote a unit test for a method that writes to stdout. I got it to
work, but I'm not sure my approach was the best. Is there a more
recommended way to do this?

    # Create a String with a singleton write method
    # that allows it to take the place of stdout.
    actual = '''
    def actual.write(data); self << data; end

Thanks! I have that working, but it's not clear to me how that is
better. In fact, it seems to take more code to do it that way. I now
have this.

  require 'stringio'

  sio = StringIO.new
  old_stdout, $stdout = $stdout, sio
  # Invoke method to test that writes to stdout.
  $stdout = old_stdout # restore stdout
  actual = sio.string

Am I overcomplicating this?

···

On 3/24/06, James Edward Gray II <james@grayproductions.net> wrote:

On Mar 24, 2006, at 7:50 AM, Mark Volkmann wrote:

> I wrote a unit test for a method that writes to stdout. I got it to
> work, but I'm not sure my approach was the best. Is there a more
> recommended way to do this?
>
> # Create a String with a singleton write method
> # that allows it to take the place of stdout.
> actual = '''
> def actual.write(data); self << data; end

See the standard library, StringIO.

--
R. Mark Volkmann
Object Computing, Inc.

>
> > I wrote a unit test for a method that writes to stdout. I got it to
> > work, but I'm not sure my approach was the best. Is there a more
> > recommended way to do this?
> >
> > # Create a String with a singleton write method
> > # that allows it to take the place of stdout.
> > actual = '''
> > def actual.write(data); self << data; end
>
> See the standard library, StringIO.

Thanks! I have that working, but it's not clear to me how that is
better. In fact, it seems to take more code to do it that way. I now
have this.

  require 'stringio'

  sio = StringIO.new
  old_stdout, $stdout = $stdout, sio
  # Invoke method to test that writes to stdout.
  $stdout = old_stdout # restore stdout
  actual = sio.string

Am I overcomplicating this?

--
R. Mark Volkmann
Object Computing, Inc.

I made a benchmark of both solutions, but I was surprised how small the
difference was.
StringIO is faster, as I expected. See below for results.
Apart from that I feel that stringio will have adavantages for giving you a
complete API.
But for a quick solution the singleton method seems elegant and I like it a
lot, after all
you do not require( which was not benchmarked!!!) 'stringio' and run a core
script.

But for reusable code I'll defenitely go for stringio.

Cheers
Robert

---------------------------------- 8< -------------------------------------

cat stringio.rb;ruby stringio.rb
#!/usr/bin/env ruby
   # Create a String with a singleton write method
   # that allows it to take the place of stdout.
require 'benchmark'
require 'stringio'

n = 500000
r1 = r2 = nil
Benchmark.bm do
        >bm>
        bm.report "single string" do
            actual = ''

            def actual.write(data); self << data.to_s; end
            old_stdout, $stdout = $stdout, actual
            n.times{ |i| $stdout.write i }
            $stdout = old_stdout
            r1= actual
        end # do

        bm.report "stringio " do
                 sio = StringIO.new
                 old_stdout, $stdout = $stdout, sio
                 n.times{ |i| $stdout.write i}
                 # Invoke method to test that writes to stdout.
                 $stdout = old_stdout # restore stdout
                 r2 = sio.string
        end # do
end # do

raise Exception unless r1 == r2

      user system total real
single string 1.460000 0.000000 1.460000 ( 1.823057)
stringio 1.320000 0.010000 1.330000 ( 1.828039)

···

On 3/24/06, Mark Volkmann <r.mark.volkmann@gmail.com> wrote:

On 3/24/06, James Edward Gray II <james@grayproductions.net> wrote:
> On Mar 24, 2006, at 7:50 AM, Mark Volkmann wrote:

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

I wrote a unit test for a method that writes to stdout. I got it to
work, but I'm not sure my approach was the best. Is there a more
recommended way to do this?

    # Create a String with a singleton write method
    # that allows it to take the place of stdout.
    actual = '''
    def actual.write(data); self << data; end

See the standard library, StringIO.

Thanks! I have that working, but it's not clear to me how that is
better. In fact, it seems to take more code to do it that way.

You originally asked:

Is there a more recommended way to do this?

I was just trying to answer that question.

I prefer the StringIO method because it is a full mock API, as Robert Dober said. However, if you know you will only need the one method (now and forever?!) there is probably little difference.

James Edward Gray II

···

On Mar 24, 2006, at 8:12 AM, Mark Volkmann wrote:

On 3/24/06, James Edward Gray II <james@grayproductions.net> wrote:

On Mar 24, 2006, at 7:50 AM, Mark Volkmann wrote: