rubysh 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,233 @@
1
+ require File.expand_path('../../../_lib', File.dirname(__FILE__))
2
+
3
+ module RubyshTest::Unit
4
+ class ParallelIOTest < UnitTest
5
+ describe 'when given no readers / writers' do
6
+ it 'returns immediately from run' do
7
+ io = Rubysh::Subprocess::ParallelIO.new({}, {})
8
+ io.run
9
+ end
10
+ end
11
+
12
+ describe 'when given only readers' do
13
+ it 'makes callbacks as data is read' do
14
+ reader, writer = IO.pipe
15
+ writer.write('hi')
16
+
17
+ count = 0
18
+
19
+ io = Rubysh::Subprocess::ParallelIO.new({reader => :reader}, {})
20
+ io.on_read do |reader_name, data|
21
+ count += 1
22
+
23
+ case count
24
+ when 1
25
+ assert_equal('hi', data)
26
+ writer.write('bye')
27
+ when 2
28
+ assert_equal('bye', data)
29
+ writer.write('done')
30
+ when 3
31
+ assert_equal('done', data)
32
+ writer.close
33
+ when 4
34
+ assert_equal(Rubysh::Subprocess::ParallelIO::EOF, data)
35
+ else
36
+ assert(false)
37
+ end
38
+ end
39
+ io.run
40
+ assert_equal(4, count)
41
+ end
42
+
43
+ it 'uses the reader name when data is read' do
44
+ reader, writer = IO.pipe
45
+ writer.write('hi')
46
+
47
+ io = Rubysh::Subprocess::ParallelIO.new({reader => :reader}, {})
48
+ io.on_read do |reader_name, data|
49
+ assert_equal(:reader, reader_name)
50
+ writer.close unless writer.closed?
51
+ end
52
+ io.run
53
+ end
54
+ end
55
+
56
+ describe 'when given only writers' do
57
+ it 'makes callbacks as data is written' do
58
+ reader, writer = IO.pipe
59
+
60
+ count = 0
61
+
62
+ io = Rubysh::Subprocess::ParallelIO.new({}, {writer => :writer})
63
+ io.on_write do |writer_name, data, remaining|
64
+ count += 1
65
+
66
+ case count
67
+ when 1
68
+ assert_equal('hi', data)
69
+ assert_equal('', remaining)
70
+ io.write(:writer, 'bye', false)
71
+ when 2
72
+ assert_equal('bye', data)
73
+ assert_equal('', remaining)
74
+ io.write(:writer, 'done', false)
75
+ when 3
76
+ assert_equal('done', data)
77
+ assert_equal('', remaining)
78
+ io.write(:writer, '', true)
79
+ when 4
80
+ assert_equal(Rubysh::Subprocess::ParallelIO::EOF, data)
81
+ assert_equal('', remaining)
82
+ else
83
+ assert(false)
84
+ end
85
+ end
86
+ io.write(:writer, 'hi', false)
87
+ io.run
88
+
89
+ assert_equal(4, count)
90
+ received = reader.read
91
+ assert_equal('hibyedone', received)
92
+ end
93
+
94
+ it 'uses the writer name when data is written' do
95
+ reader, writer = IO.pipe
96
+
97
+ io = Rubysh::Subprocess::ParallelIO.new({}, {writer => :writer})
98
+ io.on_write do |writer_name, data|
99
+ assert_equal(:writer, writer_name)
100
+ end
101
+ io.run
102
+ end
103
+
104
+ it 'splits up data if it cannot all be written at once' do
105
+ reader, writer = IO.pipe
106
+
107
+ io = Rubysh::Subprocess::ParallelIO.new({}, {writer => :writer})
108
+ io.on_write do |writer_name, data, remaining|
109
+ unless data == Rubysh::Subprocess::ParallelIO::EOF
110
+ assert(remaining.length > 0)
111
+ assert(data.length > 0)
112
+ writer.close
113
+ end
114
+ end
115
+ io.write(:writer, '*' * 100000, false)
116
+ io.run
117
+ end
118
+
119
+ it 'actually writes the correct data if it cannot all be written at once' do
120
+ reader, writer = IO.pipe
121
+ input = '*' * 100000
122
+ received = ''
123
+
124
+ io = Rubysh::Subprocess::ParallelIO.new({}, {writer => :writer})
125
+ io.on_write do |writer_name, data, remaining|
126
+ unless data == Rubysh::Subprocess::ParallelIO::EOF
127
+ received << reader.read_nonblock(100000)
128
+ end
129
+ end
130
+ io.write(:writer, input, true)
131
+ io.run
132
+
133
+ assert_equal(input, received)
134
+ end
135
+ end
136
+
137
+ describe 'when given both writers and readers' do
138
+ it 'correctly reads and writes data' do
139
+ reader1, writer1 = IO.pipe
140
+ reader2, writer2 = IO.pipe
141
+
142
+ count1 = 0
143
+ count2 = 0
144
+
145
+ io = Rubysh::Subprocess::ParallelIO.new(
146
+ {reader1 => :reader1, reader2 => :reader2},
147
+ {writer1 => :writer1, writer2 => :writer2})
148
+
149
+ io.on_read do |reader_name, data|
150
+ if reader_name == :reader1
151
+ count1 += 1
152
+ case count1
153
+ when 2
154
+ assert_equal('hi1', data)
155
+ io.write(:writer1, 'test1', false)
156
+ when 4
157
+ assert_equal('test1', data)
158
+ io.write(:writer1, 'final1', true)
159
+ when 7
160
+ assert_equal('final1', data)
161
+ when 8
162
+ assert_equal(Rubysh::Subprocess::ParallelIO::EOF, data)
163
+ else
164
+ raise "Unexpected count1: #{count1}"
165
+ end
166
+ elsif reader_name == :reader2
167
+ count2 += 1
168
+ case count2
169
+ when 2
170
+ assert_equal('hi2', data)
171
+ io.write(:writer2, 'test2', false)
172
+ when 4
173
+ assert_equal('test2', data)
174
+ io.write(:writer2, 'final2', true)
175
+ when 7
176
+ assert_equal('final2', data)
177
+ when 8
178
+ assert_equal(Rubysh::Subprocess::ParallelIO::EOF, data)
179
+ else
180
+ raise "Unexpected count2: #{count2}"
181
+ end
182
+ else
183
+ raise "Unrecognized reader"
184
+ end
185
+ end
186
+
187
+ io.on_write do |writer_name, data, remaining|
188
+ if writer_name == :writer1
189
+ count1 += 1
190
+
191
+ case count1
192
+ when 1
193
+ assert_equal('hi1', data)
194
+ when 3
195
+ assert_equal('test1', data)
196
+ when 5
197
+ assert_equal('final1', data)
198
+ when 6
199
+ assert_equal(Rubysh::Subprocess::ParallelIO::EOF, data)
200
+ else
201
+ raise "Unexpected count1: #{count1}"
202
+ end
203
+ elsif writer_name == :writer2
204
+ count2 += 1
205
+
206
+ case count2
207
+ when 1
208
+ assert_equal('hi2', data)
209
+ when 3
210
+ assert_equal('test2', data)
211
+ when 5
212
+ assert_equal('final2', data)
213
+ when 6
214
+ assert_equal(Rubysh::Subprocess::ParallelIO::EOF, data)
215
+ else
216
+ raise "Unexpected count2: #{count2}"
217
+ end
218
+ else
219
+ raise "Unrecognized writer"
220
+ end
221
+ end
222
+
223
+ io.write(:writer1, 'hi1', false)
224
+ io.write(:writer2, 'hi2', false)
225
+
226
+ io.run
227
+
228
+ assert_equal(8, count1)
229
+ assert_equal(8, count2)
230
+ end
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,37 @@
1
+ require File.expand_path('../../_lib', File.dirname(__FILE__))
2
+
3
+ module RubyshTest::Unit
4
+ class SubprocessTest < UnitTest
5
+ describe 'when running a command' do
6
+ it 'calls exec with the expected arguments' do
7
+ read_fd, write_fd = stub_pipe
8
+ Kernel.expects(:exec).with(['cmd', 'cmd'], 'arg1', 'arg2')
9
+
10
+ proc = Rubysh::Subprocess.new(['cmd', 'arg1', 'arg2'])
11
+ proc.send(:open_exec_status)
12
+ assert_raises(Rubysh::Error::UnreachableError) do
13
+ proc.send(:do_run_child)
14
+ end
15
+ end
16
+
17
+ describe 'with a Redirect' do
18
+ it 'calls exec with the expected arguments' do
19
+ runner = mock
20
+
21
+ read_fd, write_fd = stub_pipe
22
+ Kernel.expects(:exec).with(['cmd', 'cmd'], 'arg1', 'arg2')
23
+
24
+ redirect = Rubysh::Redirect.new(2, '>', 1)
25
+ redirect.expects(:apply!).with(runner)
26
+
27
+ proc = Rubysh::Subprocess.new(['cmd', 'arg1', 'arg2'],
28
+ [redirect], [], runner)
29
+ proc.send(:open_exec_status)
30
+ assert_raises(Rubysh::Error::UnreachableError) do
31
+ proc.send(:do_run_child)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,74 @@
1
+ require File.expand_path('../_lib', File.dirname(__FILE__))
2
+
3
+ module RubyshTest::Unit
4
+ class RubyshTest < UnitTest
5
+ describe 'when running a command' do
6
+ # Rubysh('ls', '/tmp')
7
+ describe 'that is straightline' do
8
+ it 'prints nicely' do
9
+ command = Rubysh('ls', '/tmp')
10
+ expected = 'Command: ls /tmp'
11
+ assert_equal(expected, command.to_s)
12
+ end
13
+
14
+ it 'creates a command with the expected arguments' do
15
+ command = Rubysh('ls', '/tmp')
16
+ runner = Rubysh::Runner.new(command)
17
+ command.send(:prepare_subprocess, runner)
18
+ subprocess = runner.state(command)[:subprocess]
19
+ assert_equal('ls', subprocess.command)
20
+ assert_equal(['/tmp'], subprocess.args)
21
+ assert_equal([], subprocess.directives)
22
+ end
23
+ end
24
+
25
+ # Rubysh('ls', '/tmp') | Rubysh('grep', 'myfile')
26
+ describe 'with a pipe' do
27
+ it 'prints nicely' do
28
+ command = Rubysh('ls', '/tmp') | Rubysh('grep', 'myfile')
29
+ expected = 'Command: ls /tmp | grep myfile'
30
+ assert_equal(expected, command.to_s)
31
+ end
32
+
33
+ it 'creates a command with the expected arguments' do
34
+ read_fd, write_fd = stub_pipe
35
+ command = Rubysh('ls', '/tmp') | Rubysh('grep', 'myfile')
36
+
37
+ pipeline = command.pipeline
38
+ assert_equal(2, pipeline.length)
39
+
40
+ runner = Rubysh::Runner.new(command)
41
+
42
+ left, right = pipeline
43
+ left.send(:prepare_subprocess, runner)
44
+ right.send(:prepare_subprocess, runner)
45
+
46
+ left_subprocess = runner.state(left)[:subprocess]
47
+ right_subprocess = runner.state(right)[:subprocess]
48
+
49
+ assert_equal([], left_subprocess.directives)
50
+ assert_equal([], right_subprocess.directives)
51
+ end
52
+ end
53
+
54
+ # Rubysh('ls', '/tmp', Rubysh.stderr > Rubysh.stdout)
55
+ describe 'with a redirection to another file descriptor' do
56
+ it 'prints nicely' do
57
+ command = Rubysh('ls', '/tmp', Rubysh.stderr > Rubysh.stdout)
58
+ expected = 'Command: ls /tmp 2>&1'
59
+ assert_equal(expected, command.to_s)
60
+ end
61
+
62
+ it 'creates a command with the expected arguments' do
63
+ command = Rubysh('ls', '/tmp', Rubysh.stderr > Rubysh.stdout)
64
+ runner = Rubysh::Runner.new(command)
65
+ command.send(:prepare_subprocess, runner)
66
+ subprocess = runner.state(command)[:subprocess]
67
+ assert_equal('ls', subprocess.command)
68
+ assert_equal(['/tmp'], subprocess.args)
69
+ assert_equal([Rubysh::Redirect.new(Rubysh::FD.new(2), '>', Rubysh::FD.new(1))], subprocess.directives)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubysh
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Greg Brockman
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-09-12 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: minitest
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - "="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 3
31
+ - 1
32
+ - 0
33
+ version: 3.1.0
34
+ type: :development
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: mocha
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ type: :development
49
+ version_requirements: *id002
50
+ description: "Rubysh: Ruby subprocesses made easy"
51
+ email:
52
+ - gdb@gregbrockman.com
53
+ executables: []
54
+
55
+ extensions: []
56
+
57
+ extra_rdoc_files: []
58
+
59
+ files:
60
+ - .gitignore
61
+ - Gemfile
62
+ - LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - lib/rubysh.rb
66
+ - lib/rubysh/base_command.rb
67
+ - lib/rubysh/base_directive.rb
68
+ - lib/rubysh/command.rb
69
+ - lib/rubysh/error.rb
70
+ - lib/rubysh/fd.rb
71
+ - lib/rubysh/pipe.rb
72
+ - lib/rubysh/pipeline.rb
73
+ - lib/rubysh/redirect.rb
74
+ - lib/rubysh/runner.rb
75
+ - lib/rubysh/subprocess.rb
76
+ - lib/rubysh/subprocess/parallel_io.rb
77
+ - lib/rubysh/subprocess/pipe_wrapper.rb
78
+ - lib/rubysh/triple_less_than.rb
79
+ - lib/rubysh/util.rb
80
+ - lib/rubysh/version.rb
81
+ - rubysh.gemspec
82
+ - test/_lib.rb
83
+ - test/functional/_lib.rb
84
+ - test/functional/lib/fd-lister
85
+ - test/functional/lib/leaked_fds.rb
86
+ - test/functional/lib/redirect_ordering.rb
87
+ - test/functional/lib/triple_less_than.rb
88
+ - test/integration/_lib.rb
89
+ - test/integration/lib/rubysh.rb
90
+ - test/rubysh
91
+ - test/unit/_lib.rb
92
+ - test/unit/lib/rubysh.rb
93
+ - test/unit/lib/rubysh/command.rb
94
+ - test/unit/lib/rubysh/pipeline.rb
95
+ - test/unit/lib/rubysh/redirect.rb
96
+ - test/unit/lib/rubysh/runner.rb
97
+ - test/unit/lib/rubysh/subprocess.rb
98
+ - test/unit/lib/rubysh/subprocess/parallel_io.rb
99
+ homepage: ""
100
+ licenses: []
101
+
102
+ post_install_message:
103
+ rdoc_options: []
104
+
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ hash: 3
113
+ segments:
114
+ - 0
115
+ version: "0"
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ hash: 3
122
+ segments:
123
+ - 0
124
+ version: "0"
125
+ requirements: []
126
+
127
+ rubyforge_project:
128
+ rubygems_version: 1.8.24
129
+ signing_key:
130
+ specification_version: 3
131
+ summary: "Rubysh makes shelling out easy with a __sh__-like syntax layer for Ruby: irb -r rubysh >> command = Rubysh('echo', 'hello-from-Rubysh') | Rubysh('grep', '--color', 'Rubysh') >> command.run hello-from-Rubysh => Rubysh::Runner: echo hello-from-Rubysh | grep --color Rubysh (exitstatus: 0)"
132
+ test_files:
133
+ - test/_lib.rb
134
+ - test/functional/_lib.rb
135
+ - test/functional/lib/fd-lister
136
+ - test/functional/lib/leaked_fds.rb
137
+ - test/functional/lib/redirect_ordering.rb
138
+ - test/functional/lib/triple_less_than.rb
139
+ - test/integration/_lib.rb
140
+ - test/integration/lib/rubysh.rb
141
+ - test/rubysh
142
+ - test/unit/_lib.rb
143
+ - test/unit/lib/rubysh.rb
144
+ - test/unit/lib/rubysh/command.rb
145
+ - test/unit/lib/rubysh/pipeline.rb
146
+ - test/unit/lib/rubysh/redirect.rb
147
+ - test/unit/lib/rubysh/runner.rb
148
+ - test/unit/lib/rubysh/subprocess.rb
149
+ - test/unit/lib/rubysh/subprocess/parallel_io.rb