Fork style of little programs

M

Markus Liebelt

Hello everybody,

I would like to build some small ruby programs, that will work
together as the unix shell commands. Eg the following could be used
inside a Cygwin shell:

$ ruby evallog.rb | ruby sum.rb "Log: (.*)"

which will evaluate a logfile, dump the result in lines, and the
second program will sum up the entries beginning with "Log: ". Just
to give you a sample how to do it.

I now try to combine the two little programs in one program without
redefining the way their methods work. The first just writes out its
result by "puts ...", the second uses the variable $stdin. But how
could a new method look that combines the two? I have no idea how to
write it down. Is there something to "fork" the first one, so that
the second one can read from standard input while the first writes to
standard output?

Thank you very much for your patience ...
 
S

Sean O'Dell

I now try to combine the two little programs in one program without
redefining the way their methods work. The first just writes out its
result by "puts ...", the second uses the variable $stdin. But how
could a new method look that combines the two? I have no idea how to
write it down. Is there something to "fork" the first one, so that
the second one can read from standard input while the first writes to
standard output?

IO.popen("-") do | pipe |
if (pipe) then
# in parent; communicate with child through pipe
else
# in child; communicate with parent through stdio
end
end


Sean O'Dell
 
R

Robert Klemme

Markus Liebelt said:
Hello everybody,

I would like to build some small ruby programs, that will work
together as the unix shell commands. Eg the following could be used
inside a Cygwin shell:

$ ruby evallog.rb | ruby sum.rb "Log: (.*)"

which will evaluate a logfile, dump the result in lines, and the
second program will sum up the entries beginning with "Log: ". Just
to give you a sample how to do it.

I now try to combine the two little programs in one program without
redefining the way their methods work. The first just writes out its
result by "puts ...", the second uses the variable $stdin. But how
could a new method look that combines the two? I have no idea how to
write it down. Is there something to "fork" the first one, so that
the second one can read from standard input while the first writes to
standard output?

You could use a Queue (or an in process pipe implementation, if there is
such a thing in ruby) and two threads within the same process.

Regards

robert
 
M

Markus Liebelt

Hello Sean,

your input gave me a solution that might be used in the future.

Because I think other's may have the same issue as I had, I want to
give a sketch of the solution.

Sean> On Monday 12 July 2004 14:32, Markus Liebelt wrote:
Sean> >

My original question was a little bit misleading. I can restructure
my programs, but I want to use them both directly in the shell as
well as components in a bigger ruby program.

Sean> IO.popen("-") do | pipe |
Sean> if (pipe) then
Sean> # in parent; communicate with child through pipe
Sean> else
Sean> # in child; communicate with parent through stdio
Sean> end
Sean> end

I tried forth and back with your solution, but to no avail. But I
read a lot in programming ruby (section IO), so I got a new idea.

If I have a file tf.rb with definition of class TestFirst with method
test_out, which normally writes on $stdout, and I have a second file
ts.rb with definition of class TestSecond with method test_in, which
normally reads from $stdin, the following will work:
1. change the second definition by providing an argument io
2. use it in the file usage of ts.rb (is there a name for that??):
if __FILE__ == $0
puts TestSecond.new.test_in($stdin)
end
3. Combine then the two programs in the following way:
def test_both
rd, wr = IO.pipe
tmp_out = $stdout
$> = wr
TestFirst.new.test_out
wr.close
$> = tmp_out
return TestSecond.new.test_in(rd)
end
4. I'm sure there could be a way to abstract the surrounding away so
that something like the following remains:

use_read_writer(
{ TestFirst.new.test_out },
{ | reader |
TestSecond.new.test_in(reader) })

Anyone to help out ;-)


The equivalent in the shell could look like this:
$ ruby tf.rb | ruby ts.rb

So the base idea is to open for each pipe in the usage in the shell a
pipe in ruby, and redirect the $stdout to the writer of the pipe,
give the IO object that is normally $stdin as argument to the method
you want to call.

I have tested this version with the cygwin shell under Win-XP and
even in the DOS Shell (shudder) with ruby-1-8-1, it works (wow).

I'm not sure that this is the simplest solution, but it is doable for
me and I see no drawback of it.

Sean> Sean O'Dell

Many thank's to all the people that helped me and other rookies to
get the right ideas. And thank' to the creator of ruby to that
wonderful language (never thought that I will find something more
consistent and elegant than Smalltalk).

Bye
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,148
Messages
2,570,838
Members
47,385
Latest member
Joneswilliam01

Latest Threads

Top