Forum: Ruby Capturing stdout

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Damphyr (Guest)
on 2006-05-17 14:50
(Received via mailing list)
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
Robert K. (Guest)
on 2006-05-17 15:18
(Received via mailing list)
2006/5/17, Damphyr <removed_email_address@domain.invalid>:
> 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
Robert K. (Guest)
on 2006-05-17 15:21
(Received via mailing list)
PS: Using Log4r may be an option, too.
Uncutstone W. (Guest)
on 2006-05-17 15:44
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.
Damphyr (Guest)
on 2006-05-17 16:00
(Received via mailing list)
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 :)
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
Robert K. (Guest)
on 2006-05-17 16:10
(Received via mailing list)
2006/5/17, Damphyr <removed_email_address@domain.invalid>:
> Yes, but I can change Kernel#puts :)

You can use a simple mock method for this. See

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

The original method is restored on exit.

Cheers

robert
Daniel H. (Guest)
on 2006-05-17 16:16
(Received via mailing list)
2006/5/17, Damphyr <removed_email_address@domain.invalid>:
>
> 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
Uncutstone W. (Guest)
on 2006-05-17 16:28
Daniel H. wrote:
> 2006/5/17, Damphyr <removed_email_address@domain.invalid>:
>>
>> 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
Mark V. (Guest)
on 2006-05-17 16:29
(Received via mailing list)
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
Tim B. (Guest)
on 2006-05-17 16:35
(Received via mailing list)
> ###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
Uncutstone W. (Guest)
on 2006-05-17 21:15
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
Sam R. (Guest)
on 2006-05-17 22:34
(Received via mailing list)
Quoting removed_email_address@domain.invalid, 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. (Guest)
on 2006-05-17 22:37
(Received via mailing list)
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. - removed_email_address@domain.invalid - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com
Uncutstone W. (Guest)
on 2006-05-17 23:09
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
Eric H. (Guest)
on 2006-05-18 00:15
(Received via mailing list)
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. - removed_email_address@domain.invalid - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com
Mark V. (Guest)
on 2006-05-18 00:44
(Received via mailing list)
On 5/17/06, Eric H. <removed_email_address@domain.invalid> 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.
Uncutstone W. (Guest)
on 2006-05-18 06:02
Mark V. wrote:
> On 5/17/06, Eric H. <removed_email_address@domain.invalid> 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
Eric H. (Guest)
on 2006-05-18 07:29
(Received via mailing list)
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. - removed_email_address@domain.invalid - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com
This topic is locked and can not be replied to.