open4 1.1.0 → 1.2.0
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/README +38 -0
- data/README.erb +38 -0
- data/lib/open4.rb +61 -25
- data/open4.gemspec +8 -2
- data/{Rakefile → rakefile} +2 -13
- data/samples/pfork4.rb +24 -0
- data/test/pfork4_test.rb +150 -0
- data/test/popen4_test.rb +82 -0
- data/test/support/test_case.rb +23 -0
- metadata +22 -5
data/README
CHANGED
@@ -193,6 +193,44 @@ SAMPLES
|
|
193
193
|
42
|
194
194
|
/dmsp/reference/ruby-1.8.1//lib/ruby/1.8/timeout.rb:42:in `relay': execution expired (Timeout::Error)
|
195
195
|
|
196
|
+
----------------------------------------------------------------------------
|
197
|
+
pfork4 is similar to popen4, but instead of executing a command, it runs
|
198
|
+
ruby code in a child process. if the child process raises an exception, it
|
199
|
+
propagates to the parent.
|
200
|
+
----------------------------------------------------------------------------
|
201
|
+
|
202
|
+
harp: > cat sample/pfork4.rb
|
203
|
+
require 'open4'
|
204
|
+
|
205
|
+
echo = lambda do
|
206
|
+
$stdout.write $stdin.read
|
207
|
+
raise 'finish implementing me'
|
208
|
+
end
|
209
|
+
|
210
|
+
org_message = "hello, world!"
|
211
|
+
got_message = nil
|
212
|
+
exception = nil
|
213
|
+
|
214
|
+
begin
|
215
|
+
Open4.pfork4(echo) do |cid, stdin, stdout, stderr|
|
216
|
+
stdin.write org_message
|
217
|
+
stdin.close
|
218
|
+
got_message = stdout.read
|
219
|
+
end
|
220
|
+
rescue RuntimeError => e
|
221
|
+
exception = e.to_s
|
222
|
+
end
|
223
|
+
|
224
|
+
puts "org_message: #{org_message}"
|
225
|
+
puts "got_message: #{got_message}"
|
226
|
+
puts "exception : #{exception}"
|
227
|
+
|
228
|
+
|
229
|
+
harp: > ruby sample/pfork4.rb
|
230
|
+
org_message: hello, world!
|
231
|
+
got_message: hello, world!
|
232
|
+
exception : finish implementing me
|
233
|
+
|
196
234
|
HISTORY
|
197
235
|
1.0.0
|
198
236
|
- added ability for spawn to take a proc (respond_to?(:call))
|
data/README.erb
CHANGED
@@ -193,6 +193,44 @@ SAMPLES
|
|
193
193
|
42
|
194
194
|
/dmsp/reference/ruby-1.8.1//lib/ruby/1.8/timeout.rb:42:in `relay': execution expired (Timeout::Error)
|
195
195
|
|
196
|
+
----------------------------------------------------------------------------
|
197
|
+
pfork4 is similar to popen4, but instead of executing a command, it runs
|
198
|
+
ruby code in a child process. if the child process raises an exception, it
|
199
|
+
propagates to the parent.
|
200
|
+
----------------------------------------------------------------------------
|
201
|
+
|
202
|
+
harp: > cat sample/pfork4.rb
|
203
|
+
require 'open4'
|
204
|
+
|
205
|
+
echo = lambda do
|
206
|
+
$stdout.write $stdin.read
|
207
|
+
raise 'finish implementing me'
|
208
|
+
end
|
209
|
+
|
210
|
+
org_message = "hello, world!"
|
211
|
+
got_message = nil
|
212
|
+
exception = nil
|
213
|
+
|
214
|
+
begin
|
215
|
+
Open4.pfork4(echo) do |cid, stdin, stdout, stderr|
|
216
|
+
stdin.write org_message
|
217
|
+
stdin.close
|
218
|
+
got_message = stdout.read
|
219
|
+
end
|
220
|
+
rescue RuntimeError => e
|
221
|
+
exception = e.to_s
|
222
|
+
end
|
223
|
+
|
224
|
+
puts "org_message: #{org_message}"
|
225
|
+
puts "got_message: #{got_message}"
|
226
|
+
puts "exception : #{exception}"
|
227
|
+
|
228
|
+
|
229
|
+
harp: > ruby sample/pfork4.rb
|
230
|
+
org_message: hello, world!
|
231
|
+
got_message: hello, world!
|
232
|
+
exception : finish implementing me
|
233
|
+
|
196
234
|
HISTORY
|
197
235
|
1.0.0
|
198
236
|
- added ability for spawn to take a proc (respond_to?(:call))
|
data/lib/open4.rb
CHANGED
@@ -4,19 +4,46 @@ require 'timeout'
|
|
4
4
|
require 'thread'
|
5
5
|
|
6
6
|
module Open4
|
7
|
-
VERSION = '1.
|
7
|
+
VERSION = '1.2.0'
|
8
8
|
def self.version() VERSION end
|
9
9
|
|
10
10
|
class Error < ::StandardError; end
|
11
11
|
|
12
|
+
def pfork4(fun, &b)
|
13
|
+
Open4.do_popen(b, :block) do |ps_read, _|
|
14
|
+
ps_read.close
|
15
|
+
begin
|
16
|
+
fun.call
|
17
|
+
rescue SystemExit => e
|
18
|
+
# Make it seem to the caller that calling Kernel#exit in +fun+ kills
|
19
|
+
# the child process normally. Kernel#exit! bypasses this rescue
|
20
|
+
# block.
|
21
|
+
exit! e.status
|
22
|
+
else
|
23
|
+
exit! 0
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
module_function :pfork4
|
28
|
+
|
12
29
|
def popen4(*cmd, &b)
|
30
|
+
Open4.do_popen(b, :init) do |ps_read, ps_write|
|
31
|
+
ps_read.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
32
|
+
ps_write.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
33
|
+
exec(*cmd)
|
34
|
+
raise 'forty-two' # Is this really needed?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
alias open4 popen4
|
38
|
+
module_function :popen4
|
39
|
+
module_function :open4
|
40
|
+
|
41
|
+
def self.do_popen(b = nil, exception_propagation_at = nil, &cmd)
|
13
42
|
pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe
|
14
43
|
|
15
44
|
verbose = $VERBOSE
|
16
45
|
begin
|
17
46
|
$VERBOSE = nil
|
18
|
-
ps.first.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
19
|
-
ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
20
47
|
|
21
48
|
cid = fork {
|
22
49
|
pw.last.close
|
@@ -34,48 +61,57 @@ module Open4
|
|
34
61
|
STDOUT.sync = STDERR.sync = true
|
35
62
|
|
36
63
|
begin
|
37
|
-
|
38
|
-
raise 'forty-two'
|
64
|
+
cmd.call(ps)
|
39
65
|
rescue Exception => e
|
40
66
|
Marshal.dump(e, ps.last)
|
41
67
|
ps.last.flush
|
68
|
+
ensure
|
69
|
+
ps.last.close unless ps.last.closed?
|
42
70
|
end
|
43
|
-
|
71
|
+
|
44
72
|
exit!
|
45
73
|
}
|
46
74
|
ensure
|
47
75
|
$VERBOSE = verbose
|
48
76
|
end
|
49
77
|
|
50
|
-
[pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close}
|
78
|
+
[ pw.first, pr.last, pe.last, ps.last ].each { |fd| fd.close }
|
51
79
|
|
52
|
-
|
53
|
-
e = Marshal.load ps.first
|
54
|
-
raise(Exception === e ? e : "unknown failure!")
|
55
|
-
rescue EOFError # If we get an EOF error, then the exec was successful
|
56
|
-
42
|
57
|
-
ensure
|
58
|
-
ps.first.close
|
59
|
-
end
|
80
|
+
Open4.propagate_exception cid, ps.first if exception_propagation_at == :init
|
60
81
|
|
61
82
|
pw.last.sync = true
|
62
83
|
|
63
|
-
pi = [pw.last, pr.first, pe.first]
|
84
|
+
pi = [ pw.last, pr.first, pe.first ]
|
85
|
+
|
86
|
+
begin
|
87
|
+
return [cid, *pi] unless b
|
64
88
|
|
65
|
-
if b
|
66
89
|
begin
|
67
|
-
b
|
68
|
-
Process.waitpid2(cid).last
|
90
|
+
b.call(cid, *pi)
|
69
91
|
ensure
|
70
|
-
pi.each{|fd| fd.close unless fd.closed?}
|
92
|
+
pi.each { |fd| fd.close unless fd.closed? }
|
71
93
|
end
|
72
|
-
|
73
|
-
|
94
|
+
|
95
|
+
Open4.propagate_exception cid, ps.first if exception_propagation_at == :block
|
96
|
+
|
97
|
+
Process.waitpid2(cid).last
|
98
|
+
ensure
|
99
|
+
ps.first.close unless ps.first.closed?
|
74
100
|
end
|
75
101
|
end
|
76
|
-
|
77
|
-
|
78
|
-
|
102
|
+
|
103
|
+
def self.propagate_exception(cid, ps_read)
|
104
|
+
e = Marshal.load ps_read
|
105
|
+
raise Exception === e ? e : "unknown failure!"
|
106
|
+
rescue EOFError
|
107
|
+
# Child process did not raise exception.
|
108
|
+
rescue
|
109
|
+
# Child process raised exception; wait it in order to avoid a zombie.
|
110
|
+
Process.waitpid2 cid
|
111
|
+
raise
|
112
|
+
ensure
|
113
|
+
ps_read.close
|
114
|
+
end
|
79
115
|
|
80
116
|
class SpawnError < Error
|
81
117
|
attr 'cmd'
|
data/open4.gemspec
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
Gem::Specification::new do |spec|
|
5
5
|
spec.name = "open4"
|
6
|
-
spec.version = "1.
|
6
|
+
spec.version = "1.2.0"
|
7
7
|
spec.platform = Gem::Platform::RUBY
|
8
8
|
spec.summary = "open4"
|
9
9
|
spec.description = "description: open4 kicks the ass"
|
@@ -12,19 +12,25 @@ Gem::Specification::new do |spec|
|
|
12
12
|
["LICENSE",
|
13
13
|
"README",
|
14
14
|
"README.erb",
|
15
|
-
"Rakefile",
|
16
15
|
"lib",
|
17
16
|
"lib/open4.rb",
|
18
17
|
"open4.gemspec",
|
18
|
+
"rakefile",
|
19
19
|
"samples",
|
20
20
|
"samples/bg.rb",
|
21
21
|
"samples/block.rb",
|
22
22
|
"samples/exception.rb",
|
23
23
|
"samples/jesse-caldwell.rb",
|
24
|
+
"samples/pfork4.rb",
|
24
25
|
"samples/simple.rb",
|
25
26
|
"samples/spawn.rb",
|
26
27
|
"samples/stdin_timeout.rb",
|
27
28
|
"samples/timeout.rb",
|
29
|
+
"test",
|
30
|
+
"test/pfork4_test.rb",
|
31
|
+
"test/popen4_test.rb",
|
32
|
+
"test/support",
|
33
|
+
"test/support/test_case.rb",
|
28
34
|
"white_box",
|
29
35
|
"white_box/leak.rb"]
|
30
36
|
|
data/{Rakefile → rakefile}
RENAMED
@@ -9,19 +9,8 @@ task :default do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
task :test do
|
12
|
-
run_tests!
|
13
|
-
end
|
14
|
-
|
15
|
-
namespace :test do
|
16
|
-
task(:unit){ run_tests!(:unit) }
|
17
|
-
task(:functional){ run_tests!(:functional) }
|
18
|
-
task(:integration){ run_tests!(:integration) }
|
19
|
-
end
|
20
|
-
|
21
|
-
def run_tests!(which = nil)
|
22
|
-
which ||= '**'
|
23
12
|
test_dir = File.join(This.dir, "test")
|
24
|
-
test_glob ||= File.join(test_dir, "
|
13
|
+
test_glob ||= File.join(test_dir, "/**_test.rb")
|
25
14
|
test_rbs = Dir.glob(test_glob).sort
|
26
15
|
|
27
16
|
div = ('=' * 119)
|
@@ -29,7 +18,7 @@ def run_tests!(which = nil)
|
|
29
18
|
|
30
19
|
test_rbs.each_with_index do |test_rb, index|
|
31
20
|
testno = index + 1
|
32
|
-
command = "#{ This.ruby } -I ./lib -I ./test/
|
21
|
+
command = "#{ This.ruby } -rubygems -I ./lib -I ./test/support #{ test_rb }"
|
33
22
|
|
34
23
|
puts
|
35
24
|
say(div, :color => :cyan, :bold => true)
|
data/samples/pfork4.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'open4'
|
2
|
+
|
3
|
+
echo = lambda do
|
4
|
+
$stdout.write $stdin.read
|
5
|
+
raise 'finish implementing me'
|
6
|
+
end
|
7
|
+
|
8
|
+
org_message = "hello, world!"
|
9
|
+
got_message = nil
|
10
|
+
exception = nil
|
11
|
+
|
12
|
+
begin
|
13
|
+
Open4.pfork4(echo) do |cid, stdin, stdout, stderr|
|
14
|
+
stdin.write org_message
|
15
|
+
stdin.close
|
16
|
+
got_message = stdout.read
|
17
|
+
end
|
18
|
+
rescue RuntimeError => e
|
19
|
+
exception = e.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
puts "org_message: #{org_message}"
|
23
|
+
puts "got_message: #{got_message}"
|
24
|
+
puts "exception : #{exception}"
|
data/test/pfork4_test.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'test_case'
|
2
|
+
|
3
|
+
module Open4
|
4
|
+
|
5
|
+
class PFork4Test < TestCase
|
6
|
+
def test_fun_successful_return
|
7
|
+
fun = lambda { 'lucky me' }
|
8
|
+
cid, _ = pfork4 fun
|
9
|
+
assert_equal 0, wait_status(cid)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_fun_force_exit
|
13
|
+
exit_code = 43
|
14
|
+
fun = lambda { exit! exit_code }
|
15
|
+
cid, _ = pfork4 fun
|
16
|
+
assert_equal exit_code, wait_status(cid)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_fun_normal_exit
|
20
|
+
exit_code = 43
|
21
|
+
fun = lambda { exit exit_code }
|
22
|
+
cid, _ = pfork4 fun
|
23
|
+
assert_equal exit_code, wait_status(cid)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_fun_does_not_propagate_exception_without_block
|
27
|
+
fun = lambda { raise MyError }
|
28
|
+
cid, _ = pfork4 fun
|
29
|
+
refute_equal 0, wait_status(cid)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_fun_propagate_exception_with_block
|
33
|
+
fun = lambda { raise MyError }
|
34
|
+
assert_raises(MyError) { pfork4(fun) {} }
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_fun_propagate_exception_with_block_avoids_zombie_child_process
|
38
|
+
fun = lambda { raise MyError }
|
39
|
+
assert_raises(MyError) { pfork4(fun) {} }
|
40
|
+
assert_empty Process.waitall
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_call_block_upon_exception
|
44
|
+
fun = lambda { raise MyError }
|
45
|
+
block_called = false
|
46
|
+
assert_raises(MyError) { pfork4(fun) { block_called = true } }
|
47
|
+
assert_equal true, block_called
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_passes_child_pid_to_block
|
51
|
+
fun = lambda { $stdout.write Process.pid }
|
52
|
+
cid_in_block = nil
|
53
|
+
cid_in_fun = nil
|
54
|
+
status = pfork4(fun) do |cid, _, stdout, _|
|
55
|
+
cid_in_block = cid
|
56
|
+
cid_in_fun = stdout.read.to_i
|
57
|
+
end
|
58
|
+
assert_equal cid_in_fun, cid_in_block
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_io_pipes_without_block
|
62
|
+
via_msg = 'foo'
|
63
|
+
err_msg = 'bar'
|
64
|
+
fun = lambda do
|
65
|
+
$stdout.write $stdin.read
|
66
|
+
$stderr.write err_msg
|
67
|
+
end
|
68
|
+
out_actual, err_actual = nil, nil
|
69
|
+
cid, stdin, stdout, stderr = pfork4 fun
|
70
|
+
stdin.write via_msg
|
71
|
+
stdin.close
|
72
|
+
out_actual = stdout.read
|
73
|
+
err_actual = stderr.read
|
74
|
+
assert_equal via_msg, out_actual
|
75
|
+
assert_equal err_msg, err_actual
|
76
|
+
assert_equal 0, wait_status(cid)
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_io_pipes_with_block
|
80
|
+
via_msg = 'foo'
|
81
|
+
err_msg = 'bar'
|
82
|
+
fun = lambda do
|
83
|
+
$stdout.write $stdin.read
|
84
|
+
$stderr.write err_msg
|
85
|
+
end
|
86
|
+
out_actual, err_actual = nil, nil
|
87
|
+
status = pfork4(fun) do |_, stdin, stdout, stderr|
|
88
|
+
stdin.write via_msg
|
89
|
+
stdin.close
|
90
|
+
out_actual = stdout.read
|
91
|
+
err_actual = stderr.read
|
92
|
+
end
|
93
|
+
assert_equal via_msg, out_actual
|
94
|
+
assert_equal err_msg, err_actual
|
95
|
+
assert_equal 0, status.exitstatus
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_exec_in_fun
|
99
|
+
via_msg = 'foo'
|
100
|
+
fun = lambda { exec %{ruby -e "print '#{via_msg}'"} }
|
101
|
+
out_actual = nil
|
102
|
+
status = pfork4(fun) do |_, stdin, stdout, _|
|
103
|
+
stdin.close
|
104
|
+
out_actual = stdout.read
|
105
|
+
end
|
106
|
+
assert_equal via_msg, out_actual
|
107
|
+
assert_equal 0, status.exitstatus
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_io_pipes_and_then_exception_propagation_with_block
|
111
|
+
via_msg = 'foo'
|
112
|
+
err_msg = 'bar'
|
113
|
+
fun = lambda do
|
114
|
+
$stdout.write $stdin.read
|
115
|
+
$stderr.write err_msg
|
116
|
+
raise MyError
|
117
|
+
end
|
118
|
+
out_actual, err_actual = nil, nil
|
119
|
+
assert_raises(MyError) do
|
120
|
+
pfork4(fun) do |_, stdin, stdout, stderr|
|
121
|
+
stdin.write via_msg
|
122
|
+
stdin.close
|
123
|
+
out_actual = stdout.read
|
124
|
+
err_actual = stderr.read
|
125
|
+
end
|
126
|
+
end
|
127
|
+
assert_equal via_msg, out_actual
|
128
|
+
assert_equal err_msg, err_actual
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_blocked_on_io_read_and_exception_propagation_with_block
|
132
|
+
fun = lambda do
|
133
|
+
$stdin.read
|
134
|
+
raise MyError
|
135
|
+
end
|
136
|
+
out_actual, err_actual = nil, nil
|
137
|
+
assert_raises(MyError) do
|
138
|
+
pfork4(fun) do |_, stdin, stdout, stderr|
|
139
|
+
stdin.write 'foo'
|
140
|
+
stdin.close
|
141
|
+
out_actual = stdout.read
|
142
|
+
err_actual = stderr.read
|
143
|
+
end
|
144
|
+
end
|
145
|
+
assert_equal '', out_actual
|
146
|
+
assert_equal '', err_actual
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
data/test/popen4_test.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'test_case'
|
2
|
+
|
3
|
+
module Open4
|
4
|
+
|
5
|
+
class POpen4Test < TestCase
|
6
|
+
UNKNOWN_CMD = 'asdfadsfjlkkk'
|
7
|
+
UNKNOWN_CMD_ERRORS = [Errno::ENOENT, Errno::EINVAL]
|
8
|
+
|
9
|
+
def test_unknown_command_propagates_exception
|
10
|
+
err = assert_raises(*UNKNOWN_CMD_ERRORS) { popen4 UNKNOWN_CMD }
|
11
|
+
assert_match /#{UNKNOWN_CMD}/, err.to_s if on_mri?
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_exception_propagation_avoids_zombie_child_process
|
15
|
+
assert_raises(*UNKNOWN_CMD_ERRORS) { popen4 UNKNOWN_CMD }
|
16
|
+
assert_empty Process.waitall
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_exit_failure
|
20
|
+
code = 43
|
21
|
+
cid, _ = popen4 %{ruby -e "exit #{43}"}
|
22
|
+
assert_equal code, wait_status(cid)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_exit_success
|
26
|
+
cid, _ = popen4 %{ruby -e "exit"}
|
27
|
+
assert_equal 0, wait_status(cid)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_passes_child_pid_to_block
|
31
|
+
cmd = %{ruby -e "STDOUT.print Process.pid"}
|
32
|
+
cid_in_block = nil
|
33
|
+
cid_in_fun = nil
|
34
|
+
status = popen4(cmd) do |cid, _, stdout, _|
|
35
|
+
cid_in_block = cid
|
36
|
+
cid_in_fun = stdout.read.to_i
|
37
|
+
end
|
38
|
+
assert_equal cid_in_fun, cid_in_block
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_io_pipes_without_block
|
42
|
+
via_msg = 'foo'
|
43
|
+
err_msg = 'bar'
|
44
|
+
cmd = <<-END
|
45
|
+
ruby -e "
|
46
|
+
STDOUT.write STDIN.read
|
47
|
+
STDERR.write '#{err_msg}'
|
48
|
+
"
|
49
|
+
END
|
50
|
+
cid, stdin, stdout, stderr = popen4 cmd
|
51
|
+
stdin.write via_msg
|
52
|
+
stdin.close
|
53
|
+
out_actual = stdout.read
|
54
|
+
err_actual = stderr.read
|
55
|
+
assert_equal via_msg, out_actual
|
56
|
+
assert_equal err_msg, err_actual
|
57
|
+
assert_equal 0, wait_status(cid)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_io_pipes_with_block
|
61
|
+
via_msg = 'foo'
|
62
|
+
err_msg = 'bar'
|
63
|
+
out_actual, err_actual = nil
|
64
|
+
cmd = <<-END
|
65
|
+
ruby -e "
|
66
|
+
STDOUT.write STDIN.read
|
67
|
+
STDERR.write '#{err_msg}'
|
68
|
+
"
|
69
|
+
END
|
70
|
+
status = popen4(cmd) do |_, stdin, stdout, stderr|
|
71
|
+
stdin.write via_msg
|
72
|
+
stdin.close
|
73
|
+
out_actual = stdout.read
|
74
|
+
err_actual = stderr.read
|
75
|
+
end
|
76
|
+
assert_equal via_msg, out_actual
|
77
|
+
assert_equal err_msg, err_actual
|
78
|
+
assert_equal 0, status.exitstatus
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'open4'
|
5
|
+
require 'rbconfig'
|
6
|
+
|
7
|
+
module Open4
|
8
|
+
class TestCase < MiniTest::Unit::TestCase
|
9
|
+
include Open4
|
10
|
+
|
11
|
+
# Custom exception class for tests so we don't shadow possible
|
12
|
+
# programming errors.
|
13
|
+
class MyError < RuntimeError; end
|
14
|
+
|
15
|
+
def on_mri?
|
16
|
+
::Config::CONFIG['ruby_install_name'] == 'ruby'
|
17
|
+
end
|
18
|
+
|
19
|
+
def wait_status(cid)
|
20
|
+
Process.waitpid2(cid).last.exitstatus
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
metadata
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: open4
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 31
|
4
5
|
prerelease:
|
5
|
-
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 1.2.0
|
6
11
|
platform: ruby
|
7
12
|
authors:
|
8
13
|
- Ara T. Howard
|
@@ -10,7 +15,7 @@ autorequire:
|
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
17
|
|
13
|
-
date: 2011-
|
18
|
+
date: 2011-10-05 00:00:00 Z
|
14
19
|
dependencies: []
|
15
20
|
|
16
21
|
description: "description: open4 kicks the ass"
|
@@ -25,21 +30,27 @@ files:
|
|
25
30
|
- LICENSE
|
26
31
|
- README
|
27
32
|
- README.erb
|
28
|
-
- Rakefile
|
29
33
|
- lib/open4.rb
|
30
34
|
- open4.gemspec
|
35
|
+
- rakefile
|
31
36
|
- samples/bg.rb
|
32
37
|
- samples/block.rb
|
33
38
|
- samples/exception.rb
|
34
39
|
- samples/jesse-caldwell.rb
|
40
|
+
- samples/pfork4.rb
|
35
41
|
- samples/simple.rb
|
36
42
|
- samples/spawn.rb
|
37
43
|
- samples/stdin_timeout.rb
|
38
44
|
- samples/timeout.rb
|
45
|
+
- test/pfork4_test.rb
|
46
|
+
- test/popen4_test.rb
|
47
|
+
- test/support/test_case.rb
|
39
48
|
- white_box/leak.rb
|
40
49
|
homepage: https://github.com/ahoward/open4
|
41
50
|
licenses: []
|
42
51
|
|
52
|
+
metadata: {}
|
53
|
+
|
43
54
|
post_install_message:
|
44
55
|
rdoc_options: []
|
45
56
|
|
@@ -50,19 +61,25 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
50
61
|
requirements:
|
51
62
|
- - ">="
|
52
63
|
- !ruby/object:Gem::Version
|
64
|
+
hash: 3
|
65
|
+
segments:
|
66
|
+
- 0
|
53
67
|
version: "0"
|
54
68
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
69
|
none: false
|
56
70
|
requirements:
|
57
71
|
- - ">="
|
58
72
|
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
74
|
+
segments:
|
75
|
+
- 0
|
59
76
|
version: "0"
|
60
77
|
requirements: []
|
61
78
|
|
62
79
|
rubyforge_project: codeforpeople
|
63
|
-
rubygems_version: 1.
|
80
|
+
rubygems_version: 1.8.10
|
64
81
|
signing_key:
|
65
|
-
specification_version:
|
82
|
+
specification_version: 4
|
66
83
|
summary: open4
|
67
84
|
test_files: []
|
68
85
|
|