open4 1.0.1 → 1.1.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.
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