From bca9bf7feff03118ebb9ab58ff57f8f8216d64c4 Mon Sep 17 00:00:00 2001 From: akr Date: Thu, 4 Dec 2008 14:24:54 +0000 Subject: [PATCH] * lib/open3.rb (Open3.poutput3): new method. (Open3.poutput2): ditto. (Open3.poutput2e): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20516 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 +++ lib/open3.rb | 99 +++++++++++++++++++++++++++++++++++++++++----- test/test_open3.rb | 26 ++++++++++++ 3 files changed, 121 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7a91e46a6b..ee77b326b9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Thu Dec 4 23:24:05 2008 Tanaka Akira + + * lib/open3.rb (Open3.poutput3): new method. + (Open3.poutput2): ditto. + (Open3.poutput2e): ditto. + Thu Dec 4 23:02:13 2008 Yuki Sonoda (Yugui) * spec/default.mspec: follows changes in rubyspec project. diff --git a/lib/open3.rb b/lib/open3.rb index 55915bb512..7bf330c825 100644 --- a/lib/open3.rb +++ b/lib/open3.rb @@ -187,17 +187,96 @@ module Open3 private :popen_run end + # Open3.poutput3 captures the standard output and the standard error of a command. + # + # stdout_str, stderr_str, status = Open3.poutput3(cmd... [, opts]) + # + # The arguments cmd and opts are passed to Open3.popen3 except opts[:stdin_data]. + # + # If opts[:stdin_data] is specified, it is sent to the command's standard input. + # + def poutput3(*cmd, &block) + if Hash === cmd.last + opts = cmd.pop.dup + else + opts = {} + end + + stdin_data = opts.delete(:stdin_data) || '' + + popen3(*cmd, opts) {|i, o, e, t| + out_reader = Thread.new { o.read } + err_reader = Thread.new { e.read } + i.write stdin_data + i.close + [out_reader.value, err_reader.value, t.value] + } + end + module_function :poutput3 + + # Open3.poutput2 captures the standard output of a command. + # + # stdout_str, status = Open3.poutput2(cmd... [, opts]) + # + # The arguments cmd and opts are passed to Open3.popen2 except opts[:stdin_data]. + # + # If opts[:stdin_data] is specified, it is sent to the command's standard input. + # + def poutput2(*cmd, &block) + if Hash === cmd.last + opts = cmd.pop.dup + else + opts = {} + end + + stdin_data = opts.delete(:stdin_data) || '' + + popen2(*cmd, opts) {|i, o, t| + out_reader = Thread.new { o.read } + i.write stdin_data + i.close + [out_reader.value, t.value] + } + end + module_function :poutput2 + + # Open3.poutput2e captures the standard output and the standard error of a command. + # + # stdout_and_stderr_str, status = Open3.poutput2e(cmd... [, opts]) + # + # The arguments cmd and opts are passed to Open3.popen2e except opts[:stdin_data]. + # + # If opts[:stdin_data] is specified, it is sent to the command's standard input. + # + def poutput2e(*cmd, &block) + if Hash === cmd.last + opts = cmd.pop.dup + else + opts = {} + end + + stdin_data = opts.delete(:stdin_data) || '' + + popen2e(*cmd, opts) {|i, oe, t| + outerr_reader = Thread.new { oe.read } + i.write stdin_data + i.close + [outerr_reader.value, t.value] + } + end + module_function :poutput2e + # Open3.pipeline_rw starts list of commands as a pipeline with pipes # which connects stdin of the first command and stdout of the last command. # - # Open3.pipeline_rw(cmd1, cmd2, ... [, opts]) {|stdin, stdout, wait_threads| + # Open3.pipeline_rw(cmd1, cmd2, ... [, opts]) {|first_stdin, last_stdout, wait_threads| # ... # } # - # stdin, stdout, wait_threads = Open3.pipeline_rw(cmd1, cmd2, ... [, opts]) + # first_stdin, last_stdout, wait_threads = Open3.pipeline_rw(cmd1, cmd2, ... [, opts]) # ... - # stdin.close - # stdout.close + # first_stdin.close + # last_stdout.close # # Each cmd is a string or an array. # If it is an array, the elements are passed to Kernel#spawn. @@ -236,13 +315,13 @@ module Open3 # Open3.pipeline_r starts list of commands as a pipeline with a pipe # which connects stdout of the last command. # - # Open3.pipeline_r(cmd1, cmd2, ... [, opts]) {|stdout, wait_threads| + # Open3.pipeline_r(cmd1, cmd2, ... [, opts]) {|last_stdout, wait_threads| # ... # } # - # stdout, wait_threads = Open3.pipeline_r(cmd1, cmd2, ... [, opts]) + # last_stdout, wait_threads = Open3.pipeline_r(cmd1, cmd2, ... [, opts]) # ... - # stdout.close + # last_stdout.close # # Example: # @@ -269,13 +348,13 @@ module Open3 # Open3.pipeline_w starts list of commands as a pipeline with a pipe # which connects stdin of the first command. # - # Open3.pipeline_w(cmd1, cmd2, ... [, opts]) {|stdin, wait_threads| + # Open3.pipeline_w(cmd1, cmd2, ... [, opts]) {|first_stdin, wait_threads| # ... # } # - # stdin, wait_threads = Open3.pipeline_w(cmd1, cmd2, ... [, opts]) + # first_stdin, wait_threads = Open3.pipeline_w(cmd1, cmd2, ... [, opts]) # ... - # stdin.close + # first_stdin.close # # Example: # diff --git a/test/test_open3.rb b/test/test_open3.rb index 7d45eb543e..5acc1c39ea 100644 --- a/test/test_open3.rb +++ b/test/test_open3.rb @@ -123,6 +123,32 @@ class TestOpen3 < Test::Unit::TestCase } end + def test_poutput3 + o, e, s = Open3.poutput3(RUBY, '-e', 'i=STDIN.read; print i+"o"; STDOUT.flush; STDERR.print i+"e"', :stdin_data=>"i") + assert_equal("io", o) + assert_equal("ie", e) + assert(s.success?) + end + + def test_poutput3_flip + o, e, s = Open3.poutput3(RUBY, '-e', 'STDOUT.sync=true; 1000.times { print "o"*1000; STDERR.print "e"*1000 }') + assert_equal("o"*1000000, o) + assert_equal("e"*1000000, e) + assert(s.success?) + end + + def test_poutput2 + o, s = Open3.poutput2(RUBY, '-e', 'i=STDIN.read; print i+"o"', :stdin_data=>"i") + assert_equal("io", o) + assert(s.success?) + end + + def test_poutput2e + oe, s = Open3.poutput2e(RUBY, '-e', 'i=STDIN.read; print i+"o"; STDOUT.flush; STDERR.print i+"e"', :stdin_data=>"i") + assert_equal("ioie", oe) + assert(s.success?) + end + def test_pipeline_rw Open3.pipeline_rw([RUBY, '-e', 'print STDIN.read + "1"'], [RUBY, '-e', 'print STDIN.read + "2"']) {|i,o,ts|