rickyrickyrice
rickyrickyrice

Reputation: 577

Combine `STDOUT` and `STDIN` into a single `IO` object

Is there a way to create a single IO object whose read stream is the current process's STDOUT and whose write stream is the current process's STDIN?

This is similar to IO.popen, which runs a command as a subprocess and returns an IO object connected to the subprocesses standard streams. However, I don't want to run a subprocess, I want to use the current Ruby process.

Upvotes: 3

Views: 431

Answers (1)

EnabrenTane
EnabrenTane

Reputation: 7466

Is there a way to create a single IO object

No. STDIN and STDOUT are two different file descriptors. An IO represents a single FD.

You can however, make something that acts like an IO object. This probably contains a bunch of bugs as duplicating FDs is often bad.

require "forwardable"
class IOTee < IO
  extend Forwardable
  def_delegators :@in, 
    :close_read, 
    :read, 
    :read_nonblock, 
    :readchar, 
    :readlines, 
    :readpartial, 
    :sysread

  def_delegators :@out, 
    :close_write,
    :syswrite, 
    :write, 
    :write_nonblock

  def initialize(input,output)
    @in = input
    @out = output
  end
end

io = IOTee.new(STDIN,STDOUT) # You would swap these
io.puts("hi")
hi
=> nil

Depending on what you're doing there is IO#pipe and IO#reopen which could also be helpful.

http://ruby-doc.org/core-2.1.0/IO.html#method-i-reopen

http://ruby-doc.org/core-2.1.0/IO.html#method-c-pipe

I suspect that the above isn't really the problem you want to solve, but the problem you hit with your solution to the problem.

I suspect really making a pipe and reopening STDOUT and STDIN to either end is what you're really after. Combining them in a single IO object doesn't make much sense.

Also, if you were talking to yourself via STDIN and STDOUT, it would be very easy to reach a deadlock while you wait for yourself to read or write data.

Upvotes: 1

Related Questions