Capturing stdout

I have code that prints to stdout (using puts and/or print).
I’m loading the code from a file (pretty much the way rake handles
rakefiles) and would like to capture the output from the loaded code.
I don’t want to redirect stdout into a file or anywhere else, I need the
output in a string.

—file1.rb
puts “Output of meaningful code omitted”
—loader.rb

begin
###do some magic to get the stdout from this point on into a string
load file1.rb
###do some more magic to put stdout back where it was.
end

Has anyone a solution for this?
(Now that I think of it would StringIO do for stdout redirection?)
Cheers,
V.-

http://www.braveworld.net/riva

2006/5/17, Damphyr [email protected]:

begin
###do some magic to get the stdout from this point on into a string
load file1.rb
###do some more magic to put stdout back where it was.
end

Has anyone a solution for this?

You can use popen but then your code is in another process.

(Now that I think of it would StringIO do for stdout redirection?)

Yes, but you then must explicitely use a receiver with those puts
statements as Kernel.puts still sends to $DEFOUT.

Kind regards

robert

PS: Using Log4r may be an option, too.

Damphyr wrote:

I have code that prints to stdout (using puts and/or print).
I’m loading the code from a file (pretty much the way rake handles
rakefiles) and would like to capture the output from the loaded code.
I don’t want to redirect stdout into a file or anywhere else, I need the
output in a string.

—file1.rb
puts “Output of meaningful code omitted”
—loader.rb

begin
###do some magic to get the stdout from this point on into a string
load file1.rb
###do some more magic to put stdout back where it was.
end

How about do it this way:

s = ruby file1.rb , you don’t need to load file1.rb in .

Best Regards.

Robert K. wrote:

(Now that I think of it would StringIO do for stdout redirection?)

Yes, but you then must explicitely use a receiver with those puts
statements as Kernel.puts still sends to $DEFOUT.
Yes, but I can change Kernel#puts :slight_smile:
These files are tests, written using a simple DSL and then run just like
rake runs it’s rakefiles.
So I am loath to require receivers for puts or any other logging
facility (I am the only one in my project comfortable with Ruby,
although everyone agrees that it saves them a lot of time and trouble).
popen was my obvious choice (it’s already in use in this whole mess) but
I was wondering if there was another way.
Oh, well.
Cheers,
V.-


http://www.braveworld.net/riva

2006/5/17, Damphyr [email protected]:

Yes, but I can change Kernel#puts :slight_smile:

You can use a simple mock method for this. See

http://groups.google.com/group/comp.lang.ruby/msg/cb4aeb65311e3a8e

The original method is restored on exit.

Cheers

robert

Daniel H. wrote:

2006/5/17, Damphyr [email protected]:

begin
###do some magic to get the stdout from this point on into a string
load file1.rb
###do some more magic to put stdout back where it was.
end

Has anyone a solution for this?

require ‘stringio’
stdout = StringIO.new
$stdout = stdout
load “file1.rb”
$stdout = STDOUT
stdout.rewind
puts “got: #{stdout.read}” # => got: Output of meaningful code omitted

– Daniel

I am wondering whether Ruby has something similar to C++ stringstream,
and you give the answer. It is happy to see it.

Best regards.

uncutstone

2006/5/17, Damphyr [email protected]:

begin
###do some magic to get the stdout from this point on into a string
load file1.rb
###do some more magic to put stdout back where it was.
end

Has anyone a solution for this?

require ‘stringio’
stdout = StringIO.new
$stdout = stdout
load “file1.rb”
$stdout = STDOUT
stdout.rewind
puts “got: #{stdout.read}” # => got: Output of meaningful code omitted

– Daniel

Here’s another alternative.

Create a string object to receive the output.

dest = ‘’

Add a write method to this string object.

def dest.write(data); self << data; end

old_stdout, $stdout = $stdout, dest

Invoke code that uses puts.

Restore stdout.

$stdout = old_stdout

###do some magic to get the stdout from this point on into a string

All you have to do is assign a different IO Object to the global
$stdout variables and Kernel.puts will write to that IO object.

The real standard out of the process will be available in the STDOUT
constant, in case you need definate access to it, though you’d
probably want to save a copy of the original value of $stdout, you
never know…

old_stdout=$stdout
$stdout=File.new(…)

Do a bunch of stuff that shouldn’t log to the console

$stdout=old_stdout # everything back to normal…

same applies to $stderr STDERR

-tim

Mark V. wrote:

Here’s another alternative.

Create a string object to receive the output.

dest = ‘’

Add a write method to this string object.

def dest.write(data); self << data; end

old_stdout, $stdout = $stdout, dest

Invoke code that uses puts.

Restore stdout.

$stdout = old_stdout

I think this is what duck type means. It’s really a good example of duck
type, isn’t it?

Best regards.

uncutstone

Quoting [email protected], on Wed, May 17, 2006 at 07:49:34PM +0900:

begin
###do some magic to get the stdout from this point on into a string
load file1.rb
###do some more magic to put stdout back where it was.
end

Has anyone a solution for this?
(Now that I think of it would StringIO do for stdout redirection?)

Yes,

% ruby -rstringio -e’$stdout = StringIO.new; puts “hello”; $stderr.puts
$stdout.string’
hello

Eric H. wrote:

On May 17, 2006, at 5:26 AM, Mark V. wrote:

$stdout = stdout

Add a write method to this string object.

def dest.write(data); self << data; end

How is this better than using StringIO?

IMHO, by using StringIO, you pay for something useless in this case but
maybe usefule anywhere else. I mean StringIO has many methods(e.g.
read,close,rewind) besides write , but “def dest.write…” has just
the function you want. You just pay for what you want. Isn’t it better?

Best regards,

uncutstone

On May 17, 2006, at 12:10 PM, uncutstone wu wrote:

but
maybe usefule anywhere else. I mean StringIO has many methods(e.g.
read,close,rewind) besides write , but “def dest.write…” has just
the function you want.

You’re confusing unused with useless. I almost never use Hash#index
but that doesn’t make it useless.

You just pay for what you want. Isn’t it better?

No. Using StringIO is more robust and more maintainable than using a
String with custom methods. If I want to puts or print then I have
to add those methods. If I just used StringIO I won’t have to do
anything.

I’ve found that having to maintain custom code is usually more
expensive than reusing what’s available.


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

On 5/17/06, Eric H. [email protected] wrote:

No. Using StringIO is more robust and more maintainable than using a
String with custom methods. If I want to puts or print then I have
to add those methods. If I just used StringIO I won’t have to do
anything.

You don’t have to add a puts method to the String object in order to
have puts calls append to it. puts ends up calling write. I assume
print does the same, but I’m not sure.

On May 17, 2006, at 5:26 AM, Mark V. wrote:

$stdout = stdout

Add a write method to this string object.

def dest.write(data); self << data; end

How is this better than using StringIO?


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

On May 17, 2006, at 1:41 PM, Mark V. wrote:

print does the same, but I’m not sure.
The Kernel methods have this behavior, yes, but this is not a general
solution.

$ ruby
s = ‘’
def s.write(d) self << d; end
$stdout = s
$stdout.puts ‘hi’
-:4: private method `puts’ called for “”:String (NoMethodError)


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

Mark V. wrote:

On 5/17/06, Eric H. [email protected] wrote:

No. Using StringIO is more robust and more maintainable than using a
String with custom methods. If I want to puts or print then I have
to add those methods. If I just used StringIO I won’t have to do
anything.

You don’t have to add a puts method to the String object in order to
have puts calls append to it. puts ends up calling write. I assume
print does the same, but I’m not sure.

Yes, print does the same.
main.rb:
strio = “”
def strio.write(data)
self << data
end
$stdout = strio
load ‘expansion.rb’
$stdout = STDOUT
puts “Get: #{strio}”
expansion.rb
print “hello”
result:
Get: hello