open4 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. data/LICENSE +3 -0
  2. data/Rakefile +175 -29
  3. data/lib/open4.rb +6 -28
  4. data/open4.gemspec +25 -7
  5. data/samples/jesse-caldwell.rb +131 -0
  6. metadata +13 -12
data/LICENSE ADDED
@@ -0,0 +1,3 @@
1
+ same as Ruby's
2
+
3
+ http://www.ruby-lang.org/en/LICENSE.txt
data/Rakefile CHANGED
@@ -1,18 +1,66 @@
1
-
2
1
  This.rubyforge_project = 'codeforpeople'
3
2
  This.author = "Ara T. Howard"
4
3
  This.email = "ara.t.howard@gmail.com"
5
- This.homepage = "http://github.com/ahoward/#{ This.lib }/tree/master"
4
+ This.homepage = "https://github.com/ahoward/#{ This.lib }"
6
5
 
7
6
 
8
7
  task :default do
9
- puts(Rake::Task.tasks.map{|task| task.name} - ['default'])
8
+ puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
9
+ end
10
+
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
+ test_dir = File.join(This.dir, "test")
24
+ test_glob ||= File.join(test_dir, "#{ which }/**_test.rb")
25
+ test_rbs = Dir.glob(test_glob).sort
26
+
27
+ div = ('=' * 119)
28
+ line = ('-' * 119)
29
+
30
+ test_rbs.each_with_index do |test_rb, index|
31
+ testno = index + 1
32
+ command = "#{ This.ruby } -I ./lib -I ./test/lib #{ test_rb }"
33
+
34
+ puts
35
+ say(div, :color => :cyan, :bold => true)
36
+ say("@#{ testno } => ", :bold => true, :method => :print)
37
+ say(command, :color => :cyan, :bold => true)
38
+ say(line, :color => :cyan, :bold => true)
39
+
40
+ system(command)
41
+
42
+ say(line, :color => :cyan, :bold => true)
43
+
44
+ status = $?.exitstatus
45
+
46
+ if status.zero?
47
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
48
+ say("SUCCESS", :color => :green, :bold => true)
49
+ else
50
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
51
+ say("FAILURE", :color => :red, :bold => true)
52
+ end
53
+ say(line, :color => :cyan, :bold => true)
54
+
55
+ exit(status) unless status.zero?
56
+ end
10
57
  end
11
58
 
12
59
 
13
60
  task :gemspec do
14
- ignore_extensions = 'git', 'svn', 'tmp', /sw./, 'bak', 'gem'
15
- ignore_directories = 'pkg'
61
+ ignore_extensions = ['git', 'svn', 'tmp', /sw./, 'bak', 'gem']
62
+ ignore_directories = ['pkg']
63
+ ignore_files = ['test/log']
16
64
 
17
65
  shiteless =
18
66
  lambda do |list|
@@ -26,17 +74,26 @@ task :gemspec do
26
74
  dirname = File.expand_path(entry)
27
75
  ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
28
76
  end
77
+ list.delete_if do |entry|
78
+ next unless test(?f, entry)
79
+ filename = File.expand_path(entry)
80
+ ignore_files.any?{|file| File.expand_path(file) == filename}
81
+ end
29
82
  end
30
83
 
31
84
  lib = This.lib
85
+ object = This.object
32
86
  version = This.version
33
87
  files = shiteless[Dir::glob("**/**")]
34
88
  executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
35
- has_rdoc = true #File.exist?('doc')
89
+ #has_rdoc = true #File.exist?('doc')
36
90
  test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
91
+ summary = object.respond_to?(:summary) ? object.summary : "summary: #{ lib } kicks the ass"
92
+ description = object.respond_to?(:description) ? object.description : "description: #{ lib } kicks the ass"
37
93
 
38
- extensions = This.extensions
39
- if extensions.nil?
94
+ if This.extensions.nil?
95
+ This.extensions = []
96
+ extensions = This.extensions
40
97
  %w( Makefile configure extconf.rb ).each do |ext|
41
98
  extensions << ext if File.exists?(ext)
42
99
  end
@@ -57,18 +114,17 @@ task :gemspec do
57
114
  spec.version = #{ version.inspect }
58
115
  spec.platform = Gem::Platform::RUBY
59
116
  spec.summary = #{ lib.inspect }
117
+ spec.description = #{ description.inspect }
60
118
 
61
- spec.description = "manage child processes and their io handles easily"
62
-
63
- spec.files = #{ files.inspect }
119
+ spec.files =\n#{ files.sort.pretty_inspect }
64
120
  spec.executables = #{ executables.inspect }
65
121
 
66
122
  spec.require_path = "lib"
67
123
 
68
- spec.has_rdoc = #{ has_rdoc.inspect }
69
124
  spec.test_files = #{ test_files.inspect }
70
- #spec.add_dependency 'lib', '>= version'
71
- #spec.add_dependency 'fattr'
125
+
126
+ ### spec.add_dependency 'lib', '>= version'
127
+ #### spec.add_dependency 'map'
72
128
 
73
129
  spec.extensions.push(*#{ extensions.inspect })
74
130
 
@@ -81,22 +137,23 @@ task :gemspec do
81
137
  }
82
138
  end
83
139
 
84
- open("#{ lib }.gemspec", "w"){|fd| fd.puts template}
85
- This.gemspec = "#{ lib }.gemspec"
140
+ Fu.mkdir_p(This.pkgdir)
141
+ gemspec = "#{ lib }.gemspec"
142
+ open(gemspec, "w"){|fd| fd.puts(template)}
143
+ This.gemspec = gemspec
86
144
  end
87
145
 
88
146
  task :gem => [:clean, :gemspec] do
89
- Fu.mkdir_p This.pkgdir
147
+ Fu.mkdir_p(This.pkgdir)
90
148
  before = Dir['*.gem']
91
149
  cmd = "gem build #{ This.gemspec }"
92
150
  `#{ cmd }`
93
151
  after = Dir['*.gem']
94
152
  gem = ((after - before).first || after.first) or abort('no gem!')
95
- Fu.mv gem, This.pkgdir
96
- This.gem = File.basename(gem)
153
+ Fu.mv(gem, This.pkgdir)
154
+ This.gem = File.join(This.pkgdir, File.basename(gem))
97
155
  end
98
156
 
99
-
100
157
  task :readme do
101
158
  samples = ''
102
159
  prompt = '~ > '
@@ -113,7 +170,7 @@ task :readme do
113
170
  cmd = "ruby #{ sample }"
114
171
  samples << Util.indent(prompt + cmd, 2) << "\n\n"
115
172
 
116
- cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -Ilib #{ sample })'"
173
+ cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
117
174
  samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
118
175
  end
119
176
 
@@ -150,9 +207,18 @@ task :release => [:clean, :gemspec, :gem] do
150
207
  gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
151
208
  raise "which one? : #{ gems.inspect }" if gems.size > 1
152
209
  raise "no gems?" if gems.size < 1
153
- cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.pkgdir }/#{ This.gem }"
210
+
211
+ cmd = "gem push #{ This.gem }"
212
+ puts cmd
213
+ puts
214
+ system(cmd)
215
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
216
+
217
+ cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.gem }"
154
218
  puts cmd
155
- system cmd
219
+ puts
220
+ system(cmd)
221
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
156
222
  end
157
223
 
158
224
 
@@ -160,37 +226,63 @@ end
160
226
 
161
227
 
162
228
  BEGIN {
229
+ # support for this rakefile
230
+ #
163
231
  $VERBOSE = nil
164
232
 
165
233
  require 'ostruct'
166
234
  require 'erb'
167
235
  require 'fileutils'
236
+ require 'rbconfig'
237
+ require 'pp'
168
238
 
239
+ # fu shortcut
240
+ #
169
241
  Fu = FileUtils
170
242
 
243
+ # cache a bunch of stuff about this rakefile/environment
244
+ #
171
245
  This = OpenStruct.new
172
246
 
173
247
  This.file = File.expand_path(__FILE__)
174
248
  This.dir = File.dirname(This.file)
175
249
  This.pkgdir = File.join(This.dir, 'pkg')
176
250
 
251
+ # grok lib
252
+ #
177
253
  lib = ENV['LIB']
178
254
  unless lib
179
- lib = File.basename(Dir.pwd)
255
+ lib = File.basename(Dir.pwd).sub(/[-].*$/, '')
180
256
  end
181
257
  This.lib = lib
182
258
 
259
+ # grok version
260
+ #
183
261
  version = ENV['VERSION']
184
262
  unless version
185
- name = lib.capitalize
186
- require "./lib/#{ lib }"
187
- version = eval(name).send(:version)
263
+ require "./lib/#{ This.lib }"
264
+ This.name = lib.capitalize
265
+ This.object = eval(This.name)
266
+ version = This.object.send(:version)
188
267
  end
189
268
  This.version = version
190
269
 
270
+ # we need to know the name of the lib an it's version
271
+ #
191
272
  abort('no lib') unless This.lib
192
273
  abort('no version') unless This.version
193
274
 
275
+ # discover full path to this ruby executable
276
+ #
277
+ c = Config::CONFIG
278
+ bindir = c["bindir"] || c['BINDIR']
279
+ ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
280
+ ruby_ext = c['EXEEXT'] || ''
281
+ ruby = File.join(bindir, (ruby_install_name + ruby_ext))
282
+ This.ruby = ruby
283
+
284
+ # some utils
285
+ #
194
286
  module Util
195
287
  def indent(s, n = 2)
196
288
  s = unindent(s)
@@ -200,7 +292,7 @@ BEGIN {
200
292
 
201
293
  def unindent(s)
202
294
  indent = nil
203
- s.each do |line|
295
+ s.each_line do |line|
204
296
  next if line =~ %r/^\s*$/
205
297
  indent = line[%r/^\s*/] and break
206
298
  end
@@ -209,17 +301,71 @@ BEGIN {
209
301
  extend self
210
302
  end
211
303
 
304
+ # template support
305
+ #
212
306
  class Template
213
307
  def initialize(&block)
214
308
  @block = block
215
309
  @template = block.call.to_s
216
310
  end
217
311
  def expand(b=nil)
218
- ERB.new(Util.unindent(@template)).result(b||@block)
312
+ ERB.new(Util.unindent(@template)).result((b||@block).binding)
219
313
  end
220
314
  alias_method 'to_s', 'expand'
221
315
  end
222
316
  def Template(*args, &block) Template.new(*args, &block) end
223
317
 
318
+ # colored console output support
319
+ #
320
+ This.ansi = {
321
+ :clear => "\e[0m",
322
+ :reset => "\e[0m",
323
+ :erase_line => "\e[K",
324
+ :erase_char => "\e[P",
325
+ :bold => "\e[1m",
326
+ :dark => "\e[2m",
327
+ :underline => "\e[4m",
328
+ :underscore => "\e[4m",
329
+ :blink => "\e[5m",
330
+ :reverse => "\e[7m",
331
+ :concealed => "\e[8m",
332
+ :black => "\e[30m",
333
+ :red => "\e[31m",
334
+ :green => "\e[32m",
335
+ :yellow => "\e[33m",
336
+ :blue => "\e[34m",
337
+ :magenta => "\e[35m",
338
+ :cyan => "\e[36m",
339
+ :white => "\e[37m",
340
+ :on_black => "\e[40m",
341
+ :on_red => "\e[41m",
342
+ :on_green => "\e[42m",
343
+ :on_yellow => "\e[43m",
344
+ :on_blue => "\e[44m",
345
+ :on_magenta => "\e[45m",
346
+ :on_cyan => "\e[46m",
347
+ :on_white => "\e[47m"
348
+ }
349
+ def say(phrase, *args)
350
+ options = args.last.is_a?(Hash) ? args.pop : {}
351
+ options[:color] = args.shift.to_s.to_sym unless args.empty?
352
+ keys = options.keys
353
+ keys.each{|key| options[key.to_s.to_sym] = options.delete(key)}
354
+
355
+ color = options[:color]
356
+ bold = options.has_key?(:bold)
357
+
358
+ parts = [phrase]
359
+ parts.unshift(This.ansi[color]) if color
360
+ parts.unshift(This.ansi[:bold]) if bold
361
+ parts.push(This.ansi[:clear]) if parts.size > 1
362
+
363
+ method = options[:method] || :puts
364
+
365
+ Kernel.send(method, parts.join)
366
+ end
367
+
368
+ # always run out of the project dir
369
+ #
224
370
  Dir.chdir(This.dir)
225
371
  }
@@ -4,14 +4,12 @@ require 'timeout'
4
4
  require 'thread'
5
5
 
6
6
  module Open4
7
- #--{{{
8
- VERSION = '1.0.1'
7
+ VERSION = '1.1.0'
9
8
  def self.version() VERSION end
10
9
 
11
10
  class Error < ::StandardError; end
12
11
 
13
12
  def popen4(*cmd, &b)
14
- #--{{{
15
13
  pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe
16
14
 
17
15
  verbose = $VERBOSE
@@ -74,14 +72,12 @@ module Open4
74
72
  else
75
73
  [cid, pw.last, pr.first, pe.first]
76
74
  end
77
- #--}}}
78
75
  end
79
76
  alias open4 popen4
80
77
  module_function :popen4
81
78
  module_function :open4
82
79
 
83
80
  class SpawnError < Error
84
- #--{{{
85
81
  attr 'cmd'
86
82
  attr 'status'
87
83
  attr 'signals'
@@ -98,11 +94,9 @@ module Open4
98
94
  sigs = @signals.map{|k,v| "#{ k }:#{ v.inspect }"}.join(' ')
99
95
  super "cmd <#{ cmd }> failed with status <#{ exitstatus.inspect }> signals <#{ sigs }>"
100
96
  end
101
- #--}}}
102
97
  end
103
98
 
104
99
  class ThreadEnsemble
105
- #--{{{
106
100
  attr 'threads'
107
101
 
108
102
  def initialize cid
@@ -154,18 +148,14 @@ module Open4
154
148
  def all_done
155
149
  @threads.size.times{ @done.pop }
156
150
  end
157
- #--}}}
158
151
  end
159
152
 
160
153
  def to timeout = nil
161
- #--{{{
162
154
  Timeout.timeout(timeout){ yield }
163
- #--}}}
164
155
  end
165
156
  module_function :to
166
157
 
167
158
  def new_thread *a, &b
168
- #--{{{
169
159
  cur = Thread.current
170
160
  Thread.new(*a) do |*a|
171
161
  begin
@@ -174,34 +164,32 @@ module Open4
174
164
  cur.raise e
175
165
  end
176
166
  end
177
- #--}}}
178
167
  end
179
168
  module_function :new_thread
180
169
 
181
170
  def getopts opts = {}
182
- #--{{{
183
171
  lambda do |*args|
184
172
  keys, default, ignored = args
185
- catch('opt') do
173
+ catch(:opt) do
186
174
  [keys].flatten.each do |key|
187
175
  [key, key.to_s, key.to_s.intern].each do |key|
188
- throw 'opt', opts[key] if opts.has_key?(key)
176
+ throw :opt, opts[key] if opts.has_key?(key)
189
177
  end
190
178
  end
191
179
  default
192
180
  end
193
181
  end
194
- #--}}}
195
182
  end
196
183
  module_function :getopts
197
184
 
198
185
  def relay src, dst = nil, t = nil
199
- #--{{{
200
186
  send_dst =
201
187
  if dst.respond_to?(:call)
202
188
  lambda{|buf| dst.call(buf)}
189
+ elsif dst.respond_to?(:<<)
190
+ lambda{|buf| dst << buf }
203
191
  else
204
- lambda{|buf| dst << buf}
192
+ lambda{|buf| buf }
205
193
  end
206
194
 
207
195
  unless src.nil?
@@ -242,12 +230,10 @@ module Open4
242
230
  send_dst[buf]
243
231
  end
244
232
  end
245
- #--}}}
246
233
  end
247
234
  module_function :relay
248
235
 
249
236
  def spawn arg, *argv
250
- #--{{{
251
237
  argv.unshift(arg)
252
238
  opts = ((argv.size > 1 and Hash === argv.last) ? argv.pop : {})
253
239
  argv.flatten!
@@ -323,7 +309,6 @@ module Open4
323
309
  (ignore_exit_failure or (status.nil? and ignore_exec_failure) or exitstatus.include?(status.exitstatus))
324
310
 
325
311
  status
326
- #--}}}
327
312
  end
328
313
  module_function :spawn
329
314
 
@@ -334,7 +319,6 @@ module Open4
334
319
  module_function :chdir
335
320
 
336
321
  def background arg, *argv
337
- #--{{{
338
322
  require 'thread'
339
323
  q = Queue.new
340
324
  opts = { 'pid' => q, :pid => q }
@@ -352,14 +336,12 @@ module Open4
352
336
  define_method(:exitstatus){ @exitstatus ||= spawn_status.exitstatus }
353
337
  }
354
338
  thread
355
- #--}}}
356
339
  end
357
340
  alias bg background
358
341
  module_function :background
359
342
  module_function :bg
360
343
 
361
344
  def maim pid, opts = {}
362
- #--{{{
363
345
  getopt = getopts opts
364
346
  sigs = getopt[ 'signals', %w(SIGTERM SIGQUIT SIGKILL) ]
365
347
  suspend = getopt[ 'suspend', 4 ]
@@ -377,12 +359,10 @@ module Open4
377
359
  return true unless alive? pid
378
360
  end
379
361
  return(not alive?(pid))
380
- #--}}}
381
362
  end
382
363
  module_function :maim
383
364
 
384
365
  def alive pid
385
- #--{{{
386
366
  pid = Integer pid
387
367
  begin
388
368
  Process.kill 0, pid
@@ -390,12 +370,10 @@ module Open4
390
370
  rescue Errno::ESRCH
391
371
  false
392
372
  end
393
- #--}}}
394
373
  end
395
374
  alias alive? alive
396
375
  module_function :alive
397
376
  module_function :'alive?'
398
- #--}}}
399
377
  end
400
378
 
401
379
  def open4(*cmd, &b) cmd.size == 0 ? Open4 : Open4::popen4(*cmd, &b) end
@@ -3,26 +3,44 @@
3
3
 
4
4
  Gem::Specification::new do |spec|
5
5
  spec.name = "open4"
6
- spec.version = "1.0.1"
6
+ spec.version = "1.1.0"
7
7
  spec.platform = Gem::Platform::RUBY
8
8
  spec.summary = "open4"
9
+ spec.description = "description: open4 kicks the ass"
9
10
 
10
- spec.description = "manage child processes and their io handles easily"
11
+ spec.files =
12
+ ["LICENSE",
13
+ "README",
14
+ "README.erb",
15
+ "Rakefile",
16
+ "lib",
17
+ "lib/open4.rb",
18
+ "open4.gemspec",
19
+ "samples",
20
+ "samples/bg.rb",
21
+ "samples/block.rb",
22
+ "samples/exception.rb",
23
+ "samples/jesse-caldwell.rb",
24
+ "samples/simple.rb",
25
+ "samples/spawn.rb",
26
+ "samples/stdin_timeout.rb",
27
+ "samples/timeout.rb",
28
+ "white_box",
29
+ "white_box/leak.rb"]
11
30
 
12
- spec.files = ["lib", "lib/open4.rb", "open4.gemspec", "Rakefile", "README", "README.erb", "samples", "samples/bg.rb", "samples/block.rb", "samples/exception.rb", "samples/simple.rb", "samples/spawn.rb", "samples/stdin_timeout.rb", "samples/timeout.rb", "white_box", "white_box/leak.rb"]
13
31
  spec.executables = []
14
32
 
15
33
  spec.require_path = "lib"
16
34
 
17
- spec.has_rdoc = true
18
35
  spec.test_files = nil
19
- #spec.add_dependency 'lib', '>= version'
20
- #spec.add_dependency 'fattr'
36
+
37
+ ### spec.add_dependency 'lib', '>= version'
38
+ #### spec.add_dependency 'map'
21
39
 
22
40
  spec.extensions.push(*[])
23
41
 
24
42
  spec.rubyforge_project = "codeforpeople"
25
43
  spec.author = "Ara T. Howard"
26
44
  spec.email = "ara.t.howard@gmail.com"
27
- spec.homepage = "http://github.com/ahoward/open4/tree/master"
45
+ spec.homepage = "https://github.com/ahoward/open4"
28
46
  end
@@ -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)
metadata CHANGED
@@ -1,7 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: open4
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ prerelease:
5
+ version: 1.1.0
5
6
  platform: ruby
6
7
  authors:
7
8
  - Ara T. Howard
@@ -9,11 +10,10 @@ autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
12
 
12
- date: 2009-10-18 00:00:00 -06:00
13
- default_executable:
13
+ date: 2011-06-24 00:00:00 Z
14
14
  dependencies: []
15
15
 
16
- description: manage child processes and their io handles easily
16
+ description: "description: open4 kicks the ass"
17
17
  email: ara.t.howard@gmail.com
18
18
  executables: []
19
19
 
@@ -22,21 +22,22 @@ extensions: []
22
22
  extra_rdoc_files: []
23
23
 
24
24
  files:
25
- - lib/open4.rb
26
- - open4.gemspec
27
- - Rakefile
25
+ - LICENSE
28
26
  - README
29
27
  - README.erb
28
+ - Rakefile
29
+ - lib/open4.rb
30
+ - open4.gemspec
30
31
  - samples/bg.rb
31
32
  - samples/block.rb
32
33
  - samples/exception.rb
34
+ - samples/jesse-caldwell.rb
33
35
  - samples/simple.rb
34
36
  - samples/spawn.rb
35
37
  - samples/stdin_timeout.rb
36
38
  - samples/timeout.rb
37
39
  - white_box/leak.rb
38
- has_rdoc: true
39
- homepage: http://github.com/ahoward/open4/tree/master
40
+ homepage: https://github.com/ahoward/open4
40
41
  licenses: []
41
42
 
42
43
  post_install_message:
@@ -45,21 +46,21 @@ rdoc_options: []
45
46
  require_paths:
46
47
  - lib
47
48
  required_ruby_version: !ruby/object:Gem::Requirement
49
+ none: false
48
50
  requirements:
49
51
  - - ">="
50
52
  - !ruby/object:Gem::Version
51
53
  version: "0"
52
- version:
53
54
  required_rubygems_version: !ruby/object:Gem::Requirement
55
+ none: false
54
56
  requirements:
55
57
  - - ">="
56
58
  - !ruby/object:Gem::Version
57
59
  version: "0"
58
- version:
59
60
  requirements: []
60
61
 
61
62
  rubyforge_project: codeforpeople
62
- rubygems_version: 1.3.5
63
+ rubygems_version: 1.7.2
63
64
  signing_key:
64
65
  specification_version: 3
65
66
  summary: open4