POpen4 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (8) hide show
  1. data/CHANGES +10 -0
  2. data/LICENSE +64 -0
  3. data/README.rdoc +42 -0
  4. data/Rakefile +44 -0
  5. data/VERSION +1 -0
  6. data/lib/popen4.rb +93 -0
  7. data/tests/popen4_test.rb +78 -0
  8. metadata +71 -0
data/CHANGES ADDED
@@ -0,0 +1,10 @@
1
+ == 0.1.3 - 20-Oct-2009
2
+ * Use of win-open3 gem
3
+
4
+ == 0.1.1 - 12-Jun-2006
5
+ * Fixed Bug 4742
6
+ - open3.so Open4 fails to return Process::Status on Windows 2000.
7
+ - Thanks to Park Heesob!
8
+
9
+ == 0.1.0 - 10-Jun-2006
10
+ * Initial release
data/LICENSE ADDED
@@ -0,0 +1,64 @@
1
+ == POpen4 License
2
+
3
+ POpen4 is copyright John-Mason P. Shackelford (john-mason@shackelford.org)
4
+ and made available under the terms of Ruby's license, included below for your
5
+ convenience.
6
+
7
+ == Ruby's License
8
+
9
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
10
+ You can redistribute it and/or modify it under either the terms of the GPL
11
+ (see the file GPL), or the conditions below:
12
+
13
+ 1. You may make and give away verbatim copies of the source form of the
14
+ software without restriction, provided that you duplicate all of the
15
+ original copyright notices and associated disclaimers.
16
+
17
+ 2. You may modify your copy of the software in any way, provided that
18
+ you do at least ONE of the following:
19
+
20
+ a) place your modifications in the Public Domain or otherwise
21
+ make them Freely Available, such as by posting said
22
+ modifications to Usenet or an equivalent medium, or by allowing
23
+ the author to include your modifications in the software.
24
+
25
+ b) use the modified software only within your corporation or
26
+ organization.
27
+
28
+ c) give non-standard binaries non-standard names, with
29
+ instructions on where to get the original software distribution.
30
+
31
+ d) make other distribution arrangements with the author.
32
+
33
+ 3. You may distribute the software in object code or binary form,
34
+ provided that you do at least ONE of the following:
35
+
36
+ a) distribute the binaries and library files of the software,
37
+ together with instructions (in the manual page or equivalent)
38
+ on where to get the original distribution.
39
+
40
+ b) accompany the distribution with the machine-readable source of
41
+ the software.
42
+
43
+ c) give non-standard binaries non-standard names, with
44
+ instructions on where to get the original software distribution.
45
+
46
+ d) make other distribution arrangements with the author.
47
+
48
+ 4. You may modify and include the part of the software into any other
49
+ software (possibly commercial). But some files in the distribution
50
+ are not written by the author, so that they are not under these terms.
51
+
52
+ For the list of those files and their copying conditions, see the
53
+ file LEGAL.
54
+
55
+ 5. The scripts and library files supplied as input to or produced as
56
+ output from the software do not automatically fall under the
57
+ copyright of the software, but belong to whomever generated them,
58
+ and may be sold commercially, and may be aggregated with this
59
+ software.
60
+
61
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
62
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
63
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
64
+ PURPOSE.
@@ -0,0 +1,42 @@
1
+ == Description
2
+ POpen4 provides the Rubyist a single API across platforms for executing a
3
+ command in a child process with handles on stdout, stderr, stdin streams as well
4
+ as access to the process ID and exit status. It does very little other than to
5
+ provide an easy way to use either Ara Howard's Open4 library or the win32-popen3
6
+ library by Park Heesob and Daniel Berger depending on your platform and without
7
+ having to code around the slight differences in their APIs.
8
+
9
+ Consider this my first attempt at a response to
10
+ {Daniel's request}[http://groups.google.com/group/comp.lang.ruby/msg/44ba016610fa8878]
11
+ for a consensus on the API back in 2005.
12
+
13
+ It is my hope that this project will be shortly absorbed or replaced with a
14
+ better solution. POpen4 offers very little in the way of features or
15
+ flexibility, but it does work across platforms without extra coding.
16
+ == Notes
17
+ Rather than adopting either Open4's API or win32-open3's (they differ in several
18
+ respects, but most obviously in the order in which streams are passed to the
19
+ block) I am proposing a third API for couple of reasons. First, Open4 passes the
20
+ PID first and win32-open3 passes stdin neither of which seem to me to be the
21
+ streams we are most likely to use when we don't need all four. POpen4 passes
22
+ stdout and stderr first so that when the others are not required we can omit
23
+ them from the block. Second, I thought it best to break everybody's code rather
24
+ than to be a drop in replacement on one platform and be a surprise on another.
25
+ No surprises--it's a new API on either platform.
26
+
27
+ == Installation
28
+
29
+ $ gem install POpen4
30
+
31
+ Needed gem on Windows:
32
+
33
+ $ gem install win32-open3
34
+
35
+ Needed gem on Unix:
36
+
37
+ $ gem install open4
38
+
39
+ == Acknowledgements
40
+ Ara Howard, Park Heesob, Daniel Berger and others have done the real work. Many
41
+ thanks to them for the many hours they have poured into sharing their work with
42
+ the Ruby community at large.
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ require 'rubygems/user_interaction'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+
6
+ task :default => [:test]
7
+
8
+ # Test --------------------------------------------------------------------
9
+
10
+ desc "Run the unit tests"
11
+ task :test do
12
+ Rake::TestTask.new("test") do |t|
13
+ t.libs << "tests"
14
+ t.pattern = 'tests/*_test.rb'
15
+ t.verbose = true
16
+ end
17
+ end
18
+
19
+ # Documentation -----------------------------------------------------------
20
+ desc "Generate RDoc"
21
+ rd = Rake::RDocTask.new("rdoc") { |rdoc|
22
+ rdoc.rdoc_dir = 'rdoc'
23
+ rdoc.title = "POpen4 -- Open4 cross-platform"
24
+ rdoc.options << '--main' << 'README'
25
+ rdoc.rdoc_files.include('README', 'LICENSE', 'CHANGES')
26
+ rdoc.rdoc_files.include('lib/**/*.rb', 'doc/**/*.rdoc')
27
+ }
28
+
29
+ # GEM Packaging -----------------------------------------------------------
30
+
31
+ begin
32
+ require 'jeweler'
33
+ Jeweler::Tasks.new do |gemspec|
34
+ gemspec.name = "POpen4"
35
+ gemspec.summary = "Open4 cross-platform"
36
+ gemspec.description = ""
37
+ gemspec.email = "john-mason@shackelford.org"
38
+ gemspec.homepage = "http://github.com/pka/popen4"
39
+ gemspec.authors = ["John-Mason P. Shackelford"]
40
+ gemspec.add_dependency("Platform", ">= 0.4.0")
41
+ end
42
+ rescue LoadError
43
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
44
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.3
@@ -0,0 +1,93 @@
1
+ require 'rubygems'
2
+ require 'platform'
3
+
4
+ case Platform::OS
5
+
6
+ # win32/popen4 yields stdin, stdout, stderr and pid, respectively
7
+ when :win32
8
+
9
+ require 'win32/open3'
10
+
11
+ # POpen4 provides the Rubyist a single API across platforms for executing a
12
+ # command in a child process with handles on stdout, stderr, and stdin streams
13
+ # as well as access to the process ID and exit status.
14
+ #
15
+ # Consider the following example (borrowed from Open4):
16
+ #
17
+ # require 'rubygems'
18
+ # require 'popen4'
19
+ #
20
+ # status =
21
+ # POpen4::popen4("cmd") do |stdout, stderr, stdin, pid|
22
+ # stdin.puts "echo hello world!"
23
+ # stdin.puts "echo ERROR! 1>&2"
24
+ # stdin.puts "exit"
25
+ # stdin.close
26
+ #
27
+ # puts "pid : #{ pid }"
28
+ # puts "stdout : #{ stdout.read.strip }"
29
+ # puts "stderr : #{ stderr.read.strip }"
30
+ # end
31
+ #
32
+ # puts "status : #{ status.inspect }"
33
+ # puts "exitstatus : #{ status.exitstatus }"
34
+ #
35
+ module POpen4
36
+ # Starts a new process and hands IO objects representing the subprocess
37
+ # stdout, stderr, stdin streams and the pid (respectively) to the block
38
+ # supplied. If the command could not be started, return nil.
39
+ #
40
+ # The mode argument may be set to t[ext] or b[inary] and is used only on
41
+ # Windows platforms.
42
+ #
43
+ # The stdin stream and/or pid may be omitted from the block parameter list
44
+ # if they are not required.
45
+ def self.popen4(command, mode = "t") # :yields: stdout, stderr, stdin, pid
46
+
47
+ err_output = nil
48
+ Open4.popen4(command, mode) do |stdin,stdout,stderr,pid|
49
+ yield stdout, stderr, stdin, pid
50
+
51
+ # On windows we will always get an exit status of 3 unless
52
+ # we read to the end of the streams so we do this on all platforms
53
+ # so that our behavior is always the same.
54
+ stdout.read unless stdout.eof?
55
+
56
+ # On windows executing a non existent command does not raise an error
57
+ # (as in unix) so on unix we return nil instead of a status object and
58
+ # on windows we try to determine if we couldn't start the command and
59
+ # return nil instead of the Process::Status object.
60
+ stderr.rewind
61
+ err_output = stderr.read
62
+ end
63
+
64
+ return $?
65
+ end # def
66
+ end # module
67
+
68
+
69
+ else # unix popen4 yields pid, stdin, stdout and stderr, respectively
70
+ # :enddoc:
71
+ require 'open4'
72
+ module POpen4
73
+ def self.popen4(command, mode = "t")
74
+ begin
75
+ return status = Open4.popen4(command) do |pid,stdin,stdout,stderr|
76
+ yield stdout, stderr, stdin, pid
77
+ # On windows we will always get an exit status of 3 unless
78
+ # we read to the end of the streams so we do this on all platforms
79
+ # so that our behavior is always the same.
80
+ stdout.read unless stdout.eof?
81
+ stderr.read unless stderr.eof?
82
+ end
83
+ rescue Errno::ENOENT => e
84
+ # On windows executing a non existent command does not raise an error
85
+ # (as in unix) so on unix we return nil instead of a status object and
86
+ # on windows we try to determine if we couldn't start the command and
87
+ # return nil instead of the Process::Status object.
88
+ return nil
89
+ end
90
+ end #def
91
+ end #module
92
+
93
+ end
@@ -0,0 +1,78 @@
1
+ $: << File.join( File.dirname( __FILE__ ), '../lib/')
2
+
3
+ require 'test/unit'
4
+ require 'popen4'
5
+
6
+ require 'platform'
7
+
8
+ class POpen4Test < Test::Unit::TestCase
9
+
10
+ case Platform::OS
11
+ when :win32
12
+ CMD_SHELL = "cmd"
13
+ CMD_STDERR = "ruby -e \"$stderr.puts 'ruby'\""
14
+ CMD_EXIT = "ruby -e \"$stdout.puts 'ruby'; exit 1\""
15
+ else # unix
16
+ CMD_SHELL = "sh"
17
+ CMD_STDERR = "ruby -e '$stderr.puts \"ruby\"'"
18
+ CMD_EXIT = "ruby -e '$stdout.puts \"ruby\"; exit 1'"
19
+ end
20
+ CMD_GOOD = "ruby --version"
21
+ CMD_BAD = CMD_GOOD.reverse
22
+
23
+ def test_popen4_block_good_cmd
24
+ assert_nothing_raised do
25
+ POpen4.popen4(CMD_GOOD){ |pout, perr, pin, pid| }
26
+ end
27
+ end
28
+
29
+ def test_popen4_block_bad_cmd
30
+ status = nil
31
+ assert_nothing_raised do
32
+ status = POpen4.popen4(CMD_BAD){ |pout, perr, pin, pid| }
33
+ end
34
+ assert_nil status
35
+ end
36
+
37
+ def test_popen4_block_status
38
+ status = POpen4.popen4(CMD_GOOD) do |pout, perr, pin, pid|
39
+ assert_kind_of(IO, pin)
40
+ assert_kind_of(IO, pout)
41
+ assert_kind_of(IO, perr)
42
+ assert_kind_of(Fixnum, pid)
43
+ end
44
+ assert_kind_of Process::Status, status
45
+ end
46
+
47
+ def test_open4_block_read_stdout
48
+ status = POpen4.popen4(CMD_GOOD) do |pout, perr|
49
+ assert_match(/ruby \d\.\d\.\d/, pout.gets)
50
+ end
51
+ assert_equal 0, status.exitstatus
52
+ end
53
+
54
+ def test_open4_block_read_stderr
55
+ status = POpen4.popen4(CMD_STDERR) do |pout, perr|
56
+ assert_match "ruby", perr.gets
57
+ end
58
+ assert_equal 0, status.exitstatus
59
+ end
60
+
61
+ def test_open4_block_exitstatus
62
+ status = POpen4.popen4(CMD_EXIT) do |pout, perr|
63
+ assert_match "ruby", pout.gets
64
+ end
65
+ assert_kind_of Process::Status, status
66
+ assert_equal 1, status.exitstatus
67
+ end
68
+
69
+ def test_open4_block_write_stdin
70
+ status = POpen4.popen4(CMD_SHELL) do |pout, perr, pin|
71
+ pin.puts CMD_GOOD
72
+ pin.puts "exit"
73
+ pin.close
74
+ assert_match(/ruby \d\.\d\.\d/, pout.readlines.join)
75
+ end
76
+ assert_equal 0, status.exitstatus
77
+ end
78
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: POpen4
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - John-Mason P. Shackelford
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-12 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: Platform
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.4.0
24
+ version:
25
+ description: ""
26
+ email: john-mason@shackelford.org
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.rdoc
34
+ files:
35
+ - CHANGES
36
+ - LICENSE
37
+ - README.rdoc
38
+ - Rakefile
39
+ - VERSION
40
+ - lib/popen4.rb
41
+ - tests/popen4_test.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/pka/popen4
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --charset=UTF-8
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.5
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: Open4 cross-platform
70
+ test_files: []
71
+