On Thu, 22 Mar 2001, Hal E. Fulton wrote:
> Actually, Donald's question makes me think of one 
> of my own.
> Suppose I have three Ruby methods (doesn't matter
> whether they are bound to a receiver or are "standalone").
> And suppose they read standard input and write to standard
> output. How would I (easily/properly) chain them together,
> effectively doing   meth1 | meth2 | meth3 ?

I just wrote this program but it doesn't work. Tell me if you find the
bug(s). 

class ProcessNode
	attr_reader :args
	def initialize(*args)
		@args = args
	end
end

class ProcessGraph
	def initialize(*args)
		@vertices = args
		@edges = {}
		@ends = 0
		args.each {|x| @edges[x] = [] }
	end
	# the writer is the source;
	# the reader is the target;
	# the writer goes first
	def connect(source,source_st,target,target_st)
		@edges[source][source_st] = [@ends,target,target_st]; @ends+=1
		@edges[target][target_st] = [@ends,source,source_st]; @ends+=1
	end

	def run
		pipes = (0...@ends/2).map { IO.pipe.reverse }.flatten
		processes = (0... / vertices.length).map {|v| fork {
			@edges[@vertices[v]].each_with_index {|x,i|
				next if nil==x
#				puts "process #{v} reopens #{i}: #{x.inspect}\n"
				[STDIN,STDOUT,STDERR][i].reopen(pipes[x[0]])
			}
#			exit!
			exec *(@vertices[v].args)
		}}
		processes.each {|p| Process.waitpid p }
	end
end

a=ProcessNode.new *%w(/bin/ls -l /boot /root /home)
b=ProcessNode.new *%w(/usr/bin/wc)
c=ProcessNode.new *%w(/usr/bin/wc)
g=ProcessGraph.new(a,b,c)
g.connect(a,1,b,0)
g.connect(a,2,c,0)
p "start"
g.run
p "stop"


===========
matju