wopen3 0.1 → 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/wopen3.rb +55 -31
- metadata +46 -31
data/lib/wopen3.rb
CHANGED
@@ -1,15 +1,13 @@
|
|
1
|
-
# Copyright 2007 Wincent Colaiuta
|
2
|
-
# $Id$
|
3
|
-
|
4
1
|
# Wopen3 is a replacement for Open3.
|
5
2
|
#
|
6
|
-
# Unlike Open3, Wopen3 does not throw away the exit code of the executed
|
7
|
-
# Only a child process is spawned and the exit status is
|
3
|
+
# Unlike Open3, Wopen3 does not throw away the exit code of the executed
|
4
|
+
# (grandchild) process. Only a child process is spawned and the exit status is
|
5
|
+
# returned in $? as normal.
|
8
6
|
#
|
9
7
|
# Usage example:
|
10
8
|
#
|
11
9
|
# result, errors = '', ''
|
12
|
-
# Wopen3.popen3('
|
10
|
+
# Wopen3.popen3('git', 'log') do |stdin, stdout, stderr|
|
13
11
|
# threads = []
|
14
12
|
# threads << Thread.new(stdout) do |out|
|
15
13
|
# out.each { |line| result << line }
|
@@ -17,53 +15,56 @@
|
|
17
15
|
# threads << Thread.new(stderr) do |err|
|
18
16
|
# err.each { |line| errors << line }
|
19
17
|
# end
|
20
|
-
# threads.each { |thread| thread.join }
|
18
|
+
# threads.each { |thread| thread.join }
|
21
19
|
# end
|
22
20
|
# status = $?.exitstatus
|
23
21
|
# raise "Non-zero exit status #{status}" if status != 0
|
24
22
|
#
|
23
|
+
# As this is such a common usage pattern, a 'system' method is provided as a
|
24
|
+
# convenience:
|
25
|
+
#
|
26
|
+
# result = Wopen3.system('git', 'log')
|
27
|
+
# result.status # => 0
|
28
|
+
# result.stderr # => ''
|
29
|
+
# result.stdout # => 'commit 491411b3...'
|
25
30
|
#
|
26
31
|
module Wopen3
|
27
|
-
|
28
32
|
class Opener
|
29
|
-
|
30
33
|
READ = 0
|
31
34
|
WRITE = 1
|
32
|
-
|
33
|
-
def initialize
|
34
|
-
|
35
|
+
|
36
|
+
def initialize *cmd
|
35
37
|
write_pipe = IO::pipe
|
36
38
|
read_pipe = IO::pipe
|
37
39
|
error_pipe = IO::pipe
|
38
|
-
|
40
|
+
|
39
41
|
pid = fork do
|
40
|
-
|
41
42
|
# in child
|
42
43
|
write_pipe[WRITE].close
|
43
44
|
STDIN.reopen(write_pipe[READ]) # file descriptor duplicated here
|
44
|
-
write_pipe[READ].close # must close in order for parent to
|
45
|
-
|
45
|
+
write_pipe[READ].close # must close in order for parent to
|
46
|
+
# see EOF
|
46
47
|
read_pipe[READ].close
|
47
48
|
STDOUT.reopen(read_pipe[WRITE])
|
48
49
|
read_pipe[WRITE].close
|
49
|
-
|
50
|
+
|
50
51
|
error_pipe[READ].close
|
51
52
|
STDERR.reopen(error_pipe[WRITE])
|
52
53
|
error_pipe[WRITE].close
|
53
|
-
|
54
|
-
exec(*cmd) # will raise SystemCallError if command can't be executed
|
54
|
+
|
55
|
+
exec(*cmd) # will raise SystemCallError if command can't be executed
|
56
|
+
# (eg Errno::NOENT)
|
55
57
|
exit! # should never get here
|
56
|
-
|
57
58
|
end
|
58
|
-
|
59
|
+
|
59
60
|
# in parent
|
60
61
|
write_pipe[READ].close
|
61
62
|
read_pipe[WRITE].close
|
62
63
|
error_pipe[WRITE].close
|
63
|
-
|
64
|
+
|
64
65
|
pipes = [write_pipe[WRITE], read_pipe[READ], error_pipe[READ]]
|
65
66
|
write_pipe[WRITE].sync = true
|
66
|
-
|
67
|
+
|
67
68
|
if defined? yield
|
68
69
|
begin
|
69
70
|
result = yield(*pipes)
|
@@ -73,17 +74,40 @@ module Wopen3
|
|
73
74
|
pipes.each { |pipe| pipe.close unless pipe.closed? }
|
74
75
|
end
|
75
76
|
end
|
76
|
-
|
77
|
-
# can't wait immediately (will hang); wait once garbage collection
|
77
|
+
|
78
|
+
# can't wait immediately (will hang); wait once garbage collection
|
79
|
+
# destroys/finalizes this instance
|
78
80
|
ObjectSpace.define_finalizer(self, proc { Process.waitpid(pid) })
|
79
81
|
pipes
|
80
|
-
|
81
82
|
end
|
82
|
-
|
83
|
+
end # class Opener
|
84
|
+
|
85
|
+
class Result
|
86
|
+
attr_reader :args, :status, :stderr, :stdout
|
87
|
+
|
88
|
+
def initialize *args
|
89
|
+
@args = args
|
90
|
+
@stderr = ''
|
91
|
+
@stdout = ''
|
92
|
+
Wopen3.popen3 *args do |stdin, stdout, stderr|
|
93
|
+
threads = []
|
94
|
+
threads << Thread.new(stdout) do |out|
|
95
|
+
out.each { |line| @stdout << line }
|
96
|
+
end
|
97
|
+
threads << Thread.new(stderr) do |err|
|
98
|
+
err.each { |line| @stderr << line }
|
99
|
+
end
|
100
|
+
threads.each { |thread| thread.join }
|
101
|
+
end
|
102
|
+
@status = $?.exitstatus
|
103
|
+
end
|
104
|
+
end # class Result
|
105
|
+
|
106
|
+
def self.popen3 *cmd, &block
|
107
|
+
Opener.new *cmd, &block
|
83
108
|
end
|
84
|
-
|
85
|
-
def self.
|
86
|
-
|
109
|
+
|
110
|
+
def self.system *args
|
111
|
+
Result.new *args
|
87
112
|
end
|
88
|
-
|
89
113
|
end # module Wopen3
|
metadata
CHANGED
@@ -1,46 +1,61 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.2
|
3
|
-
specification_version: 1
|
4
2
|
name: wopen3
|
5
3
|
version: !ruby/object:Gem::Version
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
email: win@wincent.com
|
12
|
-
homepage: http://wincent.com/a/products/walrus/wopen3/
|
13
|
-
rubyforge_project:
|
14
|
-
description: Unlike Open3, Wopen3 does not throw away the exit code of the executed (grandchild) process. Only a child process is spawned and the exit status is returned in $? as normal.
|
15
|
-
autorequire: wopen3
|
16
|
-
default_executable:
|
17
|
-
bindir: bin
|
18
|
-
has_rdoc: false
|
19
|
-
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.0.0
|
24
|
-
version:
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 2
|
8
|
+
version: "0.2"
|
25
9
|
platform: ruby
|
26
|
-
signing_key:
|
27
|
-
cert_chain:
|
28
|
-
post_install_message:
|
29
10
|
authors:
|
30
11
|
- Wincent Colaiuta
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
rdoc_options: []
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
36
15
|
|
37
|
-
|
16
|
+
date: 2010-07-28 00:00:00 +02:00
|
17
|
+
default_executable:
|
18
|
+
dependencies: []
|
38
19
|
|
20
|
+
description: " Unlike Open3, Wopen3 does not throw away the exit code of the executed\n (grandchild) process. Only a child process is spawned and the exit\n status is returned in $? as normal.\n"
|
21
|
+
email: win@wincent.com
|
39
22
|
executables: []
|
40
23
|
|
41
24
|
extensions: []
|
42
25
|
|
26
|
+
extra_rdoc_files: []
|
27
|
+
|
28
|
+
files:
|
29
|
+
- lib/wopen3.rb
|
30
|
+
has_rdoc: false
|
31
|
+
homepage: https://wincent.com/products/wopen3
|
32
|
+
licenses: []
|
33
|
+
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
segments:
|
51
|
+
- 0
|
52
|
+
version: "0"
|
43
53
|
requirements: []
|
44
54
|
|
45
|
-
|
55
|
+
rubyforge_project: walrus
|
56
|
+
rubygems_version: 1.3.6
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: Wopen3 is a simple replacement for Open3
|
60
|
+
test_files: []
|
46
61
|
|