# Block method to yield stdout?

**URL:** <https://www.ruby-forum.com/t/block-method-to-yield-stdout/151375>\
**Category:** Ruby\
**Created:** [October 20, 2008, 8:21pm UTC](https://www.ruby-forum.com/t/block-method-to-yield-stdout/151375 "2008-10-20T20:21:56Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![lstrecv](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e68b1a/32.png) [@lstrecv](https://www.ruby-forum.com/u/lstrecv)\
**Post date:** [October 20, 2008, 8:21pm UTC](https://www.ruby-forum.com/t/block-method-to-yield-stdout/151375/1 "2008-10-20T20:21:56Z")

</div>

All, I’ve written a distribution service that spawns processes using  
IO.popen in a seperate thread for each job.

In my Task class, I would like to create a block method such as  
‘Task.monitor(mode=“stdout”)’, which would yield the stdout for that  
task from that point forward. – similar to tail -f, but for a  
multithreaded environment.

The result would in essence be called like:

task = Task.new(:cmd =\> “tail -f /some/log”)  
sleep 10  
task.monitor

# fresh content from some/log will be yielded

Since $stdout is global, what would be the beat way tackle this?

---

<div class="post-metadata">

**Author:** ![lstrecv](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e68b1a/32.png) [@lstrecv](https://www.ruby-forum.com/u/lstrecv)\
**Post date:** [October 20, 2008, 11:15pm UTC](https://www.ruby-forum.com/t/block-method-to-yield-stdout/151375/2 "2008-10-20T23:15:33Z")

</div>

On Oct 20, 2:19 pm, “List.rb” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> In my Task class, I would like to create a block method such as  
> ‘Task.monitor(mode=“stdout”)’, which would yield the stdout for that  
> task from that point forward. – similar to tail -f

Have you seen File::Tail?  
[http://file-tail.rubyforge.org/doc/index.html](http://file-tail.rubyforge.org/doc/index.html)

– Mark.

---

<div class="post-metadata">

**Author:** ![lstrecv](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e68b1a/32.png) [@lstrecv](https://www.ruby-forum.com/u/lstrecv)\
**Post date:** [October 23, 2008, 2:41am UTC](https://www.ruby-forum.com/t/block-method-to-yield-stdout/151375/3 "2008-10-23T02:41:29Z")

</div>

On Mon, 20 Oct 2008 13:19:56 -0500, List.rb wrote:

> task = Task.new(:cmd =\> “tail -f /some/log”) sleep 10  
> task.monitor
> 
> # fresh content from some/log will be yielded
> 
> Since $stdout is global, what would be the beat way tackle this?

Maybe use Open3, or popen. Worst case, look at how Open3 does a  
fork/exec  
to call the appropriate program.

–Ken

---

<div class="post-metadata">

**Author:** ![lstrecv](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e68b1a/32.png) [@lstrecv](https://www.ruby-forum.com/u/lstrecv)\
**Post date:** [October 21, 2008, 4:44am UTC](https://www.ruby-forum.com/t/block-method-to-yield-stdout/151375/4 "2008-10-21T04:44:24Z")

</div>

On Mon, Oct 20, 2008 at 5:13 PM, Mark T. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> 

Thanks Mark for replying. Yes I have used Tail before but what I’m  
looking  
for is more along the lines of a non-blocking version of IO#readlines

Currently, I do this on the server side:

def spawn(job)  
task = Task.new(job)  
queue = Queue.new  
Thread.new(queue) {|q|  
pipe = IO.popen(task.job.cmd)  
q.push(pipe)  
q.push(pipe.pid)  
task.pid = pipe.pid  
begin  
Thread.new {  
task.output = pipe.readlines  
pipe.close  
task.exitstatus = $?.exitstatus  
task.history \<\< {:completed =\> Time.now}  
}  
rescue =\> e  
q.push e  
end  
}  
queue.clear  
self.tasks.push(task)  
return task  
end

Since IO#readlines blocks, I am not sure how to tap into the process  
output  
☹

Thanks again
