objective_command 0.1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/AUTHORS +5 -0
  2. data/ChangeLog +17 -0
  3. data/NEWS +3 -0
  4. data/README +2 -0
  5. data/Rakefile +8 -0
  6. data/SPEC.gemspec +15 -0
  7. data/SPEC.yml +43 -0
  8. data/bin/ocmd +32 -0
  9. data/lib/hookable.rb +284 -0
  10. data/lib/hooker.rb +47 -0
  11. data/lib/objective_command/all.rb +32 -0
  12. data/lib/objective_command/commands/command.rb +535 -0
  13. data/lib/objective_command/commands/factory.rb +69 -0
  14. data/lib/objective_command/commands/pipe.rb +121 -0
  15. data/lib/objective_command/commands/seq.rb +35 -0
  16. data/lib/objective_command/datas/composite.rb +55 -0
  17. data/lib/objective_command/datas/data.rb +175 -0
  18. data/lib/objective_command/datas/factory.rb +74 -0
  19. data/lib/objective_command/datas/pipe.rb +55 -0
  20. data/lib/objective_command/datas/temp.rb +24 -0
  21. data/lib/objective_command/datas.rb +11 -0
  22. data/lib/objective_command/helpers.rb +113 -0
  23. data/lib/objective_command/runners/exec.rb +46 -0
  24. data/lib/objective_command/runners/fork.rb +91 -0
  25. data/lib/objective_command/runners/mockable.rb +62 -0
  26. data/lib/objective_command/runners/no_run.rb +44 -0
  27. data/lib/objective_command/runners/popen.rb +49 -0
  28. data/lib/objective_command/runners/runner.rb +227 -0
  29. data/lib/objective_command/runners/system.rb +54 -0
  30. data/lib/objective_command/runners.rb +11 -0
  31. data/lib/objective_command/shell.rb +173 -0
  32. data/lib/objective_command/version_id.rb +10 -0
  33. data/lib/objective_command.rb +54 -0
  34. data/test/check-objective_command.yml +10 -0
  35. data/test/check-pkg-objective_command.yml +13 -0
  36. data/test/sanity/multiple-requires.yml +62 -0
  37. data/test/sanity/single-requires.yml +40 -0
  38. data/test/sanity-suite.yml +10 -0
  39. data/test/unit-suite.yml +14 -0
  40. metadata +97 -0
@@ -0,0 +1,535 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2005, 2006 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id: /w/fey/cmd/trunk/lib/objective_command/commands/command.rb 29674 2006-09-12T21:05:16.387536Z ertai $
5
+
6
+ module ObjectiveCommand
7
+
8
+ module Commands
9
+
10
+ class Command
11
+
12
+ attr_accessor :command
13
+ attr_accessor :dir
14
+ attr_accessor :input
15
+ attr_accessor :output
16
+ attr_accessor :error
17
+ attr_accessor :args
18
+ attr_accessor :open_mode
19
+
20
+ #
21
+ # Construction methods.
22
+ #
23
+
24
+ def initialize ( command_name, *args )
25
+ @command = command_name
26
+ @args = args.flatten
27
+ @open_mode = :w
28
+ @dir = nil
29
+ @input, @output, @error = nil, nil, nil
30
+ end
31
+
32
+ #
33
+ # Running methods.
34
+ #
35
+
36
+ @@default_runners = {}
37
+ def run_with_options ( runner_class, options )
38
+ if options.empty?
39
+ runner = @@default_runners[runner_class] ||= runner_class.new
40
+ else
41
+ runner = runner_class.new.apply_options options
42
+ end
43
+ run(runner)
44
+ end
45
+
46
+
47
+ # Simulate Kernel#system() to run the command (No shell expansion).
48
+ def system ( *options )
49
+ run_with_options(Runners::System, options.flatten)
50
+ end
51
+
52
+
53
+ # Use the ExecRunner.
54
+ def exec ( *options )
55
+ run_with_options(Runners::Exec, options.flatten)
56
+ end
57
+
58
+
59
+ # FIXME test me
60
+ def sys ( *options )
61
+ run_with_options(Runners::System, [:v, :r] + options.flatten)
62
+ end
63
+
64
+
65
+ # Use Kernel#system() but with a string to have the shell expansion.
66
+ # FIXME make me a runner
67
+ def sh
68
+ Kernel.system(to_sh)
69
+ end
70
+
71
+
72
+ # Use Kernel#exec() but with a string to have the shell expansion.
73
+ # FIXME make me a runner
74
+ def sh!
75
+ Kernel.exec(to_sh)
76
+ end
77
+
78
+
79
+ # Use Kernel#` and return the resulting string.
80
+ # FIXME make me a runner
81
+ def expand
82
+ `#{to_sh}`
83
+ end
84
+
85
+
86
+ def popen ( *options )
87
+ run_with_options(Runners::Popen, options.flatten)
88
+ end
89
+
90
+
91
+ def fork ( *options )
92
+ run_with_options(Runners::Fork, options.flatten)
93
+ end
94
+
95
+
96
+ # FIXME design me!
97
+ # FIXME make me a runner
98
+ def ruby
99
+ end
100
+
101
+
102
+ # Use a ObjectiveCommand::Runners::Runner and return a ObjectiveCommand::Datas::Data.
103
+ def run ( runner=@runner )
104
+ unless runner.respond_to? :run
105
+ raise ArgumentError, "need a runner not: #{runner.inspect}"
106
+ end
107
+ runner.run(self)
108
+ end
109
+
110
+
111
+
112
+ #
113
+ # Operators.
114
+ #
115
+
116
+
117
+ # Pipe two commands.
118
+ def | ( rhs )
119
+ Commands::Pipe.new(self, rhs)
120
+ end
121
+
122
+
123
+ # Supply return a new commands with these arguments added.
124
+ def [] ( *args )
125
+ cmd = dup
126
+ cmd.args += args.flatten
127
+ cmd
128
+ end
129
+
130
+
131
+ # Chain two commands (like a `;' in shell), and return a new one.
132
+ def + ( rhs )
133
+ case rhs
134
+ when Command
135
+ Seq.new(self, rhs)
136
+ else
137
+ self[rhs]
138
+ end
139
+ end
140
+
141
+
142
+ # Return a new command with the given command input.
143
+ def < ( arg )
144
+ cmd = dup
145
+ cmd.input = arg
146
+ cmd
147
+ end
148
+
149
+
150
+ def add_outputs ( out, err )
151
+ cmd = dup
152
+ cmd.output = out.dup if out
153
+ cmd.error = err.dup if err
154
+ cmd
155
+ end
156
+ protected :add_outputs
157
+
158
+
159
+ # Return a new command with the given command output.
160
+ def > ( arg )
161
+ out, err = (arg.is_a?(Array))? arg : [arg, nil]
162
+ add_outputs(out, err)
163
+ end
164
+
165
+
166
+ # Like > but open the output in append mode.
167
+ def >> ( arg )
168
+ out, err = (arg.is_a?(Array))? arg : [arg, nil]
169
+ @open_mode = :a
170
+ add_outputs(out, err)
171
+ end
172
+
173
+
174
+ # Add an argument to a command.
175
+ # cmd = Command.new('ls')
176
+ # cmd << '-la'
177
+ # cmd.sh
178
+ def << ( arg )
179
+ @args << arg
180
+ self
181
+ end
182
+
183
+
184
+
185
+ #
186
+ # Misc
187
+ #
188
+
189
+ def arg_string
190
+ @args.map { |arg| arg.to_s.to_sh }.join(' ')
191
+ end
192
+
193
+ def whereis ( path=ENV['PATH'] )
194
+ # FIXME
195
+ end
196
+
197
+
198
+ #
199
+ # Conversion methods
200
+ #
201
+
202
+ def to_s
203
+ str = @command.to_s.to_sh
204
+ arg_str = arg_string
205
+ str += ' ' + arg_str unless arg_str.empty?
206
+ str
207
+ end
208
+
209
+
210
+ def to_sh
211
+ cmd = instanciate_args
212
+ "#{cmd.to_s}#{cmd.sh_args}"
213
+ end
214
+
215
+
216
+ def inspect_for_unified_matchers
217
+ "#{to_s.inspect}.to_ocmd"
218
+ end
219
+
220
+
221
+ def instanciate_args!
222
+ if defined? @input and @input and @args.include? '%i'
223
+ @args.map! { |a| (a == '%i')? @input : a }
224
+ @input = nil
225
+ end
226
+ if defined? @output and @output and @args.include? '%o'
227
+ @args.map! { |a| (a == '%o')? @output : a }
228
+ @output = nil
229
+ end
230
+ if defined? @error and @error and @args.include? '%e'
231
+ @args.map! { |a| (a == '%e')? @error : a }
232
+ @error = nil
233
+ end
234
+ end
235
+
236
+ def instanciate_args
237
+ copy = dup
238
+ copy.instanciate_args!
239
+ copy
240
+ end
241
+
242
+ def sh_args
243
+ args = ''
244
+ [ ['<', input], ['>', output], ['2>', error] ].each do |str, io|
245
+ args += " #{str} #{io.to_s.to_sh}" if io and not (io.respond_to? :pipe? and io.pipe?)
246
+ end
247
+ args
248
+ end
249
+
250
+
251
+ def to_a
252
+ [@command.dup, *@args.map { |arg| arg.to_s }]
253
+ end
254
+
255
+ def to_ocmd
256
+ self
257
+ end
258
+
259
+ def freeze
260
+ super
261
+ for i in [@command, @dir, @input, @output, @error, @args] do
262
+ i.freeze
263
+ end
264
+ end
265
+
266
+ end # class Command
267
+
268
+ Helpers.import!
269
+
270
+ test_section __FILE__ do
271
+
272
+ class CommandTest < Test::Unit::TestCase
273
+
274
+ def setup
275
+ @file = TempPath.new
276
+ @tmp = TempPath.new
277
+ @tmp2 = TempPath.new
278
+ @file.open('w') { |f| f.puts "bla bla\n foo bar"}
279
+ ENV['TEST_FILE'] = @file.to_s
280
+ @touch = Command.new('touch')
281
+ @cp = Command.new('cp')
282
+ @cat = Command.new('cat')
283
+ @wc = Command.new('wc')
284
+ @sleep = Command.new('sleep')
285
+ @dne = Command.new('ThisCommandDoesNotExist')
286
+ @dev_null = Pathname.new('/dev/null')
287
+ end
288
+
289
+ def teardown
290
+ [@file, @tmp, @tmp2].each { |t| t.clean }
291
+ end
292
+
293
+ def test_0_initialize
294
+ end
295
+
296
+ def test_system_dne
297
+ @dne.system
298
+ assert_equal(127, $?.exitstatus)
299
+ end
300
+
301
+ def test_system
302
+ @touch << @tmp.to_s
303
+ @touch.system
304
+ assert_equal(0, $?)
305
+ assert(@tmp.exist?)
306
+ end
307
+
308
+ def test_system_raise_on_failures
309
+ assert_raise(Runners::Runner::FailureHooker::Error) do
310
+ 'false'.to_ocmd.system(:r)
311
+ end
312
+ assert_not_equal(0, $?)
313
+ end
314
+
315
+ def test_sh_and_pipe
316
+ ((@cat | @wc) < @file > @tmp).sh
317
+ assert_equal(0, $?)
318
+ assert(@tmp.exist?)
319
+ assert_match(/\s*2\s*4\s*17\s+/, @tmp.read)
320
+ end
321
+
322
+ def test_system_and_pipe
323
+ ((@cat | @wc) < @file.open('r+') > @tmp).system
324
+ assert_equal(0, $?)
325
+ assert(@tmp.exist?)
326
+ assert_match(/\s*2\s*4\s*17\s+/, @tmp.read)
327
+ end
328
+
329
+ def test_system_is_not_sh
330
+ @cat << '$TEST_FILE'
331
+ @cat.error = @dev_null
332
+ (@cat > @tmp).system
333
+ assert_not_equal(0, $?)
334
+ assert(!@tmp.exist? || @tmp.zero?)
335
+ end
336
+
337
+ def test_exec
338
+ @cp << @file << @tmp
339
+ pid = fork do
340
+ @cp.exec
341
+ end
342
+ Process.waitpid pid
343
+ assert_equal(0, $?)
344
+ assert(@tmp.exist?)
345
+ assert_equal(@file.read, @tmp.read)
346
+ end
347
+
348
+ def test_exec_not_sh!
349
+ @cat << '$TEST_FILE'
350
+ @cat.error = @dev_null
351
+ pid = fork do
352
+ (@cat > @tmp).exec
353
+ end
354
+ Process.waitpid pid
355
+ assert_not_equal(0, $?)
356
+ assert(!@tmp.exist? || @tmp.size.zero?)
357
+ end
358
+
359
+ def test_sh
360
+ @cat << '$TEST_FILE'
361
+ (@cat > @tmp).sh
362
+ assert_equal(0, $?)
363
+ assert(@tmp.exist?)
364
+ assert_equal(@file.read, @tmp.read)
365
+ end
366
+
367
+ def test_sh2
368
+ ((@cat | @wc) < @file > @tmp).sh
369
+ assert_equal(0, $?)
370
+ assert(@tmp.exist?)
371
+ assert_match(/\s*2\s*4\s*17\s+/, @tmp.read)
372
+ end
373
+
374
+ def test_sh!
375
+ @cat << '$TEST_FILE'
376
+ pid = fork do
377
+ (@cat > @tmp).sh!
378
+ end
379
+ Process.waitpid pid
380
+ assert_equal(0, $?)
381
+ assert(@tmp.exist?)
382
+ assert_equal(@file.read, @tmp.read)
383
+ end
384
+
385
+ def test_expand
386
+ @cat << '$TEST_FILE'
387
+ str = (@cat).expand
388
+ assert_equal(0, $?)
389
+ assert_equal(@file.read, str)
390
+
391
+ str = ((@cat | @wc) < @file).expand
392
+ assert_equal(0, $?)
393
+ assert_match(/\s*2\s*4\s*17\s+/, str)
394
+ end
395
+
396
+ # FIXME
397
+ def test_popen
398
+ cmd = (@touch + @tmp) + (@sleep + 1)
399
+ diff = DTime.diff { @data = cmd.popen }
400
+ assert(@tmp.exist?)
401
+ @data.waitpid
402
+ assert(@tmp.exist?)
403
+ assert(diff.to_f < 1)
404
+ end
405
+
406
+ def test_fork
407
+ sleep_arg = 2
408
+ cmd = (@touch + @tmp) + (@sleep + sleep_arg)
409
+ diff = DTime.diff { @data = cmd.fork }
410
+ assert(@tmp.exist?)
411
+ @data.waitpid
412
+ assert(@tmp.exist?)
413
+ assert(diff.to_f < sleep_arg, "#{diff} should be < #{sleep_arg}")
414
+ end
415
+
416
+ def test_ruby
417
+ # FIXME
418
+ end
419
+
420
+ def test_pipe # test_|
421
+ assert_kind_of(Pipe, (@cat | @wc) < @file)
422
+ end
423
+
424
+ def test_subscript # test_[]
425
+ assert_equal(['a', 'b'], @cat['a', 'b'].args)
426
+ assert_equal(['a'], @cat['a'].args)
427
+ assert_equal([], @cat[].args)
428
+ assert_equal(['a', 'b', 'c'], @cat[[['a'], 'b', ['c']]].args)
429
+ end
430
+
431
+ def test_chain # test_+
432
+ assert_kind_of(Seq, (@cat + @wc) < @file)
433
+ cmd = @cat + @file.to_s
434
+ assert_kind_of(Command, cmd)
435
+ assert_equal([@file.to_s], cmd.args)
436
+ cmd += ['a', 'b']
437
+ assert_equal([@file.to_s, 'a', 'b'], cmd.args)
438
+ cmd += @file.to_s
439
+ assert_equal([@file.to_s, 'a', 'b', @file.to_s], cmd.args)
440
+ end
441
+
442
+ def test_chain_complex
443
+ ((@cat < @file > @tmp) + (@wc + [@tmp] > @tmp2)).sh
444
+ assert_equal(0, $?)
445
+ assert(@tmp.exist?)
446
+ assert(@tmp2.exist?)
447
+ assert_equal(@file.read, @tmp.read)
448
+ assert_match(/\s*2\s*4\s*17\s*#{@tmp}\s+/, @tmp2.read)
449
+ end
450
+
451
+ def test_add_input # test_<
452
+ @cat.input = 'foo'
453
+ assert_equal('foo', @cat.input)
454
+ cmd = @cat < 'bar'
455
+ assert_equal('bar', cmd.input)
456
+ assert_not_equal(cmd.object_id, @cat.object_id)
457
+ end
458
+
459
+ def test_add_output # test_>
460
+ @cat.output = 'foo'
461
+ assert_equal('foo', @cat.output)
462
+ cmd = @cat > 'bar'
463
+ assert_equal('bar', cmd.output)
464
+ cmd = @cat > @file
465
+ assert_equal(@file, cmd.output)
466
+ assert_equal(:w, cmd.open_mode)
467
+ assert_not_equal(cmd.object_id, @cat.object_id)
468
+ cmd = @cat > [ 'outbar', 'errbar' ]
469
+ assert_equal('outbar', cmd.output)
470
+ assert_equal('errbar', cmd.error)
471
+ cmd = @cat > [ @file, @file ]
472
+ assert_equal(:w, cmd.open_mode)
473
+ end
474
+
475
+ def test_append_output # test_>>
476
+ @cat.output = 'foo'
477
+ assert_equal('foo', @cat.output)
478
+ cmd = @cat >> 'bar'
479
+ assert_equal('bar', cmd.output)
480
+ assert_not_equal(cmd.object_id, @cat.object_id)
481
+ cmd = @cat >> @file
482
+ assert_equal(@file, cmd.output)
483
+ assert_equal(:a, cmd.open_mode)
484
+ cmd = @cat >> [ 'outbar', 'errbar' ]
485
+ assert_equal('outbar', cmd.output)
486
+ assert_equal('errbar', cmd.error)
487
+ cmd = @cat >> [ @file, @file ]
488
+ assert_equal(:a, cmd.open_mode)
489
+ end
490
+
491
+ def test_args
492
+ assert_equal([], @cp.args)
493
+ @cat << 'foo bar' << 'baz'
494
+ assert_equal(['foo bar', 'baz'], @cat.args)
495
+ end
496
+
497
+ def test_arg_string
498
+ assert_equal('', @cp.arg_string)
499
+ @cat << 'foo bar' << 'baz' << 'b"o' << '\o/' << '>' << 'b3o'
500
+ assert_equal('"foo bar" baz "b\\"o" "\\\\o/" ">" b3o', @cat.arg_string)
501
+ end
502
+
503
+ def test_to_s
504
+ assert_equal('cp', @cp.to_s)
505
+ @cat << 'foo bar' << 'baz'
506
+ assert_equal('cat "foo bar" baz', @cat.to_s)
507
+ end
508
+
509
+ def test_to_sh
510
+ assert_equal('cp > ya', (@cp > 'ya').to_sh)
511
+ @cat << 'foo > bar' << '< baz'
512
+ assert_equal(
513
+ '(cat "foo > bar" "< baz" < yay) | (cp > yoy)',
514
+ ((@cat | @cp) < 'yay' > 'yoy').to_sh)
515
+ @wc.error = 'foo'
516
+ assert_equal('wc 2> foo', @wc.to_sh)
517
+ end
518
+
519
+ def test_complex
520
+ ls = 'ls'.to_ocmd
521
+ wc = 'wc'.to_ocmd
522
+ (ls | wc) < @file > @tmp
523
+ end
524
+
525
+ def test_where
526
+ # FIXME
527
+ end
528
+
529
+ end # class CommandTest
530
+
531
+ end
532
+
533
+ end # module Commands
534
+
535
+ end # module ObjectiveCommand
@@ -0,0 +1,69 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2005, 2006 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id: /w/fey/cmd/trunk/lib/objective_command/commands/factory.rb 22684 2006-03-12T16:36:11.301558Z pouillar $
5
+
6
+ module ObjectiveCommand
7
+
8
+ module Commands
9
+
10
+ class Factory < Command
11
+
12
+ def initialize
13
+ super(nil)
14
+ @command_class = Command
15
+ end
16
+
17
+ def new_command ( *a, &b )
18
+ cmd = @command_class.new(*a, &b)
19
+ instance_variables.each do |var|
20
+ next if var =~ /^@command(_class)?$/
21
+ cmd.send(var[1..-1] + '=', instance_variable_get(var))
22
+ end
23
+ cmd
24
+ end
25
+
26
+ alias :create :new_command
27
+
28
+ end # class Factory
29
+
30
+
31
+
32
+ test_section __FILE__ do
33
+
34
+ class FactoryTest < Test::Unit::TestCase
35
+
36
+ def setup
37
+ assert_nothing_raised { @fa = Factory.new }
38
+ end
39
+
40
+ def test_0_initialize
41
+ end
42
+
43
+ def test_new_command
44
+ assert_nothing_raised do
45
+ assert_kind_of(Command, @fa.create('wc'))
46
+ assert_kind_of(Command, @fa.new_command('ls'))
47
+ end
48
+ end
49
+
50
+ def test_simple
51
+ assert_nothing_raised do
52
+ @fa << 42
53
+ @fa.input = 'inp'
54
+ @fa = @fa > 'out'
55
+ @cmd = @fa.create('foo')
56
+ end
57
+ assert_equal('foo', @cmd.command)
58
+ assert_equal(42, @cmd.args.first)
59
+ assert_equal('inp', @cmd.input)
60
+ assert_equal('out', @cmd.output)
61
+ end
62
+
63
+ end # class FactoryTest
64
+
65
+ end
66
+
67
+ end # module Commands
68
+
69
+ end # module ObjectiveCommand
@@ -0,0 +1,121 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2005, 2006 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id: /w/fey/cmd/trunk/lib/objective_command/commands/pipe.rb 22779 2006-03-19T18:30:55.288309Z ertai $
5
+
6
+ class IO
7
+
8
+ def pipe?
9
+ false
10
+ end
11
+
12
+ class << self
13
+
14
+ alias_method :pipe_without_pipe?, :pipe unless method_defined? :pipe_without_pipe?
15
+
16
+ def pipe
17
+ ios = pipe_without_pipe?
18
+ ios.each do |io|
19
+ io.send(:define_singleton_method, :pipe?) { true }
20
+ end
21
+ ios
22
+ end
23
+
24
+ end # class << self
25
+
26
+ end # class IO
27
+
28
+ module ObjectiveCommand
29
+
30
+ module Commands
31
+
32
+ class Pipe < Command
33
+
34
+ def initialize ( *cmds )
35
+ @cmds = cmds.flatten.map { |x| x.dup }
36
+ end
37
+
38
+ def run ( runner=@runner, *a )
39
+ if runner.nil?
40
+ raise ArgumentError, "need a runner not: #{runner.inspect}"
41
+ end
42
+ datas = Datas::Composite.new
43
+ runner = runner.dup
44
+ runner.hook_trigger :display_command, self
45
+ runner.disable_hook :display_command
46
+ runner.disable_hook :waitpid
47
+ ([nil] + @cmds).zip(@cmds + [nil]).each do |cmd1, cmd2|
48
+ next if cmd1.nil? or cmd2.nil?
49
+ rd, wr = IO.pipe
50
+ cmd1_runner = runner.dup
51
+ cmd1_runner.disable_hook :waitpid
52
+ cmd1_runner.subscribe_hook(:son) { rd.close }
53
+ cmd1.output = wr
54
+ cmd2.input = rd
55
+ datas << cmd1.run(cmd1_runner)
56
+ wr.close
57
+ end
58
+ runner = runner.dup
59
+ datas << @cmds.last.run(runner, *a)
60
+ datas.waitpid if runner.is_a? Runners::System
61
+ datas
62
+ end
63
+
64
+ def input= ( arg )
65
+ @cmds.first.input = arg
66
+ end
67
+
68
+ def input
69
+ @cmds.first.input
70
+ end
71
+
72
+ def output= ( arg )
73
+ @cmds.last.output = arg
74
+ end
75
+
76
+ def output
77
+ @cmds.last.output
78
+ end
79
+
80
+ def error= ( arg )
81
+ @cmds.last.error = arg
82
+ end
83
+
84
+ def error
85
+ @cmds.last.error
86
+ end
87
+
88
+ %w[ args command ].each do |meth|
89
+ class_eval %Q{
90
+ def #{meth} ( *a, &b )
91
+ raise ArgumentError, "no method `#{meth}' on a pipe"
92
+ end
93
+ }
94
+ end
95
+
96
+ def [] ( *args )
97
+ new_cmds = @cmds.dup
98
+ new_cmds[-1] = new_cmds.last[*args]
99
+ Pipe.new(*new_cmds)
100
+ end
101
+
102
+ #
103
+ # Conversion methods
104
+ #
105
+
106
+ def to_sh
107
+ strs = @cmds.map { |cmd| "(#{cmd.to_sh})" }
108
+ "#{strs.join(' | ')}"
109
+ end
110
+
111
+ def to_s
112
+ to_sh
113
+ end
114
+
115
+
116
+
117
+ end # class Pipe
118
+
119
+ end # module Commands
120
+
121
+ end # module ObjectiveCommand