objective_command 0.1.5.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.
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