Problem
You don't want the standard input, output, or error of your process to go to the default IO objects set up by the Ruby interpreter. You want them to go to other filetype objects of your own choosing.
Solution
You can assign any IO object (a File, a Socket, or what have you) to the global variables $stdin, $stdout, or $stderr. You can then read from or write to those objects as though they were the originals.
This short Ruby program demonstrates how to redirect the Kernel methods that print to standard output. To avoid confusion, I'm presenting it as a standalone Ruby program rather than an interactive irb session.[4]
[4] irb prints the result of each Ruby expression to $stdout, which tends to clutter the results in this case.
#!/usr/bin/ruby -w # ./redirect_stdout.rb require 'stringio' new_stdout = StringIO.new $stdout = new_stdout puts "Hello, hello." puts "I'm writing to standard output." $stderr.puts "#{new_stdout.size} bytes written to standard ouput so far." $stderr.puts "You haven't seen anything on the screen yet, but you soon will:" $stderr.puts new_stdout.string
Run this program and you'll see the following:
$ ruby redirect_stdout.rb 46 bytes written to standard output so far. You haven't seen anything on the screen yet, but you soon will: Hello, hello. I'm writing to standard output.
Discussion
If you have any Unix experience, you know that when you run a Ruby script from the command line, you can make the shell redirect its standard input, output, and error streams to files or other programs. This technique lets you do the same thing from within a Ruby script.
You can use this as a quick and dirty way to write errors to a file, write output to a StringIO object (as seen above), or even read input from a socket. Within a script, you can programatically decide where to send your output, or receive standard input from multiple sources. These things are generally not possible from the command line without a lot of fancy shell scripting.
The redirection technique is especially useful when you've written or inherited a script that prints text to standard output, and you need to make it capable of printing to any file-like object. Rather than changing almost every line of your code, you can just set $stdout at the start of your program, and let it run as is. This isn't a perfect solution, but it's often good enough.
The original input and output streams for a process are always available as the constants STDIN, STDOUT, and STDERR. If you want to temporarily swap one IO stream for another, change back to the "standard" standard output by setting $stdin = STDIN. Keep in mind that since the $std objects are global variables, even a temporary change affects all threads in your script.
See Also
Recipe 6.15, "Pretending a String Is a File," has much more information on StringIO
Strings
Numbers
Date and Time
Arrays
Hashes
Files and Directories
Code Blocks and Iteration
Objects and Classes8
Modules and Namespaces
Reflection and Metaprogramming
XML and HTML
Graphics and Other File Formats
Databases and Persistence
Internet Services
Web Development Ruby on Rails
Web Services and Distributed Programming
Testing, Debugging, Optimizing, and Documenting
Packaging and Distributing Software
Automating Tasks with Rake
Multitasking and Multithreading
User Interface
Extending Ruby with Other Languages
System Administration