open4 1.0.1 → 1.3.4
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.
- checksums.yaml +15 -0
- data/LICENSE +3 -0
- data/README +38 -0
- data/README.erb +38 -0
- data/lib/open4.rb +109 -73
- data/open4.gemspec +32 -7
- data/rakefile +394 -0
- data/samples/jesse-caldwell.rb +131 -0
- data/samples/pfork4.rb +24 -0
- data/test/lib/test_case.rb +23 -0
- data/test/pfork4_test.rb +150 -0
- data/test/popen4_test.rb +82 -0
- data/test/popen4ext_test.rb +89 -0
- metadata +35 -38
- data/Rakefile +0 -225
data/rakefile
ADDED
@@ -0,0 +1,394 @@
|
|
1
|
+
This.rubyforge_project = 'codeforpeople'
|
2
|
+
This.author = "Ara T. Howard"
|
3
|
+
This.email = "ara.t.howard@gmail.com"
|
4
|
+
This.homepage = "https://github.com/ahoward/#{ This.lib }"
|
5
|
+
|
6
|
+
task :license do
|
7
|
+
open('LICENSE', 'w'){|fd| fd.puts "Ruby"}
|
8
|
+
end
|
9
|
+
|
10
|
+
task :default do
|
11
|
+
puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
|
12
|
+
end
|
13
|
+
|
14
|
+
task :test do
|
15
|
+
run_tests!
|
16
|
+
end
|
17
|
+
|
18
|
+
namespace :test do
|
19
|
+
task(:unit){ run_tests!(:unit) }
|
20
|
+
task(:functional){ run_tests!(:functional) }
|
21
|
+
task(:integration){ run_tests!(:integration) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def run_tests!(which = nil)
|
25
|
+
which ||= '**'
|
26
|
+
test_dir = File.join(This.dir, "test")
|
27
|
+
test_glob ||= File.join(test_dir, "#{ which }/**_test.rb")
|
28
|
+
test_rbs = Dir.glob(test_glob).sort
|
29
|
+
|
30
|
+
div = ('=' * 119)
|
31
|
+
line = ('-' * 119)
|
32
|
+
|
33
|
+
test_rbs.each_with_index do |test_rb, index|
|
34
|
+
testno = index + 1
|
35
|
+
command = "#{ This.ruby } -rubygems -w -I ./lib -I ./test/lib #{ test_rb }"
|
36
|
+
|
37
|
+
puts
|
38
|
+
say(div, :color => :cyan, :bold => true)
|
39
|
+
say("@#{ testno } => ", :bold => true, :method => :print)
|
40
|
+
say(command, :color => :cyan, :bold => true)
|
41
|
+
say(line, :color => :cyan, :bold => true)
|
42
|
+
|
43
|
+
system(command)
|
44
|
+
|
45
|
+
say(line, :color => :cyan, :bold => true)
|
46
|
+
|
47
|
+
status = $?.exitstatus
|
48
|
+
|
49
|
+
if status.zero?
|
50
|
+
say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
|
51
|
+
say("SUCCESS", :color => :green, :bold => true)
|
52
|
+
else
|
53
|
+
say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
|
54
|
+
say("FAILURE", :color => :red, :bold => true)
|
55
|
+
end
|
56
|
+
say(line, :color => :cyan, :bold => true)
|
57
|
+
|
58
|
+
exit(status) unless status.zero?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
task :gemspec do
|
64
|
+
ignore_extensions = ['git', 'svn', 'tmp', /sw./, 'bak', 'gem']
|
65
|
+
ignore_directories = ['pkg']
|
66
|
+
ignore_files = ['test/log']
|
67
|
+
|
68
|
+
shiteless =
|
69
|
+
lambda do |list|
|
70
|
+
list.delete_if do |entry|
|
71
|
+
next unless test(?e, entry)
|
72
|
+
extension = File.basename(entry).split(%r/[.]/).last
|
73
|
+
ignore_extensions.any?{|ext| ext === extension}
|
74
|
+
end
|
75
|
+
list.delete_if do |entry|
|
76
|
+
next unless test(?d, entry)
|
77
|
+
dirname = File.expand_path(entry)
|
78
|
+
ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
|
79
|
+
end
|
80
|
+
list.delete_if do |entry|
|
81
|
+
next unless test(?f, entry)
|
82
|
+
filename = File.expand_path(entry)
|
83
|
+
ignore_files.any?{|file| File.expand_path(file) == filename}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
lib = This.lib
|
88
|
+
object = This.object
|
89
|
+
version = This.version
|
90
|
+
files = shiteless[Dir::glob("**/**")]
|
91
|
+
executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
|
92
|
+
#has_rdoc = true #File.exist?('doc')
|
93
|
+
test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
|
94
|
+
summary = object.respond_to?(:summary) ? object.summary : "summary: #{ lib } kicks the ass"
|
95
|
+
description = object.respond_to?(:description) ? object.description : "description: #{ lib } kicks the ass"
|
96
|
+
license = object.respond_to?(:license) ? object.license : "Ruby"
|
97
|
+
|
98
|
+
if This.extensions.nil?
|
99
|
+
This.extensions = []
|
100
|
+
extensions = This.extensions
|
101
|
+
%w( Makefile configure extconf.rb ).each do |ext|
|
102
|
+
extensions << ext if File.exists?(ext)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
extensions = [extensions].flatten.compact
|
106
|
+
|
107
|
+
if This.dependencies.nil?
|
108
|
+
dependencies = []
|
109
|
+
else
|
110
|
+
case This.dependencies
|
111
|
+
when Hash
|
112
|
+
dependencies = This.dependencies.values
|
113
|
+
when Array
|
114
|
+
dependencies = This.dependencies
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
template =
|
119
|
+
if test(?e, 'gemspec.erb')
|
120
|
+
Template{ IO.read('gemspec.erb') }
|
121
|
+
else
|
122
|
+
Template {
|
123
|
+
<<-__
|
124
|
+
## <%= lib %>.gemspec
|
125
|
+
#
|
126
|
+
|
127
|
+
Gem::Specification::new do |spec|
|
128
|
+
spec.name = <%= lib.inspect %>
|
129
|
+
spec.version = <%= version.inspect %>
|
130
|
+
spec.platform = Gem::Platform::RUBY
|
131
|
+
spec.summary = <%= lib.inspect %>
|
132
|
+
spec.description = <%= description.inspect %>
|
133
|
+
spec.license = <%= license.inspect %>
|
134
|
+
|
135
|
+
spec.files =\n<%= files.sort.pretty_inspect %>
|
136
|
+
spec.executables = <%= executables.inspect %>
|
137
|
+
|
138
|
+
spec.require_path = "lib"
|
139
|
+
|
140
|
+
spec.test_files = <%= test_files.inspect %>
|
141
|
+
|
142
|
+
<% dependencies.each do |lib_version| %>
|
143
|
+
spec.add_dependency(*<%= Array(lib_version).flatten.inspect %>)
|
144
|
+
<% end %>
|
145
|
+
|
146
|
+
spec.extensions.push(*<%= extensions.inspect %>)
|
147
|
+
|
148
|
+
spec.rubyforge_project = <%= This.rubyforge_project.inspect %>
|
149
|
+
spec.author = <%= This.author.inspect %>
|
150
|
+
spec.email = <%= This.email.inspect %>
|
151
|
+
spec.homepage = <%= This.homepage.inspect %>
|
152
|
+
end
|
153
|
+
__
|
154
|
+
}
|
155
|
+
end
|
156
|
+
|
157
|
+
Fu.mkdir_p(This.pkgdir)
|
158
|
+
gemspec = "#{ lib }.gemspec"
|
159
|
+
open(gemspec, "w"){|fd| fd.puts(template)}
|
160
|
+
This.gemspec = gemspec
|
161
|
+
end
|
162
|
+
|
163
|
+
task :gem => [:clean, :gemspec] do
|
164
|
+
Fu.mkdir_p(This.pkgdir)
|
165
|
+
before = Dir['*.gem']
|
166
|
+
cmd = "gem build #{ This.gemspec }"
|
167
|
+
`#{ cmd }`
|
168
|
+
after = Dir['*.gem']
|
169
|
+
gem = ((after - before).first || after.first) or abort('no gem!')
|
170
|
+
Fu.mv(gem, This.pkgdir)
|
171
|
+
This.gem = File.join(This.pkgdir, File.basename(gem))
|
172
|
+
end
|
173
|
+
|
174
|
+
task :readme do
|
175
|
+
samples = ''
|
176
|
+
prompt = '~ > '
|
177
|
+
lib = This.lib
|
178
|
+
version = This.version
|
179
|
+
|
180
|
+
Dir['sample*/*'].sort.each do |sample|
|
181
|
+
samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
|
182
|
+
|
183
|
+
cmd = "cat #{ sample }"
|
184
|
+
samples << Util.indent(prompt + cmd, 2) << "\n\n"
|
185
|
+
samples << Util.indent(`#{ cmd }`, 4) << "\n"
|
186
|
+
|
187
|
+
cmd = "ruby #{ sample }"
|
188
|
+
samples << Util.indent(prompt + cmd, 2) << "\n\n"
|
189
|
+
|
190
|
+
cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
|
191
|
+
samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
|
192
|
+
end
|
193
|
+
|
194
|
+
template =
|
195
|
+
if test(?e, 'README.erb')
|
196
|
+
Template{ IO.read('README.erb') }
|
197
|
+
else
|
198
|
+
Template {
|
199
|
+
<<-__
|
200
|
+
NAME
|
201
|
+
#{ lib }
|
202
|
+
|
203
|
+
DESCRIPTION
|
204
|
+
|
205
|
+
INSTALL
|
206
|
+
gem install #{ lib }
|
207
|
+
|
208
|
+
SAMPLES
|
209
|
+
#{ samples }
|
210
|
+
__
|
211
|
+
}
|
212
|
+
end
|
213
|
+
|
214
|
+
open("README", "w"){|fd| fd.puts template}
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
task :clean do
|
219
|
+
Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
task :release => [:clean, :gemspec, :gem] do
|
224
|
+
gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
|
225
|
+
raise "which one? : #{ gems.inspect }" if gems.size > 1
|
226
|
+
raise "no gems?" if gems.size < 1
|
227
|
+
|
228
|
+
cmd = "gem push #{ This.gem }"
|
229
|
+
puts cmd
|
230
|
+
puts
|
231
|
+
system(cmd)
|
232
|
+
abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
|
233
|
+
|
234
|
+
cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.gem }"
|
235
|
+
puts cmd
|
236
|
+
puts
|
237
|
+
system(cmd)
|
238
|
+
abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
|
239
|
+
end
|
240
|
+
|
241
|
+
|
242
|
+
|
243
|
+
|
244
|
+
|
245
|
+
BEGIN {
|
246
|
+
# support for this rakefile
|
247
|
+
#
|
248
|
+
$VERBOSE = nil
|
249
|
+
|
250
|
+
require 'ostruct'
|
251
|
+
require 'erb'
|
252
|
+
require 'fileutils'
|
253
|
+
require 'rbconfig'
|
254
|
+
require 'pp'
|
255
|
+
|
256
|
+
# fu shortcut
|
257
|
+
#
|
258
|
+
Fu = FileUtils
|
259
|
+
|
260
|
+
# cache a bunch of stuff about this rakefile/environment
|
261
|
+
#
|
262
|
+
This = OpenStruct.new
|
263
|
+
|
264
|
+
This.file = File.expand_path(__FILE__)
|
265
|
+
This.dir = File.dirname(This.file)
|
266
|
+
This.pkgdir = File.join(This.dir, 'pkg')
|
267
|
+
|
268
|
+
# grok lib
|
269
|
+
#
|
270
|
+
lib = ENV['LIB']
|
271
|
+
unless lib
|
272
|
+
lib = File.basename(Dir.pwd).sub(/[-].*$/, '')
|
273
|
+
end
|
274
|
+
This.lib = lib
|
275
|
+
|
276
|
+
# grok version
|
277
|
+
#
|
278
|
+
version = ENV['VERSION']
|
279
|
+
unless version
|
280
|
+
require "./lib/#{ This.lib }"
|
281
|
+
This.name = lib.capitalize
|
282
|
+
This.object = eval(This.name)
|
283
|
+
version = This.object.send(:version)
|
284
|
+
end
|
285
|
+
This.version = version
|
286
|
+
|
287
|
+
# see if dependencies are export by the module
|
288
|
+
#
|
289
|
+
if This.object.respond_to?(:dependencies)
|
290
|
+
This.dependencies = This.object.dependencies
|
291
|
+
end
|
292
|
+
|
293
|
+
# we need to know the name of the lib an it's version
|
294
|
+
#
|
295
|
+
abort('no lib') unless This.lib
|
296
|
+
abort('no version') unless This.version
|
297
|
+
|
298
|
+
# discover full path to this ruby executable
|
299
|
+
#
|
300
|
+
c = Config::CONFIG
|
301
|
+
bindir = c["bindir"] || c['BINDIR']
|
302
|
+
ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
|
303
|
+
ruby_ext = c['EXEEXT'] || ''
|
304
|
+
ruby = File.join(bindir, (ruby_install_name + ruby_ext))
|
305
|
+
This.ruby = ruby
|
306
|
+
|
307
|
+
# some utils
|
308
|
+
#
|
309
|
+
module Util
|
310
|
+
def indent(s, n = 2)
|
311
|
+
s = unindent(s)
|
312
|
+
ws = ' ' * n
|
313
|
+
s.gsub(%r/^/, ws)
|
314
|
+
end
|
315
|
+
|
316
|
+
def unindent(s)
|
317
|
+
indent = nil
|
318
|
+
s.each_line do |line|
|
319
|
+
next if line =~ %r/^\s*$/
|
320
|
+
indent = line[%r/^\s*/] and break
|
321
|
+
end
|
322
|
+
indent ? s.gsub(%r/^#{ indent }/, "") : s
|
323
|
+
end
|
324
|
+
extend self
|
325
|
+
end
|
326
|
+
|
327
|
+
# template support
|
328
|
+
#
|
329
|
+
class Template
|
330
|
+
def initialize(&block)
|
331
|
+
@block = block
|
332
|
+
@template = block.call.to_s
|
333
|
+
end
|
334
|
+
def expand(b=nil)
|
335
|
+
ERB.new(Util.unindent(@template)).result((b||@block).binding)
|
336
|
+
end
|
337
|
+
alias_method 'to_s', 'expand'
|
338
|
+
end
|
339
|
+
def Template(*args, &block) Template.new(*args, &block) end
|
340
|
+
|
341
|
+
# colored console output support
|
342
|
+
#
|
343
|
+
This.ansi = {
|
344
|
+
:clear => "\e[0m",
|
345
|
+
:reset => "\e[0m",
|
346
|
+
:erase_line => "\e[K",
|
347
|
+
:erase_char => "\e[P",
|
348
|
+
:bold => "\e[1m",
|
349
|
+
:dark => "\e[2m",
|
350
|
+
:underline => "\e[4m",
|
351
|
+
:underscore => "\e[4m",
|
352
|
+
:blink => "\e[5m",
|
353
|
+
:reverse => "\e[7m",
|
354
|
+
:concealed => "\e[8m",
|
355
|
+
:black => "\e[30m",
|
356
|
+
:red => "\e[31m",
|
357
|
+
:green => "\e[32m",
|
358
|
+
:yellow => "\e[33m",
|
359
|
+
:blue => "\e[34m",
|
360
|
+
:magenta => "\e[35m",
|
361
|
+
:cyan => "\e[36m",
|
362
|
+
:white => "\e[37m",
|
363
|
+
:on_black => "\e[40m",
|
364
|
+
:on_red => "\e[41m",
|
365
|
+
:on_green => "\e[42m",
|
366
|
+
:on_yellow => "\e[43m",
|
367
|
+
:on_blue => "\e[44m",
|
368
|
+
:on_magenta => "\e[45m",
|
369
|
+
:on_cyan => "\e[46m",
|
370
|
+
:on_white => "\e[47m"
|
371
|
+
}
|
372
|
+
def say(phrase, *args)
|
373
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
374
|
+
options[:color] = args.shift.to_s.to_sym unless args.empty?
|
375
|
+
keys = options.keys
|
376
|
+
keys.each{|key| options[key.to_s.to_sym] = options.delete(key)}
|
377
|
+
|
378
|
+
color = options[:color]
|
379
|
+
bold = options.has_key?(:bold)
|
380
|
+
|
381
|
+
parts = [phrase]
|
382
|
+
parts.unshift(This.ansi[color]) if color
|
383
|
+
parts.unshift(This.ansi[:bold]) if bold
|
384
|
+
parts.push(This.ansi[:clear]) if parts.size > 1
|
385
|
+
|
386
|
+
method = options[:method] || :puts
|
387
|
+
|
388
|
+
Kernel.send(method, parts.join)
|
389
|
+
end
|
390
|
+
|
391
|
+
# always run out of the project dir
|
392
|
+
#
|
393
|
+
Dir.chdir(This.dir)
|
394
|
+
}
|
@@ -0,0 +1,131 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'open4'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
# define a function we can call later. the function will take two
|
7
|
+
# arguments:
|
8
|
+
# command which we will run via open4 and be able to
|
9
|
+
# send stdin as well as collect the pid, stderr and stdout.
|
10
|
+
# input optional data string to send to command on stdin
|
11
|
+
#
|
12
|
+
# this returns a hash of the command's pid, stderr, stdout, and status.
|
13
|
+
def run_cmd(command, input = nil)
|
14
|
+
|
15
|
+
# we will use open4 in block form, which means that the variables
|
16
|
+
# used inside the block will not be available once open4 has
|
17
|
+
# finished. as long as variables are declared outside of the
|
18
|
+
# block, they can be set inside the block and are available after
|
19
|
+
# the block has finished.
|
20
|
+
err = out = procid = status = verbose = nil
|
21
|
+
|
22
|
+
# using a begin so we can use rescue later on.
|
23
|
+
begin
|
24
|
+
|
25
|
+
# run our command with open4 in block form.
|
26
|
+
stat = Open4::popen4(command) do |pid, stdin, stdout, stderr|
|
27
|
+
|
28
|
+
# the default behavior of ruby is to internally buffer I/O
|
29
|
+
# ports when they are opened. open4 may not detect that stderr
|
30
|
+
# and/or stdout has closed because ruby is helpfully buffering
|
31
|
+
# the pipe for us. if open4 hangs, try uncommenting the next
|
32
|
+
# two lines.
|
33
|
+
# stderr.sync = true
|
34
|
+
# stdout.sync = true
|
35
|
+
|
36
|
+
# set procid to pid so we can see it outside of the block.
|
37
|
+
procid = pid
|
38
|
+
|
39
|
+
# if you want to use stdin, talk to stdin here. i tried it
|
40
|
+
# with bc. generally i only need to capture output, not
|
41
|
+
# interact with commands i'm running.
|
42
|
+
stdin.puts input if input
|
43
|
+
|
44
|
+
# stdin is opened write only. you'll raise an exception if
|
45
|
+
# you try to read anything from it. here you can try to read
|
46
|
+
# the first character from stdin.
|
47
|
+
# stdin.gets(1)
|
48
|
+
|
49
|
+
# now close stdin.
|
50
|
+
stdin.close
|
51
|
+
|
52
|
+
# make stderr and stdout available outside the block as well.
|
53
|
+
# removing the read will return pointers to objects rather
|
54
|
+
# than the data that the objects contain.
|
55
|
+
out = stdout.read
|
56
|
+
err = stderr.read
|
57
|
+
|
58
|
+
# as stdin is write-only, stderr and stdout are read only.
|
59
|
+
# you'll raise an exception if you try to write to either.
|
60
|
+
# stderr.puts 'building appears to be on fire'
|
61
|
+
|
62
|
+
# end of open4 block. pid, stdin, stdout and stderr are no
|
63
|
+
# longer accessible.
|
64
|
+
end
|
65
|
+
|
66
|
+
# now outside of the open4 block, we can get the exit status
|
67
|
+
# of our command by calling stat.exitstatus.
|
68
|
+
status = stat.exitstatus
|
69
|
+
|
70
|
+
# our function returns status from a command. however, if you
|
71
|
+
# tell the function to run a command that does not exist, ruby
|
72
|
+
# will raise an exception. we will trap that exception here, make
|
73
|
+
# up a non-zero exit status, convert the ruby error to a string,
|
74
|
+
# and populate err with it.
|
75
|
+
rescue Errno::ENOENT => stderr
|
76
|
+
status = 1
|
77
|
+
err = stderr.to_s
|
78
|
+
|
79
|
+
# handle null commands gracefully
|
80
|
+
rescue TypeError => stderr
|
81
|
+
status = 2
|
82
|
+
err = 'Can\'t execute null command.'
|
83
|
+
|
84
|
+
# done calling and/or rescuing open4.
|
85
|
+
end
|
86
|
+
|
87
|
+
# uncomment to make function print output.
|
88
|
+
verbose = true
|
89
|
+
|
90
|
+
# print the values if verbose is not nil.
|
91
|
+
print "\n============================================================" if verbose
|
92
|
+
print "\ncommand: #{ command }" if verbose
|
93
|
+
print "\ninput : \n\n#{ input }\n" if (verbose and input)
|
94
|
+
print "\npid : #{ procid }" if verbose
|
95
|
+
print "\nstatus : #{ status }" if verbose
|
96
|
+
print "\nstdout : #{ out }\n" if verbose
|
97
|
+
print "\nstderr : #{ err }\n" if verbose
|
98
|
+
print "============================================================\n" if verbose
|
99
|
+
|
100
|
+
# now that (we think) we have handled everything, return a hash
|
101
|
+
# with the process id, standard error, standard output, and the
|
102
|
+
# exit status.
|
103
|
+
return {
|
104
|
+
:pid => procid, # integer
|
105
|
+
:stderr => err, # string
|
106
|
+
:stdout => out, # string
|
107
|
+
:status => status, # integer
|
108
|
+
}
|
109
|
+
|
110
|
+
# return terminates function. code here will not run!
|
111
|
+
print 'this will never show up.'
|
112
|
+
|
113
|
+
# end of run_cmd function.
|
114
|
+
end
|
115
|
+
|
116
|
+
# this will raise an exception which our function will trap,
|
117
|
+
# complaining that the command does not exist.
|
118
|
+
cmd = run_cmd('/bin/does/not/exist')
|
119
|
+
|
120
|
+
# something that will produce a fair amount of output. you do have
|
121
|
+
# an nmap source tree lying around, right?
|
122
|
+
cmd = run_cmd('cd nmap-5.51 ; ./configure')
|
123
|
+
|
124
|
+
# bc, to illustrate using stdin.
|
125
|
+
cmd = run_cmd('bc', "2^16\nquit")
|
126
|
+
|
127
|
+
# uncomment to see hash returned by run_cmd function.
|
128
|
+
# pp cmd
|
129
|
+
|
130
|
+
# test function with null command
|
131
|
+
cmd = run_cmd(nil)
|
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}"
|
@@ -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
|
+
::RbConfig::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
|