open4 0.3.0 → 0.4.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 CHANGED
@@ -9,6 +9,10 @@ SYNOPSIS
9
9
 
10
10
  HISTORY
11
11
 
12
+ 0.4.0:
13
+ - improved error handling contributed by jordan breeding.
14
+ - introduction of background/bg method
15
+
12
16
  0.3.0 :
13
17
  - bug fix from jordan breeding. general clean up. added spawn method.
14
18
 
@@ -136,6 +140,52 @@ SAMPLES
136
140
  "42"
137
141
  ""
138
142
 
143
+
144
+ ----------------------------------------------------------------------------
145
+ the bg/background method is similar to spawn, but the process is
146
+ automatically set running in a thread. the returned thread has several
147
+ methods added dynamically which return the pid and blocking calls to the
148
+ exitstatus.
149
+ ----------------------------------------------------------------------------
150
+
151
+ harp: > cat sample/bg.rb
152
+ require 'yaml'
153
+ require 'open4'
154
+ include Open4
155
+
156
+ stdin = '42'
157
+ stdout = ''
158
+ stderr = ''
159
+
160
+ t = bg 'ruby -e"sleep 4; puts ARGF.read"', 0=>stdin, 1=>stdout, 2=>stderr
161
+
162
+ waiter = Thread.new{ y t.pid => t.exitstatus } # t.exitstatus is a blocking call!
163
+
164
+ while((status = t.status))
165
+ y "status" => status
166
+ sleep 1
167
+ end
168
+
169
+ waiter.join
170
+
171
+ y "stdout" => stdout
172
+
173
+
174
+ harp: > ruby sample/bg.rb
175
+ ---
176
+ status: run
177
+ ---
178
+ status: sleep
179
+ ---
180
+ status: sleep
181
+ ---
182
+ status: sleep
183
+ ---
184
+ 21357: 0
185
+ ---
186
+ stdout: "42\n"
187
+
188
+
139
189
  AUTHOR
140
190
 
141
191
  ara.t.howard@noaa.gov
data/gemspec.rb CHANGED
@@ -8,11 +8,11 @@ Gem::Specification::new do |spec|
8
8
  spec.platform = Gem::Platform::RUBY
9
9
  spec.summary = lib
10
10
 
11
- # spec.files = Dir[ File::join("{lib,bin}", "*") ]
12
- # spec.require_path = "lib"
13
-
14
11
  spec.files = Dir::glob "**/**"
15
12
  spec.executables = Dir::glob("bin/*").map{|exe| File::basename exe}
13
+
14
+ spec.require_path = "lib"
15
+ spec.autorequire = lib
16
16
 
17
17
  spec.has_rdoc = File::exist? "doc"
18
18
  spec.test_suite_file = "test/#{ lib }.rb" if File::directory? "test"
@@ -2,7 +2,9 @@ require 'fcntl'
2
2
 
3
3
  module Open4
4
4
  #--{{{
5
- def self.version() '0.3.0' end
5
+ def self.version
6
+ '0.4.0'
7
+ end
6
8
 
7
9
  def popen4(*cmd)
8
10
  #--{{{
@@ -46,11 +48,7 @@ module Open4
46
48
 
47
49
  begin
48
50
  e = Marshal.load ps.first
49
- if Exception === e
50
- raise e
51
- else
52
- raise "unknown failure"
53
- end
51
+ raise(Exception === e ? e : "unknown failure!")
54
52
  rescue EOFError # If we get an EOF error, then the exec was successful
55
53
  42
56
54
  end
@@ -75,6 +73,20 @@ module Open4
75
73
  module_function :popen4
76
74
  module_function :open4
77
75
 
76
+ class Error < ::StandardError; end
77
+ class SpawnError < Error
78
+ #--{{{
79
+ attr 'cmd'
80
+ attr 'status'
81
+ def exitstatus
82
+ @status.exitstatus
83
+ end
84
+ def initialize cmd, status
85
+ @cmd, @status = cmd, status
86
+ super "cmd <#{ cmd }> failed with <#{ exitstatus }>"
87
+ end
88
+ #--}}}
89
+ end
78
90
  def spawn cmd, opts = {}
79
91
  #--{{{
80
92
  getopt = lambda do |*args|
@@ -89,11 +101,13 @@ module Open4
89
101
  end
90
102
  end
91
103
 
92
- dont_raise = getopt[ 'quiet', !getopt['raise', true] ]
104
+ ignore_exit_failure = getopt[ 'ignore_exit_failure', getopt['quiet', false] ]
105
+ ignore_exec_failure = getopt[ 'ignore_exec_failure', !getopt['raise', true] ]
93
106
  exitstatus = getopt[ %w( exitstatus exit_status status ), 0 ]
94
107
  stdin = getopt[ ['stdin', 'in', '0', 0] ]
95
108
  stdout = getopt[ ['stdout', 'out', '1', 1] ]
96
109
  stderr = getopt[ ['stderr', 'err', '2', 2] ]
110
+ pid = getopt[ 'pid' ]
97
111
 
98
112
  started = false
99
113
 
@@ -102,32 +116,60 @@ module Open4
102
116
  popen4(cmd) do |c, i, o, e|
103
117
  started = true
104
118
 
105
- if stdin.respond_to? :each
106
- stdin.each{|buf| i << buf}
107
- elsif stdin.respond_to? :read
108
- i << stdin.read
109
- else
110
- i << stdin.to_s
119
+ if pid.respond_to? '<<'
120
+ pid << c
111
121
  end
112
122
 
113
- i.close
123
+ it = Thread.new(i,stdin) do |i,stdin|
124
+ if stdin
125
+ if stdin.respond_to? :each
126
+ stdin.each{|buf| i << buf}
127
+ elsif stdin.respond_to? :read
128
+ i << stdin.read
129
+ else
130
+ i << stdin.to_s
131
+ end
132
+ end
133
+ i.close
134
+ end
114
135
 
115
- ot = Thread.new(o){ o.each{|buf| stdout << buf if stdout} }
116
- et = Thread.new(e){ e.each{|buf| stderr << buf if stderr} }
136
+ ot = Thread.new(o,stdout){|o,stdout| o.each{|buf| stdout << buf if stdout}}
137
+ et = Thread.new(e,stderr){|e,stderr| e.each{|buf| stderr << buf if stderr}}
117
138
 
118
- ot.join
119
- et.join
139
+ it.join
140
+ ot.join if ot
141
+ et.join if et
120
142
  end
121
143
  rescue
122
- raise unless(not started and dont_raise)
144
+ raise unless(not started and ignore_exec_failure)
123
145
  end
124
146
 
125
- raise "cmd <#{ cmd }> failed with <#{ status }>" unless
126
- ((status == exitstatus) or dont_raise)
147
+ raise SpawnError.new(cmd, status) unless
148
+ (ignore_exit_failure or (status.nil? and ignore_exec_failure) or (status.exitstatus == exitstatus))
127
149
 
128
150
  status
129
151
  #--}}}
130
152
  end
131
153
  module_function :spawn
154
+
155
+ def background cmd, opts = {}
156
+ #--{{{
157
+ require 'thread'
158
+ q = Queue.new
159
+ opts['pid'] = opts[:pid] = q
160
+ thread = Thread.new(cmd, opts){|cmd, opts| spawn cmd, opts}
161
+ pid = q.pop
162
+ sc = class << thread; self; end
163
+ sc.module_eval {
164
+ define_method(:pid){ pid }
165
+ define_method(:spawn_status){ @spawn_status ||= value }
166
+ define_method(:exitstatus){ spawn_status.exitstatus }
167
+ }
168
+ thread
169
+ #--}}}
170
+ end
171
+ alias bg background
172
+ module_function :background
173
+ module_function :bg
132
174
  #--}}}
133
175
  end
@@ -2,7 +2,9 @@ require 'fcntl'
2
2
 
3
3
  module Open4
4
4
  #--{{{
5
- def self.version() '0.3.0' end
5
+ def self.version
6
+ '0.4.0'
7
+ end
6
8
 
7
9
  def popen4(*cmd)
8
10
  #--{{{
@@ -46,11 +48,7 @@ module Open4
46
48
 
47
49
  begin
48
50
  e = Marshal.load ps.first
49
- if Exception === e
50
- raise e
51
- else
52
- raise "unknown failure"
53
- end
51
+ raise(Exception === e ? e : "unknown failure!")
54
52
  rescue EOFError # If we get an EOF error, then the exec was successful
55
53
  42
56
54
  end
@@ -75,6 +73,20 @@ module Open4
75
73
  module_function :popen4
76
74
  module_function :open4
77
75
 
76
+ class Error < ::StandardError; end
77
+ class SpawnError < Error
78
+ #--{{{
79
+ attr 'cmd'
80
+ attr 'status'
81
+ def exitstatus
82
+ @status.exitstatus
83
+ end
84
+ def initialize cmd, status
85
+ @cmd, @status = cmd, status
86
+ super "cmd <#{ cmd }> failed with <#{ exitstatus }>"
87
+ end
88
+ #--}}}
89
+ end
78
90
  def spawn cmd, opts = {}
79
91
  #--{{{
80
92
  getopt = lambda do |*args|
@@ -89,11 +101,13 @@ module Open4
89
101
  end
90
102
  end
91
103
 
92
- dont_raise = getopt[ 'quiet', !getopt['raise', true] ]
104
+ ignore_exit_failure = getopt[ 'ignore_exit_failure', getopt['quiet', false] ]
105
+ ignore_exec_failure = getopt[ 'ignore_exec_failure', !getopt['raise', true] ]
93
106
  exitstatus = getopt[ %w( exitstatus exit_status status ), 0 ]
94
107
  stdin = getopt[ ['stdin', 'in', '0', 0] ]
95
108
  stdout = getopt[ ['stdout', 'out', '1', 1] ]
96
109
  stderr = getopt[ ['stderr', 'err', '2', 2] ]
110
+ pid = getopt[ 'pid' ]
97
111
 
98
112
  started = false
99
113
 
@@ -102,32 +116,60 @@ module Open4
102
116
  popen4(cmd) do |c, i, o, e|
103
117
  started = true
104
118
 
105
- if stdin.respond_to? :each
106
- stdin.each{|buf| i << buf}
107
- elsif stdin.respond_to? :read
108
- i << stdin.read
109
- else
110
- i << stdin.to_s
119
+ if pid.respond_to? '<<'
120
+ pid << c
111
121
  end
112
122
 
113
- i.close
123
+ it = Thread.new(i,stdin) do |i,stdin|
124
+ if stdin
125
+ if stdin.respond_to? :each
126
+ stdin.each{|buf| i << buf}
127
+ elsif stdin.respond_to? :read
128
+ i << stdin.read
129
+ else
130
+ i << stdin.to_s
131
+ end
132
+ end
133
+ i.close
134
+ end
114
135
 
115
- ot = Thread.new(o){ o.each{|buf| stdout << buf if stdout} }
116
- et = Thread.new(e){ e.each{|buf| stderr << buf if stderr} }
136
+ ot = Thread.new(o,stdout){|o,stdout| o.each{|buf| stdout << buf if stdout}}
137
+ et = Thread.new(e,stderr){|e,stderr| e.each{|buf| stderr << buf if stderr}}
117
138
 
118
- ot.join
119
- et.join
139
+ it.join
140
+ ot.join if ot
141
+ et.join if et
120
142
  end
121
143
  rescue
122
- raise unless(not started and dont_raise)
144
+ raise unless(not started and ignore_exec_failure)
123
145
  end
124
146
 
125
- raise "cmd <#{ cmd }> failed with <#{ status }>" unless
126
- ((status == exitstatus) or dont_raise)
147
+ raise SpawnError.new(cmd, status) unless
148
+ (ignore_exit_failure or (status.nil? and ignore_exec_failure) or (status.exitstatus == exitstatus))
127
149
 
128
150
  status
129
151
  #--}}}
130
152
  end
131
153
  module_function :spawn
154
+
155
+ def background cmd, opts = {}
156
+ #--{{{
157
+ require 'thread'
158
+ q = Queue.new
159
+ opts['pid'] = opts[:pid] = q
160
+ thread = Thread.new(cmd, opts){|cmd, opts| spawn cmd, opts}
161
+ pid = q.pop
162
+ sc = class << thread; self; end
163
+ sc.module_eval {
164
+ define_method(:pid){ pid }
165
+ define_method(:spawn_status){ @spawn_status ||= value }
166
+ define_method(:exitstatus){ spawn_status.exitstatus }
167
+ }
168
+ thread
169
+ #--}}}
170
+ end
171
+ alias bg background
172
+ module_function :background
173
+ module_function :bg
132
174
  #--}}}
133
175
  end
File without changes
@@ -0,0 +1,21 @@
1
+ require 'yaml'
2
+ require 'open4'
3
+ include Open4
4
+
5
+ stdin = '42'
6
+ stdout = ''
7
+ stderr = ''
8
+
9
+ t = bg 'ruby -e"sleep 4; puts ARGF.read"', 0=>stdin, 1=>stdout, 2=>stderr
10
+
11
+ waiter = Thread.new{ y t.pid => t.exitstatus } # t.exitstatus is a blocking call!
12
+
13
+ while((status = t.status))
14
+ y "status" => status
15
+ sleep 1
16
+ end
17
+
18
+ waiter.join
19
+
20
+ y "stdout" => stdout
21
+
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: open4
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.0
7
- date: 2006-04-19 00:00:00.000000 -06:00
6
+ version: 0.4.0
7
+ date: 2006-04-26 00:00:00.000000 -06:00
8
8
  summary: open4
9
9
  require_paths:
10
10
  - lib
@@ -12,7 +12,7 @@ email: ara.t.howard@noaa.gov
12
12
  homepage: http://codeforpeople.com/lib/ruby/open4/
13
13
  rubyforge_project:
14
14
  description:
15
- autorequire:
15
+ autorequire: open4
16
16
  default_executable:
17
17
  bindir: bin
18
18
  has_rdoc: false
@@ -29,7 +29,6 @@ cert_chain:
29
29
  authors:
30
30
  - Ara T. Howard
31
31
  files:
32
- - open4-0.3.0.gem
33
32
  - install.rb
34
33
  - sample
35
34
  - lib
@@ -37,11 +36,13 @@ files:
37
36
  - build
38
37
  - install
39
38
  - gemspec.rb
39
+ - open4-0.4.0.gem
40
40
  - sample/block.rb
41
41
  - sample/simple.rb
42
42
  - sample/exception.rb
43
43
  - sample/spawn.rb
44
- - lib/open4-0.3.0.rb
44
+ - sample/bg.rb
45
+ - lib/open4-0.4.0.rb
45
46
  - lib/open4.rb
46
47
  test_files: []
47
48
  rdoc_options: []