Skip to content

Commit 3bdb402

Browse files
[DOC] Open3 doc (#21)
1 parent 4c9e749 commit 3bdb402

File tree

1 file changed

+170
-106
lines changed

1 file changed

+170
-106
lines changed

lib/open3.rb

Lines changed: 170 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -899,48 +899,84 @@ def capture2e(*cmd)
899899
end
900900
module_function :capture2e
901901

902-
# Open3.pipeline_rw starts a list of commands as a pipeline with pipes
903-
# which connect to stdin of the first command and stdout of the last command.
904-
#
905-
# Open3.pipeline_rw(cmd1, cmd2, ... [, opts]) {|first_stdin, last_stdout, wait_threads|
906-
# ...
907-
# }
902+
# :call-seq:
903+
# Open3.pipeline_rw([env, ] *cmds, options = {}) -> [first_stdin, last_stdout, wait_threads]
908904
#
909-
# first_stdin, last_stdout, wait_threads = Open3.pipeline_rw(cmd1, cmd2, ... [, opts])
910-
# ...
911-
# first_stdin.close
912-
# last_stdout.close
905+
# Basically a wrapper for
906+
# {Process.spawn}[https://docs.ruby-lang.org/en/master/Process.html#method-c-spawn]
907+
# that:
913908
#
914-
# Each cmd is a string or an array.
915-
# If it is an array, the elements are passed to Process.spawn.
909+
# - Creates a child process for each of the given +cmds+
910+
# by calling Process.spawn.
911+
# - Pipes the +stdout+ from each child to the +stdin+ of the next child,
912+
# or, for the first child, from the caller's +stdin+,
913+
# or, for the last child, to the caller's +stdout+.
916914
#
917-
# cmd:
918-
# commandline command line string which is passed to a shell
919-
# [env, commandline, opts] command line string which is passed to a shell
920-
# [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell)
921-
# [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)
915+
# The method does not wait for child processes to exit,
916+
# so the caller must do so.
922917
#
923-
# Note that env and opts are optional, as for Process.spawn.
918+
# With no block given, returns a 3-element array containing:
924919
#
925-
# The options to pass to Process.spawn are constructed by merging
926-
# +opts+, the last hash element of the array, and
927-
# specifications for the pipes between each of the commands.
920+
# - The +stdin+ stream of the first child process.
921+
# - The +stdout+ stream of the last child process.
922+
# - An array of the wait threads for all of the child processes.
928923
#
929924
# Example:
930925
#
931-
# Open3.pipeline_rw("tr -dc A-Za-z", "wc -c") {|i, o, ts|
932-
# i.puts "All persons more than a mile high to leave the court."
933-
# i.close
934-
# p o.gets #=> "42\n"
935-
# }
936-
#
937-
# Open3.pipeline_rw("sort", "cat -n") {|stdin, stdout, wait_thrs|
938-
# stdin.puts "foo"
939-
# stdin.puts "bar"
940-
# stdin.puts "baz"
941-
# stdin.close # send EOF to sort.
942-
# p stdout.read #=> " 1\tbar\n 2\tbaz\n 3\tfoo\n"
943-
# }
926+
# first_stdin, last_stdout, wait_threads = Open3.pipeline_rw('sort', 'cat -n')
927+
# # => [#<IO:fd 20>, #<IO:fd 21>, [#<Process::Waiter:0x000055e8de29ab40 sleep>, #<Process::Waiter:0x000055e8de29a690 sleep>]]
928+
# first_stdin.puts("foo\nbar\nbaz")
929+
# first_stdin.close # Send EOF to sort.
930+
# puts last_stdout.read
931+
# wait_threads.each do |wait_thread|
932+
# wait_thread.join
933+
# end
934+
#
935+
# Output:
936+
#
937+
# 1 bar
938+
# 2 baz
939+
# 3 foo
940+
#
941+
# With a block given, calls the block with the +stdin+ stream of the first child,
942+
# the +stdout+ stream of the last child,
943+
# and an array of the wait processes:
944+
#
945+
# Open3.pipeline_rw('sort', 'cat -n') do |first_stdin, last_stdout, wait_threads|
946+
# first_stdin.puts "foo\nbar\nbaz"
947+
# first_stdin.close # send EOF to sort.
948+
# puts last_stdout.read
949+
# wait_threads.each do |wait_thread|
950+
# wait_thread.join
951+
# end
952+
# end
953+
#
954+
# Output:
955+
#
956+
# 1 bar
957+
# 2 baz
958+
# 3 foo
959+
#
960+
# Like Process.spawn, this method has potential security vulnerabilities
961+
# if called with untrusted input;
962+
# see {Command Injection}[rdoc-ref:command_injection.rdoc].
963+
#
964+
# If the first argument is a hash, it becomes leading argument +env+
965+
# in each call to Process.spawn;
966+
# see {Execution Environment}[https://docs.ruby-lang.org/en/master/Process.html#module-Process-label-Execution+Environment].
967+
#
968+
# If the last argument is a hash, it becomes trailing argument +options+
969+
# in each call to Process.spawn;
970+
# see {Execution Options}[https://docs.ruby-lang.org/en/master/Process.html#module-Process-label-Execution+Options].
971+
#
972+
# Each remaining argument in +cmds+ is one of:
973+
#
974+
# - A +command_line+: a string that begins with a shell reserved word
975+
# or special built-in, or contains one or more metacharacters.
976+
# - An +exe_path+: the string path to an executable to be called.
977+
# - An array containing a +command_line+ or an +exe_path+,
978+
# along with zero or more string arguments for the command.
979+
#
944980
def pipeline_rw(*cmds, &block)
945981
if Hash === cmds.last
946982
opts = cmds.pop.dup
@@ -970,7 +1006,9 @@ def pipeline_rw(*cmds, &block)
9701006
# by calling Process.spawn.
9711007
# - Pipes the +stdout+ from each child to the +stdin+ of the next child,
9721008
# or, for the last child, to the caller's +stdout+.
973-
# - Waits for all child processes to exit.
1009+
#
1010+
# The method does not wait for child processes to exit,
1011+
# so the caller must do so.
9741012
#
9751013
# With no block given, returns a 2-element array containing:
9761014
#
@@ -979,31 +1017,38 @@ def pipeline_rw(*cmds, &block)
9791017
#
9801018
# Example:
9811019
#
982-
# Open3.pipeline_r('ls', 'grep R')
983-
# # => [#<IO:fd 5>, [#<Process::Waiter:0x00005638280167b8 sleep>, #<Process::Waiter:0x0000563828015480 dead>]]
1020+
# last_stdout, wait_threads = Open3.pipeline_r('ls', 'grep R')
1021+
# # => [#<IO:fd 5>, [#<Process::Waiter:0x000055e8de2f9898 dead>, #<Process::Waiter:0x000055e8de2f94b0 sleep>]]
1022+
# puts last_stdout.read
1023+
# wait_threads.each do |wait_thread|
1024+
# wait_thread.join
1025+
# end
1026+
#
1027+
# Output:
1028+
#
1029+
# Rakefile
1030+
# README.md
9841031
#
9851032
# With a block given, calls the block with the +stdout+ stream
9861033
# of the last child process,
9871034
# and an array of the wait processes:
9881035
#
989-
# Open3.pipeline_r('ls', 'grep R') do |x, ts|
990-
# puts x.read
991-
# p ts
1036+
# Open3.pipeline_r('ls', 'grep R') do |last_stdout, wait_threads|
1037+
# puts last_stdout.read
1038+
# wait_threads.each do |wait_thread|
1039+
# wait_thread.join
1040+
# end
9921041
# end
9931042
#
9941043
# Output:
9951044
#
9961045
# Rakefile
9971046
# README.md
998-
# [#<Process::Waiter:0x000055f1d78d76f0 sleep>, #<Process::Waiter:0x000055f1d78d7358 dead>]
9991047
#
10001048
# Like Process.spawn, this method has potential security vulnerabilities
10011049
# if called with untrusted input;
10021050
# see {Command Injection}[rdoc-ref:command_injection.rdoc].
10031051
#
1004-
# Unlike Process.spawn, this method waits for the child processes to exit
1005-
# before returning, so the caller need not do so.
1006-
#
10071052
# If the first argument is a hash, it becomes leading argument +env+
10081053
# in each call to Process.spawn;
10091054
# see {Execution Environment}[https://docs.ruby-lang.org/en/master/Process.html#module-Process-label-Execution+Environment].
@@ -1046,7 +1091,9 @@ def pipeline_r(*cmds, &block)
10461091
# by calling Process.spawn.
10471092
# - Pipes the +stdout+ from each child to the +stdin+ of the next child,
10481093
# or, for the first child, pipes the caller's +stdout+ to the child's +stdin+.
1049-
# - Waits for all child processes to exit.
1094+
#
1095+
# The method does not wait for child processes to exit,
1096+
# so the caller must do so.
10501097
#
10511098
# With no block given, returns a 2-element array containing:
10521099
#
@@ -1055,36 +1102,42 @@ def pipeline_r(*cmds, &block)
10551102
#
10561103
# Example:
10571104
#
1058-
# p Open3.pipeline_r(
1059-
# ['ruby', '-e', 'print "Foo"'],
1060-
# ['ruby', '-e', 'print STDIN.read + "Bar"']
1061-
# )
1062-
# [#<IO:fd 5>, [#<Process::Waiter:0x00005568cad44a08 sleep>, #<Process::Waiter:0x00005568cad44508 run>]]
1105+
# first_stdin, wait_threads = Open3.pipeline_w('sort', 'cat -n')
1106+
# # => [#<IO:fd 7>, [#<Process::Waiter:0x000055e8de928278 run>, #<Process::Waiter:0x000055e8de923e80 run>]]
1107+
# first_stdin.puts("foo\nbar\nbaz")
1108+
# first_stdin.close # Send EOF to sort.
1109+
# wait_threads.each do |wait_thread|
1110+
# wait_thread.join
1111+
# end
1112+
#
1113+
# Output:
1114+
#
1115+
# 1 bar
1116+
# 2 baz
1117+
# 3 foo
10631118
#
10641119
# With a block given, calls the block with the +stdin+ stream
10651120
# of the first child process,
10661121
# and an array of the wait processes:
10671122
#
1068-
# Open3.pipeline_r(
1069-
# ['ruby', '-e', 'print "Foo"'],
1070-
# ['ruby', '-e', 'print STDIN.read + "Bar"']
1071-
# ) do |x, ts|
1072-
# puts x.read
1073-
# p ts
1123+
# Open3.pipeline_w('sort', 'cat -n') do |first_stdin, wait_threads|
1124+
# first_stdin.puts("foo\nbar\nbaz")
1125+
# first_stdin.close # Send EOF to sort.
1126+
# wait_threads.each do |wait_thread|
1127+
# wait_thread.join
1128+
# end
10741129
# end
10751130
#
10761131
# Output:
10771132
#
1078-
# FooBar
1079-
# [#<Process::Waiter:0x000055628e2ebbc0 dead>, #<Process::Waiter:0x000055628e2eb7b0 sleep>]
1133+
# 1 bar
1134+
# 2 baz
1135+
# 3 foo
10801136
#
10811137
# Like Process.spawn, this method has potential security vulnerabilities
10821138
# if called with untrusted input;
10831139
# see {Command Injection}[rdoc-ref:command_injection.rdoc].
10841140
#
1085-
# Unlike Process.spawn, this method waits for the child processes to exit
1086-
# before returning, so the caller need not do so.
1087-
#
10881141
# If the first argument is a hash, it becomes leading argument +env+
10891142
# in each call to Process.spawn;
10901143
# see {Execution Environment}[https://docs.ruby-lang.org/en/master/Process.html#module-Process-label-Execution+Environment].
@@ -1116,49 +1169,65 @@ def pipeline_w(*cmds, &block)
11161169
end
11171170
module_function :pipeline_w
11181171

1119-
# Open3.pipeline_start starts a list of commands as a pipeline.
1120-
# No pipes are created for stdin of the first command and
1121-
# stdout of the last command.
1172+
# :call-seq:
1173+
# Open3.pipeline_start([env, ] *cmds, options = {}) -> [wait_threads]
1174+
#
1175+
# Basically a wrapper for
1176+
# {Process.spawn}[https://docs.ruby-lang.org/en/master/Process.html#method-c-spawn]
1177+
# that:
11221178
#
1123-
# Open3.pipeline_start(cmd1, cmd2, ... [, opts]) {|wait_threads|
1124-
# ...
1125-
# }
1179+
# - Creates a child process for each of the given +cmds+
1180+
# by calling Process.spawn.
1181+
# - Does not wait for child processes to exit.
11261182
#
1127-
# wait_threads = Open3.pipeline_start(cmd1, cmd2, ... [, opts])
1128-
# ...
1183+
# With no block given, returns an array of the wait threads
1184+
# for all of the child processes.
11291185
#
1130-
# Each cmd is a string or an array.
1131-
# If it is an array, the elements are passed to Process.spawn.
1186+
# Example:
11321187
#
1133-
# cmd:
1134-
# commandline command line string which is passed to a shell
1135-
# [env, commandline, opts] command line string which is passed to a shell
1136-
# [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell)
1137-
# [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)
1188+
# wait_threads = Open3.pipeline_start('ls', 'grep R')
1189+
# # => [#<Process::Waiter:0x000055e8de9d2bb0 run>, #<Process::Waiter:0x000055e8de9d2890 run>]
1190+
# wait_threads.each do |wait_thread|
1191+
# wait_thread.join
1192+
# end
11381193
#
1139-
# Note that env and opts are optional, as for Process.spawn.
1194+
# Output:
11401195
#
1141-
# Example:
1196+
# Rakefile
1197+
# README.md
1198+
#
1199+
# With a block given, calls the block with an array of the wait processes:
1200+
#
1201+
# Open3.pipeline_start('ls', 'grep R') do |wait_threads|
1202+
# wait_threads.each do |wait_thread|
1203+
# wait_thread.join
1204+
# end
1205+
# end
1206+
#
1207+
# Output:
11421208
#
1143-
# # Run xeyes in 10 seconds.
1144-
# Open3.pipeline_start("xeyes") {|ts|
1145-
# sleep 10
1146-
# t = ts[0]
1147-
# Process.kill("TERM", t.pid)
1148-
# p t.value #=> #<Process::Status: pid 911 SIGTERM (signal 15)>
1149-
# }
1150-
#
1151-
# # Convert pdf to ps and send it to a printer.
1152-
# # Collect error message of pdftops and lpr.
1153-
# pdf_file = "paper.pdf"
1154-
# printer = "printer-name"
1155-
# err_r, err_w = IO.pipe
1156-
# Open3.pipeline_start(["pdftops", pdf_file, "-"],
1157-
# ["lpr", "-P#{printer}"],
1158-
# :err=>err_w) {|ts|
1159-
# err_w.close
1160-
# p err_r.read # error messages of pdftops and lpr.
1161-
# }
1209+
# Rakefile
1210+
# README.md
1211+
#
1212+
# Like Process.spawn, this method has potential security vulnerabilities
1213+
# if called with untrusted input;
1214+
# see {Command Injection}[rdoc-ref:command_injection.rdoc].
1215+
#
1216+
# If the first argument is a hash, it becomes leading argument +env+
1217+
# in each call to Process.spawn;
1218+
# see {Execution Environment}[https://docs.ruby-lang.org/en/master/Process.html#module-Process-label-Execution+Environment].
1219+
#
1220+
# If the last argument is a hash, it becomes trailing argument +options+
1221+
# in each call to Process.spawn;
1222+
# see {Execution Options}[https://docs.ruby-lang.org/en/master/Process.html#module-Process-label-Execution+Options].
1223+
#
1224+
# Each remaining argument in +cmds+ is one of:
1225+
#
1226+
# - A +command_line+: a string that begins with a shell reserved word
1227+
# or special built-in, or contains one or more metacharacters.
1228+
# - An +exe_path+: the string path to an executable to be called.
1229+
# - An array containing a +command_line+ or an +exe_path+,
1230+
# along with zero or more string arguments for the command.
11621231
#
11631232
def pipeline_start(*cmds, &block)
11641233
if Hash === cmds.last
@@ -1187,28 +1256,23 @@ def pipeline_start(*cmds, &block)
11871256
# by calling Process.spawn.
11881257
# - Pipes the +stdout+ from each child to the +stdin+ of the next child,
11891258
# or, for the last child, to the caller's +stdout+.
1190-
# - Waits for all child processes to exit.
1259+
# - Waits for the child processes to exit.
11911260
# - Returns an array of Process::Status objects (one for each child).
11921261
#
1193-
# A simple example:
1262+
# Example:
11941263
#
1195-
# Open3.pipeline('ls', 'grep [A-Z]')
1196-
# # => [#<Process::Status: pid 1343895 exit 0>, #<Process::Status: pid 1343897 exit 0>]
1264+
# wait_threads = Open3.pipeline('ls', 'grep R')
1265+
# # => [#<Process::Status: pid 2139200 exit 0>, #<Process::Status: pid 2139202 exit 0>]
11971266
#
11981267
# Output:
11991268
#
1200-
# Gemfile
1201-
# LICENSE.txt
12021269
# Rakefile
12031270
# README.md
12041271
#
12051272
# Like Process.spawn, this method has potential security vulnerabilities
12061273
# if called with untrusted input;
12071274
# see {Command Injection}[rdoc-ref:command_injection.rdoc].
12081275
#
1209-
# Unlike Process.spawn, this method waits for the child process to exit
1210-
# before returning, so the caller need not do so.
1211-
#
12121276
# If the first argument is a hash, it becomes leading argument +env+
12131277
# in each call to Process.spawn;
12141278
# see {Execution Environment}[https://docs.ruby-lang.org/en/master/Process.html#module-Process-label-Execution+Environment].

0 commit comments

Comments
 (0)