rubysh 0.0.1

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.
@@ -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