Open4-0.5.0

URIS

http://rubyforge.org/projects/codeforpeople/
http://www.codeforpeople.com/lib/ruby/

SYNOPSIS

open child process with handles on pid, stdin, stdout, and stderr:
manage
child processes and their io handles easily.

HISTORY

0.5.0:
- on the suggestion of tim pease (thanks tim!), i added timeout
features
to open4. the command run may have an overall timeout and
individual
timeouts set for each of the io handles. for example

     cmd = 'command_that_produce_out_at_one_second_intervals'

     open4.spawn cmd, :stdout_timeout => 2

   or

     cmd = 'command_that_should_complete_in_about_one_minute'

     open4.spawn cmd, :timeout => 60

   or

     cmd = 'consumes_input_at_one_line_per_second_rate'

     input = %w( 42 forty-two 42.0 )

     open4.spawn cmd, :stdin=>input, :stdin_timeout=>1

 - added 'open4' alias so one can write

     open4.spawn  vs Open4.spawn

   or even

     open4(cmd) do |pid,i,o,e|
     end

 - added signal info to SpawnError

0.4.0:
- improved error handling contributed by jordan breeding.
- introduction of background/bg method

0.3.0 :
- bug fix from jordan breeding. general clean up. added spawn
method.

0.2.0 :
- added exception marshaled from child → parent when exec fails.
thanks
to jordan breeding for a patch (yay!) and paul brannan for this
most
excellent idea.

0.1.0 :
- fixed docs to correctly show return value of popen4 (pid first
not last).
thanks Stefanie T. [email protected] for catching this.
0.0.0 :
- initial version

INSTALL

~> gem install open4

SAMPLES


simple usage

 harp: > cat sample/simple.rb
 require "open4"

 pid, stdin, stdout, stderr = Open4::popen4 "sh"

 stdin.puts "echo 42.out"
 stdin.puts "echo 42.err 1>&2"
 stdin.close

 ignored, status = Process::waitpid2 pid

 puts "pid        : #{ pid }"
 puts "stdout     : #{ stdout.read.strip }"
 puts "stderr     : #{ stderr.read.strip }"
 puts "status     : #{ status.inspect }"
 puts "exitstatus : #{ status.exitstatus }"


 harp: > ruby sample/simple.rb
 pid        : 17273
 stdout     : 42.out
 stderr     : 42.err
 status     : #<Process::Status: pid=17273,exited(0)>
 exitstatus : 0

in block form - the child process is automatically waited for

 harp: > cat sample/block.rb
 require 'open4'

 status =
   Open4::popen4("sh") do |pid, stdin, stdout, stderr|
     stdin.puts "echo 42.out"
     stdin.puts "echo 42.err 1>&2"
     stdin.close

     puts "pid        : #{ pid }"
     puts "stdout     : #{ stdout.read.strip }"
     puts "stderr     : #{ stderr.read.strip }"
   end

     puts "status     : #{ status.inspect }"
     puts "exitstatus : #{ status.exitstatus }"


 harp: > ruby sample/block.rb
 pid        : 17295
 stdout     : 42.out
 stderr     : 42.err
 status     : #<Process::Status: pid=17295,exited(0)>
 exitstatus : 0

exceptions are marshaled from child to parent if fork/exec fails

 harp: > cat sample/exception.rb
 require "open4"
 Open4::popen4 "noexist"


 harp: > ruby sample/exception.rb
 /dmsp/reference/ruby-1.8.1//lib/ruby/site_ruby/open4.rb:100:in 

`popen4’: No such file or directory - noexist (Errno::ENOENT)
from sample/exception.rb:3


the spawn method provides and even more convenient method of running
a
process, allowing any object that supports ‘each’, ‘read’, or ‘to_s’
to be
given as stdin and any objects that support ‘<<’ to be given as
stdout/stderr. an exception is thrown if the exec’d cmd fails
(nonzero
exitstatus) unless the option ‘raise’=>false is given

 harp: > cat sample/spawn.rb
 require 'open4'
 include Open4

 cat = '  ruby -e"  ARGF.each{|line| STDOUT << line}  "  '

 stdout, stderr = '', ''
 status = spawn cat, 'stdin' => '42', 'stdout' => stdout, 'stderr' 

=> stderr
p status
p stdout
p stderr

 stdout, stderr = '', ''
 status = spawn cat, 0=>'42', 1=>stdout, 2=>stderr
 p status
 p stdout
 p stderr


 harp: > RUBYLIB=lib ruby sample/spawn.rb
 0
 "42"
 ""
 0
 "42"
 ""

the bg/background method is similar to spawn, but the process is
automatically set running in a thread. the returned thread has
several
methods added dynamically which return the pid and blocking calls to
the
exitstatus.

 harp: > cat sample/bg.rb
 require 'yaml'
 require 'open4'
 include Open4

 stdin = '42'
 stdout = ''
 stderr = ''

 t = bg 'ruby -e"sleep 4; puts ARGF.read"', 0=>stdin, 1=>stdout, 

2=>stderr

 waiter = Thread.new{ y t.pid => t.exitstatus } # t.exitstatus is a 

blocking call!

 while((status = t.status))
   y "status" => status
   sleep 1
 end

 waiter.join

 y "stdout" => stdout


 harp: > ruby sample/bg.rb
 ---
 status: run
 ---
 status: sleep
 ---
 status: sleep
 ---
 status: sleep
 ---
 21357: 0
 ---
 stdout: "42\n"

the timeout methods can be used to ensure execution is preceding at
the
desired interval. note also how to setup a ‘pipeline’

 harp: > cat sample/stdin_timeout.rb
 require 'open4'

 producer = 'ruby -e" STDOUT.sync = true; loop{sleep(rand+rand) and 

puts 42} "’

 consumer = 'ruby -e" STDOUT.sync = true; STDIN.each{|line| puts 

line} "’

 open4(producer) do |pid, i, o, e|

   open4.spawn consumer, :stdin=>o, :stdout=>STDOUT, :stdin_timeout 

=> 1.4

 end


 harp: > ruby sample/stdin_timeout.rb
 42
 42
 42
 42
 42
 /dmsp/reference/ruby-1.8.1//lib/ruby/1.8/timeout.rb:42:in `relay': 

execution expired (Timeout::Error)

AUTHOR

[email protected]

LICENSE

ruby’s

enjoy.

-a