How to extend $stdout#write for system calls?

J

Jim Freeze

Hi

I am writing a tee function for ruby and am pretty close.
The problem I am having now is that I don't know
how to extend $stdout#write and have it survive
a system (or exec) call.

Below is some code illustrating what I have:
cat tee.rb
module M
def write(a)
super("fred\n")
end
end

$stdout.extend(M)
puts "puts: should be fred" # prints twice for some reason
system("echo", "system: should be fred") # no fred
ruby tee.rb
fred
fred
system: should be fred

If this is not possible, maybe there is a way with alias_method,
but I haven't been able to get that going either.

TIA
 
J

Joel VanderWerf

Jim said:
Hi

I am writing a tee function for ruby and am pretty close.
The problem I am having now is that I don't know
how to extend $stdout#write and have it survive
a system (or exec) call.

Below is some code illustrating what I have:

module M
def write(a)
super("fred\n")
end
end

$stdout.extend(M)
puts "puts: should be fred" # prints twice for some reason
system("echo", "system: should be fred") # no fred

fred
fred
system: should be fred

If this is not possible, maybe there is a way with alias_method,
but I haven't been able to get that going either.

How could this work if echo is not even a ruby program? Maybe if you run
echo with popen, and print the output of that... But if you want it to
work with arb. ruby code, this won't help.

Probably the only hope is to $stdout.reopen into something you can read
and do what you want with. Never tried it tho.
 
J

Jim Freeze

* Joel VanderWerf said:
How could this work if echo is not even a ruby program? Maybe if you run
echo with popen, and print the output of that... But if you want it to
work with arb. ruby code, this won't help.

It may not be possible. My knowledge of $stdout doesn't run too deep.
So far, I have wrapped the write call, so puts is captured and I
have reopened stdout to write to a file. So, I figured there should
be a way to capture a system call (since it inherits $stdout from the
current process).

The idea is to do the following:

IO::Tee(file) {
# all output is to go to file and screen
puts "from ruby puts"
system("echo", "from system")
exec("echo", "from system")
}

and have the contents of file and the screen be identical.
 
J

Joel VanderWerf

Jim said:
It may not be possible. My knowledge of $stdout doesn't run too deep.
So far, I have wrapped the write call, so puts is captured and I
have reopened stdout to write to a file. So, I figured there should
be a way to capture a system call (since it inherits $stdout from the
current process).

A child process inherits the file handle that $stdout refers to, but not
the ruby object itself, even if the child process is ruby.
The idea is to do the following:

IO::Tee(file) {
# all output is to go to file and screen
puts "from ruby puts"
system("echo", "from system")
exec("echo", "from system")
}

and have the contents of file and the screen be identical.

You'll be disappointed by the following if you are using windows, but
what else is new.

------
class IO
def tee
IO.popen("-") do |pipe| # Won't work on mswin.
if pipe # parent
while (str = pipe.gets)
puts str
$stdout.puts str
end
else # child
yield
end
end
end
end

f=File.open("/tmp/tee-example-output", "w+")

f.tee do
puts "something"
puts "something else"
end

f.rewind
puts "The contents of file is:\n#{f.read.inspect}"
-------
output:

something
something else
The contents of file is:
"something\nsomething else\n"

Note that the "tee" block is executed in a child process, so state (e.g.
local vars) will not be changed when you get back to the main process.
 
J

Joel VanderWerf

Joel said:
class IO
def tee
IO.popen("-") do |pipe| # Won't work on mswin.
if pipe # parent
while (str = pipe.gets)
puts str
$stdout.puts str
end
else # child
yield
end
end
end
end

f=File.open("/tmp/tee-example-output", "w+")

f.tee do
puts "something"
puts "something else"
system("echo", "from system")
end


Head.whack! I forgot to show that this does work with system calls...
 
D

Daniel Berger

Jim said:
Hi

I am writing a tee function for ruby and am pretty close.

Does Sean Chittenden's io-tee package not work? It's on the RAA.

Regards,

Dan
 
J

Jim Freeze

* Daniel Berger said:
Does Sean Chittenden's io-tee package not work? It's on the RAA.

Don't know. rubynet.org seems to be down. I wrote Sean about
it this morning, but no reply.
 
J

Jim Freeze

Windows shmwindows. So what? ;)
f.tee do
puts "something"
puts "something else"
system("echo", "from system")
end

Nice twist on this. I like it, but maybe I'm too tired.
How would I integrate capturing stderr also?
I tried popen3, but couldn't get that to work either.
 
D

Daniel Berger

Jim said:
Don't know. rubynet.org seems to be down. I wrote Sean about
it this morning, but no reply.

Ah, you're right. In any case, if you can read Perl it's probably
worth your while to look at Chung-chieh Shan's IO::Tee module, on CPAN.

Regards,

Dan
 
J

Jim Freeze

* Daniel Berger said:
Ah, you're right. In any case, if you can read Perl it's probably
worth your while to look at Chung-chieh Shan's IO::Tee module, on CPAN.

Thanks. I'll take a look
 

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

Forum statistics

Threads
473,767
Messages
2,569,573
Members
45,046
Latest member
Gavizuho

Latest Threads

Top