From cc6ffceeec3ec98a51b5c8445d3ef957e08406ab Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Thu, 28 Sep 2023 14:37:44 -0400 Subject: [ruby/open3] [DOC] RDoc for Open3 --- lib/open3.rb | 129 ++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 101 insertions(+), 28 deletions(-) (limited to 'lib/open3.rb') diff --git a/lib/open3.rb b/lib/open3.rb index c4089dafe6..c24c4cd44e 100644 --- a/lib/open3.rb +++ b/lib/open3.rb @@ -151,6 +151,8 @@ module Open3 # when the unread buffer fills. # To avoid that, +stdout+ and +stderr+ should be read simultaneously # (using threads or IO.select). + # + # Related: Open3.popen2, Open3.popen2e. def popen3(*cmd, &block) if Hash === cmd.last opts = cmd.pop.dup @@ -172,46 +174,117 @@ module Open3 end module_function :popen3 - # Open3.popen2 is similar to Open3.popen3 except that it doesn't create a pipe for - # the standard error stream. + # :call-seq: + # Open3.popen2([env, ] command_line, options = {}) -> [stdin, stdout, wait_thread] + # Open3.popen2([env, ] exe_path, *args, options = {}) -> [stdin, stdout, wait_thread] + # Open3.popen2([env, ] command_line, options = {}) {|stdin, stdout, wait_thread| ... } -> object + # Open3.popen2([env, ] exe_path, *args, options = {}) {|stdin, stdout, wait_thread| ... } -> object # - # Block form: + # Basically a wrapper for Process.spawn that: # - # Open3.popen2([env,] cmd... [, opts]) {|stdin, stdout, wait_thr| - # pid = wait_thr.pid # pid of the started process. - # ... - # exit_status = wait_thr.value # Process::Status object returned. - # } + # - Creates a child process, by calling Process.spawn with the given arguments. + # - Creates streams +stdin+ and +stdout+, + # which are the standard input and standard output streams + # in the child process. + # - Creates thread +wait_thread+ that waits for the child process to exit; + # the thread has method +pid+, which returns the process ID + # of the child process. # - # Non-block form: + # With no block given, returns the array + # [stdin, stdout, wait_thread]. + # The caller should close each of the two returned streams. # - # stdin, stdout, wait_thr = Open3.popen2([env,] cmd... [, opts]) - # ... - # stdin.close # stdin and stdout should be closed explicitly in this form. + # stdin, stdout, wait_thread = Open3.popen2('echo') + # # => [#, #, #] + # stdin.close # stdout.close + # wait_thread.pid # => 2263572 + # wait_thread.value # => # # - # See Process.spawn for the optional hash arguments _env_ and _opts_. + # With a block given, calls the block with the three variables + # (two streams and the wait thread) + # and returns the block's return value. + # The caller need not close the streams: + # + # Open3.popen2('echo') do |stdin, stdout, wait_thread| + # p stdin + # p stdout + # p wait_thread + # p wait_thread.pid + # p wait_thread.value + # end + # + # Output: + # + # # + # # + # # + # 2263636 + # # + # + # Like Process.spawn, this method has potential security vulnerabilities + # if called with untrusted input; + # see {Command Injection}[rdoc-ref:command_injection.rdoc]. + # + # Unlike Process.spawn, this method waits for the child process to exit + # before returning, so the caller need not do so. + # + # Argument +options+ is a hash of options for the new process; + # see {Execution Options}[rdoc-ref:Process@Execution+Options]. + # + # The single required argument is one of the following: + # + # - +command_line+ if it is a string, + # and if it begins with a shell reserved word or special built-in, + # or if it contains one or more metacharacters. + # - +exe_path+ otherwise. + # + # Argument +command_line+ + # + # \String argument +command_line+ is a command line to be passed to a shell; + # it must begin with a shell reserved word, begin with a special built-in, + # or contain meta characters: + # + # Open3.popen2('if true; then echo "Foo"; fi') {|*args| p args } # Shell reserved word. + # Open3.popen2('echo') {|*args| p args } # Built-in. + # Open3.popen2('date > date.tmp') {|*args| p args } # Contains meta character. + # + # Output (for each call above): + # + # # => [#, #, #] + # + # The command line may also contain arguments and options for the command: + # + # Open3.popen2('echo "Foo"') { |i, o, t| o.gets } + # "Foo\n" + # + # Argument +exe_path+ + # + # Argument +exe_path+ is one of the following: + # + # - The string path to an executable to be called. + # - A 2-element array containing the path to an executable + # and the string to be used as the name of the executing process. # # Example: # - # Open3.popen2("wc -c") {|i,o,t| - # i.print "answer to life the universe and everything" - # i.close - # p o.gets #=> "42\n" - # } + # Open3.popen2('/usr/bin/date') { |i, o, t| o.gets } + # # => "Thu Sep 28 09:41:06 AM CDT 2023\n" # - # Open3.popen2("bc -q") {|i,o,t| - # i.puts "obase=13" - # i.puts "6 * 9" - # p o.gets #=> "42\n" - # } + # Ruby invokes the executable directly, with no shell and no shell expansion: + # + # Open3.popen2('doesnt_exist') { |i, o, t| o.gets } # Raises Errno::ENOENT + # + # If one or more +args+ is given, each is an argument or option + # to be passed to the executable: + # + # Open3.popen2('echo', 'C #') { |i, o, t| o.gets } + # # => "C #\n" + # Open3.popen2('echo', 'hello', 'world') { |i, o, t| o.gets } + # # => "hello world\n" # - # Open3.popen2("dc") {|i,o,t| - # i.print "42P" - # i.close - # p o.read #=> "*" - # } # + # Related: Open3.popen3, Open3.popen2e. def popen2(*cmd, &block) if Hash === cmd.last opts = cmd.pop.dup -- cgit v1.2.3