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

On Mar 24, 2006, at 7:50 AM, Mark V. 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.

James Edward G. II

On 3/24/06, James Edward G. II [email protected] wrote:

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?

On 3/24/06, Mark V. [email protected] wrote:

actual = '''

sio = StringIO.new

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)


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

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

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 G. II

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs