Module: Open3

Defined in:
lib/open3_backport/open3.rb,
lib/open3_backport/original_open3.rb

Overview

Open3 grants you access to stdin, stdout, stderr and a thread to wait the child process when running another program. You can specify various attributes, redirections, current directory, etc., of the program as Process.spawn.

  • Open3.popen3 : pipes for stdin, stdout, stderr

  • Open3.popen2 : pipes for stdin, stdout

  • Open3.popen2e : pipes for stdin, merged stdout and stderr

  • Open3.capture3 : give a string for stdin. get strings for stdout, stderr

  • Open3.capture2 : give a string for stdin. get a string for stdout

  • Open3.capture2e : give a string for stdin. get a string for merged stdout and stderr

  • Open3.pipeline_rw : pipes for first stdin and last stdout of a pipeline

  • Open3.pipeline_r : pipe for last stdout of a pipeline

  • Open3.pipeline_w : pipe for first stdin of a pipeline

  • Open3.pipeline_start : a pipeline

  • Open3.pipeline : run a pipline and wait

Constant Summary collapse

CAPTURE_BUFFER_SIZE =
65536

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.capture2(*cmd, &block) ⇒ Object

Open3.capture2 captures the standard output of a command.

stdout_str, status = Open3.capture2([env,] cmd... [, opts])

The arguments env, cmd and opts are passed to Open3.popen3 except opts and opts. See Process.spawn.

If opts is specified, it is sent to the command’s standard input.

If opts is true, internal pipes are set to binary mode.

Example:

# factor is a command for integer factorization.
o, s = Open3.capture2("factor", :stdin_data=>"42")
p o #=> "42: 2 3 7\n"

# generate x**2 graph in png using gnuplot.
gnuplot_commands = <<"End"
  set terminal png
  plot x**2, "-" with lines
  1 14
  2 1
  3 8
  4 5
  e
End
image, s = Open3.capture2("gnuplot", :stdin_data=>gnuplot_commands, :binmode=>true)


349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
# File 'lib/open3_backport/open3.rb', line 349

def capture2(*cmd)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  binmode = opts[:binmode]
  i_data = (opts[:stdin_data] || '').to_s
  o_data = ''

  popen3(*cmd) do |i, o, e, t|
    e.close
    if binmode
      i.binmode
      o.binmode
      e.binmode
    end

    i_complete = i_data.empty?
    o_complete = false

    until i_complete && o_complete
      i_blocked = false
      o_blocked = false

      unless i_complete
        begin
          bytes_written = i.write_nonblock(i_data)
          if bytes_written == i_data.length
            i.close
            i_complete = true
          else
            i_data = i_data[bytes_written .. -1]
          end
        rescue Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EINTR
          i_blocked = true
        end
      end

      unless o_complete
        begin
          o_data << o.read_nonblock(CAPTURE_BUFFER_SIZE)
        rescue Errno::EWOULDBLOCK, Errno::EAGAIN
          o_blocked = true
        rescue EOFError
          raise unless i_complete
          o.close
          o_complete = true
        end
      end

      if i_blocked && o_blocked && e_blocked
        IO.select([o], [i], [o,i])
      end
    end
    return [o_data, t.value]
  end
end

.capture2e(*cmd, &block) ⇒ Object

Open3.capture2e captures the standard output and the standard error of a command.

stdout_and_stderr_str, status = Open3.capture2e([env,] cmd... [, opts])

The arguments env, cmd and opts are passed to Open3.popen3 except opts and opts. See Process.spawn.

If opts is specified, it is sent to the command’s standard input.

If opts is true, internal pipes are set to binary mode.

Example:

# capture make log
make_log, s = Open3.capture2e("make")


425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
# File 'lib/open3_backport/open3.rb', line 425

def capture2e(*cmd)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  binmode = opts[:binmode]
  i_data = (opts[:stdin_data] || '').to_s
  oe_data = ''

  popen3(*cmd) do |i, o, e, t|
    if binmode
      i.binmode
      o.binmode
      e.binmode
    end

    i_complete = i_data.empty?
    o_complete = false
    e_complete = false

    until i_complete && o_complete && e_complete
      i_blocked = false
      o_blocked = false
      e_blocked = false

      unless i_complete
        begin
          bytes_written = i.write_nonblock(i_data)
          if bytes_written == i_data.length
            i.close
            i_complete = true
          else
            i_data = i_data[bytes_written .. -1]
          end
        rescue Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EINTR
          i_blocked = true
        end
      end

      unless o_complete
        begin
          oe_data << o.read_nonblock(CAPTURE_BUFFER_SIZE)
        rescue Errno::EWOULDBLOCK, Errno::EAGAIN
          o_blocked = true
        rescue EOFError
          raise unless i_complete
          o.close
          o_complete = true
        end
      end

      unless e_complete
        begin
          oe_data << e.read_nonblock(CAPTURE_BUFFER_SIZE)
        rescue Errno::EWOULDBLOCK, Errno::EAGAIN
          e_blocked = true
        rescue EOFError
          raise unless i_complete
          e.close
          e_complete = true
        end
      end

      if i_blocked && o_blocked && e_blocked
        IO.select([o, e], [i], [o,e,i])
      end
    end
    return [oe_data, t.value]
  end
end

.capture3(*cmd, &block) ⇒ Object

Open3.capture3 captures the standard output and the standard error of a command.

stdout_str, stderr_str, status = Open3.capture3([env,] cmd... [, opts])

The arguments env, cmd and opts are passed to Open3.popen3 except opts and opts. See Process.spawn.

If opts is specified, it is sent to the command’s standard input.

If opts is true, internal pipes are set to binary mode.

Example:

# dot is a command of graphviz.
graph = <<'End'
  digraph g {
    a -> b
  }
End
layouted_graph, dot_log = Open3.capture3("dot -v", :stdin_data=>graph)

o, e, s = Open3.capture3("echo a; sort >&2", :stdin_data=>"foo\nbar\nbaz\n")
p o #=> "a\n"
p e #=> "bar\nbaz\nfoo\n"
p s #=> #<Process::Status: pid 32682 exit 0>

# generate a thumnail image using the convert command of ImageMagick.
# However, if the image stored really in a file,
# system("convert", "-thumbnail", "80", "png:#{filename}", "png:-") is better
# because memory consumption.
# But if the image is stored in a DB or generated by gnuplot Open3.capture2 example,
# Open3.capture3 is considerable.
#
image = File.read("/usr/share/openclipart/png/animals/mammals/sheep-md-v0.1.png", :binmode=>true)
thumnail, err, s = Open3.capture3("convert -thumbnail 80 png:- png:-", :stdin_data=>image, :binmode=>true)
if s.success?
  STDOUT.binmode; print thumnail
end


246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/open3_backport/open3.rb', line 246

def capture3(*cmd)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  binmode = opts[:binmode]
  i_data = (opts[:stdin_data] || '').to_s
  o_data = ''
  e_data = ''

  popen3(*cmd) do |i, o, e, t|
    if binmode
      i.binmode
      o.binmode
      e.binmode
    end

    i_complete = i_data.empty?
    o_complete = false
    e_complete = false

    until i_complete && o_complete && e_complete
      i_blocked = false
      o_blocked = false
      e_blocked = false

      unless i_complete
        begin
          bytes_written = i.write_nonblock(i_data)
          if bytes_written == i_data.length
            i.close
            i_complete = true
          else
            i_data = i_data[bytes_written .. -1]
          end
        rescue Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EINTR
          i_blocked = true
        end
      end

      unless o_complete
        begin
          o_data << o.read_nonblock(CAPTURE_BUFFER_SIZE)
        rescue Errno::EWOULDBLOCK, Errno::EAGAIN
          o_blocked = true
        rescue EOFError
          raise unless i_complete
          o.close
          o_complete = true
        end
      end

      unless e_complete
        begin
          e_data << e.read_nonblock(CAPTURE_BUFFER_SIZE)
        rescue Errno::EWOULDBLOCK, Errno::EAGAIN
          e_blocked = true
        rescue EOFError
          raise unless i_complete
          e.close
          e_complete = true
        end
      end

      if i_blocked && o_blocked && e_blocked
        IO.select([o, e], [i], [o,e,i])
      end
    end
    return [o_data, e_data, t.value]
  end
end

.detach(pid) ⇒ Object

:nodoc:



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/open3_backport/open3.rb', line 30

def detach(pid) # :nodoc:
  thread = Process.detach(pid)
  thread[:pid] = pid
  thread.instance_eval do

    def pid
      self[:pid]
    end

    def value(*args)
      self[:value] ||= begin
        Process.waitpid(pid) rescue nil
        $?
      ensure
        self.run
        self.join
      end
    end

  end
  thread
end

.pipeline(*cmds) ⇒ Object

Open3.pipeline starts a list of commands as a pipeline. It waits the finish of the commands. No pipe made for stdin of the first command and stdout of the last command.

status_list = Open3.pipeline(cmd1, cmd2, ... [, opts])

Each cmd is a string or an array. If it is an array, the elements are passed to Process.spawn.

cmd:
  commandline                              command line string which is passed to a shell
  [env, commandline, opts]                 command line string which is passed to a shell
  [env, cmdname, arg1, ..., opts]          command name and one or more arguments (no shell)
  [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)

Note that env and opts are optional, as Process.spawn.

Example:

fname = "/usr/share/man/man1/ruby.1.gz"
p Open3.pipeline(["zcat", fname], "nroff -man", "less")
#=> [#<Process::Status: pid 11817 exit 0>,
#    #<Process::Status: pid 11820 exit 0>,
#    #<Process::Status: pid 11828 exit 0>]

fname = "/usr/share/man/man1/ls.1.gz"
Open3.pipeline(["zcat", fname], "nroff -man", "colcrt")

# convert PDF to PS and send to a printer by lpr
pdf_file = "paper.pdf"
printer = "printer-name"
Open3.pipeline(["pdftops", pdf_file, "-"],
               ["lpr", "-P#{printer}"])

# count lines
Open3.pipeline("sort", "uniq -c", :in=>"names.txt", :out=>"count")

# cyclic pipeline
r,w = IO.pipe
w.print "ibase=14\n10\n"
Open3.pipeline("bc", "tee /dev/tty", :in=>r, :out=>w)
#=> 14
#   18
#   22
#   30
#   42
#   58
#   78
#   106
#   202


686
687
688
# File 'lib/open3_backport/open3.rb', line 686

def pipeline(*cmds)
  raise NotImplementedError
end

.pipeline_r(*cmds, &block) ⇒ Object

Open3.pipeline_r starts a list of commands as a pipeline with a pipe which connects stdout of the last command.

Open3.pipeline_r(cmd1, cmd2, ... [, opts]) {|last_stdout, wait_threads|
  ...
}

last_stdout, wait_threads = Open3.pipeline_r(cmd1, cmd2, ... [, opts])
...
last_stdout.close

Each cmd is a string or an array. If it is an array, the elements are passed to Process.spawn.

cmd:
  commandline                              command line string which is passed to a shell
  [env, commandline, opts]                 command line string which is passed to a shell
  [env, cmdname, arg1, ..., opts]          command name and one or more arguments (no shell)
  [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)

Note that env and opts are optional, as Process.spawn.

Example:

Open3.pipeline_r("zcat /var/log/apache2/access.log.*.gz",
                 [{"LANG"=>"C"}, "grep", "GET /favicon.ico"],
                 "logresolve") {|o, ts|
  o.each_line {|line|
    ...
  }
}

Open3.pipeline_r("yes", "head -10") {|o, ts|
  p o.read      #=> "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"
  p ts[0].value #=> #<Process::Status: pid 24910 SIGPIPE (signal 13)>
  p ts[1].value #=> #<Process::Status: pid 24913 exit 0>
}


568
569
570
# File 'lib/open3_backport/open3.rb', line 568

def pipeline_r(*cmds, &block)
  raise NotImplementedError
end

.pipeline_run(cmds, pipeline_opts, child_io, parent_io, &block) ⇒ Object

:nodoc:



656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
# File 'lib/open3_backport/original_open3.rb', line 656

def pipeline_run(cmds, pipeline_opts, child_io, parent_io, &block) # :nodoc:
  if cmds.empty?
    raise ArgumentError, "no commands"
  end

  opts_base = pipeline_opts.dup
  opts_base.delete :in
  opts_base.delete :out

  wait_thrs = []
  r = nil
  cmds.each_with_index {|cmd, i|
    cmd_opts = opts_base.dup
    if String === cmd
      cmd = [cmd]
    else
      cmd_opts.update cmd.pop if Hash === cmd.last
    end
    if i == 0
      if !cmd_opts.include?(:in)
        if pipeline_opts.include?(:in)
          cmd_opts[:in] = pipeline_opts[:in]
        end
      end
    else
      cmd_opts[:in] = r
    end
    if i != cmds.length - 1
      r2, w2 = IO.pipe
      cmd_opts[:out] = w2
    else
      if !cmd_opts.include?(:out)
        if pipeline_opts.include?(:out)
          cmd_opts[:out] = pipeline_opts[:out]
        end
      end
    end
    pid = spawn(*cmd, cmd_opts)
    wait_thrs << Process.detach(pid)
    r.close if r
    w2.close if w2
    r = r2
  }
  result = parent_io + [wait_thrs]
  child_io.each {|io| io.close }
  if defined? yield
    begin
      return yield(*result)
    ensure
      parent_io.each{|io| io.close unless io.closed?}
      wait_thrs.each {|t| t.join }
    end
  end
  result
end

.pipeline_rw(*cmds, &block) ⇒ Object

Open3.pipeline_rw starts a 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]) {|first_stdin, last_stdout, wait_threads|
  ...
}

first_stdin, last_stdout, wait_threads = Open3.pipeline_rw(cmd1, cmd2, ... [, opts])
...
first_stdin.close
last_stdout.close

Each cmd is a string or an array. If it is an array, the elements are passed to Process.spawn.

cmd:
  commandline                              command line string which is passed to a shell
  [env, commandline, opts]                 command line string which is passed to a shell
  [env, cmdname, arg1, ..., opts]          command name and one or more arguments (no shell)
  [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)

Note that env and opts are optional, as Process.spawn.

The option to pass Process.spawn is constructed by merging opts, the last hash element of the array and specification for the pipe between each commands.

Example:

Open3.pipeline_rw("tr -dc A-Za-z", "wc -c") {|i,o,ts|
  i.puts "All persons more than a mile high to leave the court."
  i.close
  p o.gets #=> "42\n"
}

Open3.pipeline_rw("sort", "cat -n") {|stdin, stdout, wait_thrs|
  stdin.puts "foo"
  stdin.puts "bar"
  stdin.puts "baz"
  stdin.close     # send EOF to sort.
  p stdout.read   #=> "     1\tbar\n     2\tbaz\n     3\tfoo\n"
}


532
533
534
# File 'lib/open3_backport/open3.rb', line 532

def pipeline_rw(*cmds, &block)
  raise NotImplementedError
end

.pipeline_start(*cmds, &block) ⇒ Object

Open3.pipeline_start starts a list of commands as a pipeline. No pipe made for stdin of the first command and stdout of the last command.

Open3.pipeline_start(cmd1, cmd2, ... [, opts]) {|wait_threads|
  ...
}

wait_threads = Open3.pipeline_start(cmd1, cmd2, ... [, opts])
...

Each cmd is a string or an array. If it is an array, the elements are passed to Process.spawn.

cmd:
  commandline                              command line string which is passed to a shell
  [env, commandline, opts]                 command line string which is passed to a shell
  [env, cmdname, arg1, ..., opts]          command name and one or more arguments (no shell)
  [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)

Note that env and opts are optional, as Process.spawn.

Example:

# run xeyes in 10 seconds.
Open3.pipeline_start("xeyes") {|ts|
  sleep 10
  t = ts[0]
  Process.kill("TERM", t.pid)
  p t.value #=> #<Process::Status: pid 911 SIGTERM (signal 15)>
}

# convert pdf to ps and send it to a printer.
# collect error message of pdftops and lpr.
pdf_file = "paper.pdf"
printer = "printer-name"
err_r, err_w = IO.pipe
Open3.pipeline_start(["pdftops", pdf_file, "-"],
                     ["lpr", "-P#{printer}"],
                     :err=>err_w) {|ts|
  err_w.close
  p err_r.read # error messages of pdftops and lpr.
}


636
637
638
# File 'lib/open3_backport/open3.rb', line 636

def pipeline_start(*cmds, &block)
  raise NotImplementedError
end

.pipeline_w(*cmds, &block) ⇒ Object

Open3.pipeline_w starts a list of commands as a pipeline with a pipe which connects stdin of the first command.

Open3.pipeline_w(cmd1, cmd2, ... [, opts]) {|first_stdin, wait_threads|
  ...
}

first_stdin, wait_threads = Open3.pipeline_w(cmd1, cmd2, ... [, opts])
...
first_stdin.close

Each cmd is a string or an array. If it is an array, the elements are passed to Process.spawn.

cmd:
  commandline                              command line string which is passed to a shell
  [env, commandline, opts]                 command line string which is passed to a shell
  [env, cmdname, arg1, ..., opts]          command name and one or more arguments (no shell)
  [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)

Note that env and opts are optional, as Process.spawn.

Example:

Open3.pipeline_w("bzip2 -c", :out=>"/tmp/hello.bz2") {|i, ts|
  i.puts "hello"
}


594
595
596
# File 'lib/open3_backport/open3.rb', line 594

def pipeline_w(*cmds, &block)
  raise NotImplementedError
end

.popen2(*cmd, &block) ⇒ Object

Open3.popen2 is similer to Open3.popen3 except it doesn’t make a pipe for the standard error stream.

Block form:

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.
}

Non-block form:

stdin, stdout, wait_thr = Open3.popen2([env,] cmd... [, opts])
...
stdin.close  # stdin and stdout should be closed explicitly in this form.
stdout.close

See Process.spawn for the optional hash arguments env and opts.

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("bc -q") {|i,o,t|
  i.puts "obase=13"
  i.puts "6 * 9"
  p o.gets #=> "42\n"
}

Open3.popen2("dc") {|i,o,t|
  i.print "42P"
  i.close
  p o.read #=> "*"
}


149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/open3_backport/open3.rb', line 149

def popen2(*cmd)
  if block_given?
    popen3(*cmd) do |i, o, e, t|
      e.close
      yield(i, o, t)
    end
  else
    i, o, e, t = popen3(*cmd)
    e.close
    return [i, o, t]
  end
end

.popen2e(*cmd, &block) ⇒ Object

Open3.popen2e is similer to Open3.popen3 except it merges the standard output stream and the standard error stream.

Block form:

Open3.popen2e([env,] cmd... [, opts]) {|stdin, stdout_and_stderr, wait_thr|
  pid = wait_thr.pid # pid of the started process.
  ...
  exit_status = wait_thr.value # Process::Status object returned.
}

Non-block form:

stdin, stdout_and_stderr, wait_thr = Open3.popen2e([env,] cmd... [, opts])
...
stdin.close  # stdin and stdout_and_stderr should be closed explicitly in this form.
stdout_and_stderr.close

See Process.spawn for the optional hash arguments env and opts.

Example:

# check gcc warnings
source = "foo.c"
Open3.popen2e("gcc", "-Wall", source) {|i,oe,t|
  oe.each {|line|
    if /warning/ =~ line
      ...
    end
  }
}


192
193
194
195
196
197
198
199
200
201
# File 'lib/open3_backport/open3.rb', line 192

def popen2e(*cmd)
  if block_given?
    popen3(*cmd) do |i, o, e, t|
      yield(i, merged_read_stream(o, e), t)
    end
  else
    i, o, e, t = popen3(*cmd)
    return [i, merged_read_stream(o, e), t]
  end
end

.popen3(*cmd, &block) ⇒ Object

Open stdin, stdout, and stderr streams and start external executable. In addition, a thread for waiting the started process is noticed. The thread has a pid method and thread variable :pid which is the pid of the started process.

Block form:

Open3.popen3([env,] cmd... [, opts]) {|stdin, stdout, stderr, wait_thr|
  pid = wait_thr.pid # pid of the started process.
  ...
  exit_status = wait_thr.value # Process::Status object returned.
}

Non-block form:

stdin, stdout, stderr, wait_thr = Open3.popen3([env,] cmd... [, opts])
pid = wait_thr[:pid]  # pid of the started process.
...
stdin.close  # stdin, stdout and stderr should be closed explicitly in this form.
stdout.close
stderr.close
exit_status = wait_thr.value  # Process::Status object returned.

The parameters cmd... is passed to Process.spawn. So a commandline string and list of argument strings can be accepted as follows.

Open3.popen3("echo a") {|i, o, e, t| ... }
Open3.popen3("echo", "a") {|i, o, e, t| ... }
Open3.popen3(["echo", "argv0"], "a") {|i, o, e, t| ... }

If the last parameter, opts, is a Hash, it is recognized as an option for Process.spawn.

Open3.popen3("pwd", :chdir=>"/") {|i,o,e,t|
  p o.read.chomp #=> "/"
}

wait_thr.value waits the termination of the process. The block form also waits the process when it returns.

Closing stdin, stdout and stderr does not wait the process.



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/open3_backport/open3.rb', line 90

def popen3(*cmd)
  if block_given?
    begin
      pid, stdin, stdout, stderr = Open4::popen4(*cmd)
      wait_thr = detach(pid)
      stdin.sync = true
      return yield(stdin, stdout, stderr, wait_thr)
    ensure
      stdin.close unless stdin.nil? || stdin.closed?
      stdout.close unless stdout.nil? || stdout.closed?
      stderr.close unless stderr.nil? || stderr.closed?
      wait_thr.value unless wait_thr.nil?
    end
  else
    pid, stdin, stdout, stderr = Open4::popen4(*cmd)
    stdin.sync = true
    return [stdin, stdout, stderr, detach(pid)]
  end
end

.popen_run(cmd, opts, child_io, parent_io) ⇒ Object

:nodoc:



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/open3_backport/original_open3.rb', line 201

def popen_run(cmd, opts, child_io, parent_io) # :nodoc:
  pid = spawn(*cmd, opts)
  wait_thr = Process.detach(pid)
  child_io.each {|io| io.close }
  result = [*parent_io, wait_thr]
  if defined? yield
    begin
      return yield(*result)
    ensure
      parent_io.each{|io| io.close unless io.closed?}
      wait_thr.join
    end
  end
  result
end

Instance Method Details

#merged_read_stream(*streams) ⇒ Object

:nodoc:

Raises:

  • (NotImplementedError)


204
205
206
# File 'lib/open3_backport/open3.rb', line 204

def merged_read_stream(*streams) # :nodoc:
  raise NotImplementedError
end