pvc 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,2 +1,6 @@
1
1
  .DS_Store
2
2
  *.sw*
3
+ pkg/*
4
+ *.gem
5
+ TODO.md
6
+
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile.lock CHANGED
@@ -2,11 +2,15 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  pvc (0.0.1)
5
+ childprocess
5
6
 
6
7
  GEM
7
8
  remote: http://rubygems.org/
8
9
  specs:
10
+ childprocess (0.3.6)
11
+ ffi (~> 1.0, >= 1.0.6)
9
12
  diff-lcs (1.1.3)
13
+ ffi (1.3.1)
10
14
  rspec (2.12.0)
11
15
  rspec-core (~> 2.12.0)
12
16
  rspec-expectations (~> 2.12.0)
data/README.md CHANGED
@@ -7,9 +7,6 @@ Pipe between processes as easily as in the shell
7
7
  # run the specs
8
8
  bundle exec rspec spec
9
9
 
10
- # run the simulation interactively (see description below)
11
- ./bin/gorobo
12
-
13
10
  ## Install it as a RubyGem
14
11
 
15
12
  This code is packaged as a Gem. If you like, you can build and install it by running:
@@ -17,8 +14,41 @@ This code is packaged as a Gem. If you like, you can build and install it by run
17
14
  gem build pvc.gemspec
18
15
  gem install pvc-*.gem
19
16
 
20
- ## Description
17
+ ## Synopsis - implemented
18
+
19
+ # Run a single process
20
+ PVC.new("echo hello").run
21
+
22
+ # Or pipe from one process to another
23
+ PVC.new("echo hello").to("tr h H").run
24
+
25
+ # Get individual or several outputs from the final result
26
+ PVC.new("echo hello && ls doesnotexist").run.stdout # => "hello\n"
27
+ PVC.new("echo hello && ls doesnotexist").run.stderr # => "ls: doesnotexist: No such file or directory\n"
28
+ PVC.new("echo hello && ls doesnotexist").run.stdboth # => "hello\nls: doesnotexist: No such file or directory\n"
29
+ PVC.new("echo hello && ls doesnotexist").run.code # => 1
30
+ stderr, code = PVC.new("echo hello && ls doesnotexist").run.get(:stderr, :code) # => ["ls: doesnotexist: No such file or directory\n", 1]
31
+
32
+ # Input a string into stdin
33
+ PVC.new.input("one\ntwo\nthree\n").to("sort -r").run.stdout # => "two\nthree\none\n"
34
+
35
+ # Process intermediate results with Ruby
36
+ PVC.new("cat some.log").to { |i,o| i.each_line { |line| o.puts line if line.match(/ERROR/) } }.to("tail -n10").run
37
+
38
+ # Mix stderr and stdin at some point in a pipeline
39
+ PVC.new("echo hello && ls doesnotexist").with_err.to("wc -l").run.stdout # => " 2\n"
40
+
41
+ # Pass on only stderr at some point in a pipeline
42
+ PVC.new("echo hello && ls doesnotexist").only_err.to("wc -l").run.stdout # => " 1\n"
43
+
44
+ # Insert one pipeline into another
45
+ upcase_unique_pipeline = PVC.new("tr a-z A-Z").to("uniq")
46
+ PVC.new.input("hello\nHeLlO\nworld\nWoRlD\n").to(upcase_unique_pipeline).to("sort -r").run.stdout # => "WORLD\nHELLO"
47
+
48
+ ## Synopsis - unimplemented
21
49
 
50
+ # Kill run if it does not finish in time (miliseconds)
51
+ PVC.new("sleep 2").run(:timeout => 1000)
22
52
 
23
53
  ## Compatibility
24
54
 
@@ -0,0 +1,43 @@
1
+ module PVC
2
+ class BlockPiece
3
+
4
+ class Runner
5
+
6
+ def initialize(&block)
7
+ @block = block
8
+ @read, @write = IO.pipe
9
+ @read.close_on_exec = true
10
+ @write.close_on_exec = true
11
+ end
12
+
13
+ def stdin
14
+ @write
15
+ end
16
+
17
+ def start(following_piece)
18
+ @return = nil
19
+ @thread = Thread.new do
20
+ @return = @block.call(@read, following_piece.stdin)
21
+ end
22
+ end
23
+
24
+ def finish
25
+ @write.close
26
+ @thread.join
27
+ @read.close
28
+ end
29
+
30
+ attr_reader :return
31
+ end
32
+
33
+ def initialize(&block)
34
+ @block = block
35
+ end
36
+
37
+ def runner
38
+ Runner.new(&@block)
39
+ end
40
+
41
+ end
42
+ end
43
+
@@ -0,0 +1,37 @@
1
+ module PVC
2
+ class InputPiece
3
+
4
+ class Runner
5
+ def initialize(input)
6
+ @input = input
7
+ @read, @write = IO.pipe
8
+ @read.close_on_exec = true
9
+ @write.close_on_exec = true
10
+ end
11
+
12
+ def stdin
13
+ @write
14
+ end
15
+
16
+ def start(following_piece)
17
+ following_piece.stdin.write(@input)
18
+ following_piece.stdin.flush
19
+ end
20
+
21
+ def finish
22
+ @write.close
23
+ @read.close
24
+ end
25
+ end
26
+
27
+ def initialize(input)
28
+ @input = input
29
+ end
30
+
31
+ def runner
32
+ Runner.new(@input)
33
+ end
34
+
35
+ end
36
+ end
37
+
@@ -0,0 +1,32 @@
1
+ module PVC
2
+ class NullPiece
3
+
4
+ class Runner
5
+ def initialize
6
+ @read, @write = IO.pipe
7
+ @read.close_on_exec = true
8
+ @write.close_on_exec = true
9
+ end
10
+
11
+ def stdin
12
+ @write
13
+ end
14
+
15
+ def start(following=nil)
16
+ # do nothing
17
+ end
18
+
19
+ def finish
20
+ @write.close
21
+ @read.close
22
+ end
23
+
24
+ end
25
+
26
+ def runner
27
+ Runner.new
28
+ end
29
+
30
+ end
31
+ end
32
+
@@ -0,0 +1,44 @@
1
+ module PVC
2
+ class OnlyErrPiece
3
+
4
+ class Runner
5
+ def initialize
6
+ @stdread, @stdwrite = IO.pipe
7
+ @errread, @errwrite = IO.pipe
8
+ @stdread.close_on_exec = true
9
+ @stdwrite.close_on_exec = true
10
+ @errread.close_on_exec = true
11
+ @errwrite.close_on_exec = true
12
+ end
13
+
14
+ def stdin
15
+ @stdwrite
16
+ end
17
+
18
+ def errin
19
+ @errwrite
20
+ end
21
+
22
+ def start(following_piece)
23
+ @errthread = Thread.new do
24
+ @errread.each_line { |line| following_piece.stdin.puts line }
25
+ end
26
+ end
27
+
28
+ def finish
29
+ @stdwrite.close
30
+ @errwrite.close
31
+ @errthread.join
32
+ @stdread.close
33
+ @errread.close
34
+ end
35
+
36
+ end
37
+
38
+ def runner
39
+ Runner.new
40
+ end
41
+
42
+ end
43
+ end
44
+
@@ -0,0 +1,74 @@
1
+ require "childprocess"
2
+
3
+ require "pvc/block_piece"
4
+ require "pvc/null_piece"
5
+ require "pvc/process_piece"
6
+ require "pvc/with_err_piece"
7
+ require "pvc/only_err_piece"
8
+ require "pvc/result_piece"
9
+ require "pvc/input_piece"
10
+ require "pvc/result"
11
+
12
+ module PVC
13
+ class Pipeline
14
+
15
+ def initialize(*args, &block)
16
+ @pieces = []
17
+ if args.length > 0 || block_given?
18
+ self.to(*args, &block)
19
+ end
20
+ end
21
+
22
+ def to(*args, &block)
23
+ if block_given?
24
+ @pieces << BlockPiece.new(&block)
25
+ elsif args.length == 1 && args.first.respond_to?(:pieces)
26
+ args.first.pieces.each { |piece| @pieces << piece }
27
+ else
28
+ @pieces << ProcessPiece.new(*args)
29
+ end
30
+ self
31
+ end
32
+
33
+ def input(input)
34
+ @pieces << InputPiece.new(input)
35
+ self
36
+ end
37
+
38
+ def with_err
39
+ @pieces << WithErrPiece.new
40
+ self
41
+ end
42
+
43
+ def only_err
44
+ @pieces << OnlyErrPiece.new
45
+ self
46
+ end
47
+
48
+ def run
49
+ runners = ([NullPiece.new] + @pieces + [ResultPiece.new]).map(&:runner)
50
+
51
+ runners.zip(runners[1..-1]).reverse.each do |current, following|
52
+ current.start(following)
53
+ end
54
+
55
+ runners.each do |current|
56
+ current.finish
57
+ end
58
+
59
+ Result.new(
60
+ :stdout => runners.last.stdout,
61
+ :stderr => runners.last.stderr,
62
+ :stdboth => runners.last.stdboth,
63
+ :codes => runners.inject([]) { |codes, runner| codes << runner.code if runner.respond_to?(:code); codes },
64
+ :returns => runners.inject([]) { |returns, runner| returns << runner.return if runner.respond_to?(:return); returns }
65
+ )
66
+ end
67
+
68
+ protected
69
+
70
+ attr_reader :pieces
71
+
72
+ end
73
+ end
74
+
@@ -0,0 +1,41 @@
1
+ module PVC
2
+ class ProcessPiece
3
+
4
+ class Runner
5
+ def initialize(*args)
6
+ @args = args
7
+ @process = ChildProcess.build(*args)
8
+ end
9
+
10
+ def stdin
11
+ @process.io.stdin
12
+ end
13
+
14
+ def start(following_piece)
15
+ @process.duplex = true
16
+ @process.io.stdout = following_piece.stdin
17
+ @process.io.stderr = following_piece.errin if following_piece.respond_to?(:errin)
18
+ @process.start
19
+ end
20
+
21
+ def finish
22
+ @process.io.stdin.close
23
+ @process.wait
24
+ end
25
+
26
+ def code
27
+ @process.exit_code
28
+ end
29
+ end
30
+
31
+ def initialize(args)
32
+ @args = args
33
+ end
34
+
35
+ def runner
36
+ Runner.new(@args)
37
+ end
38
+
39
+ end
40
+ end
41
+
data/lib/pvc/result.rb ADDED
@@ -0,0 +1,32 @@
1
+ module PVC
2
+ class Result
3
+
4
+ attr_reader :stdout
5
+ attr_reader :stderr
6
+ attr_reader :stdboth
7
+
8
+ def initialize(args)
9
+ @stdout = args[:stdout]
10
+ @stderr = args[:stderr]
11
+ @stdboth = args[:stdboth]
12
+ @returns = args[:returns]
13
+ @codes = args[:codes]
14
+ end
15
+
16
+ def return
17
+ @returns.last
18
+ end
19
+
20
+ def code
21
+ @codes.last
22
+ end
23
+
24
+ def get(*requested_outputs)
25
+ allowed_outputs = [:stdout, :stderr, :stdboth, :return, :code]
26
+ raise "No such output to get!" unless (requested_outputs-allowed_outputs)==[]
27
+ requested_outputs.map { |output_kind| self.send(output_kind) }
28
+ end
29
+
30
+ end
31
+ end
32
+
@@ -0,0 +1,69 @@
1
+ module PVC
2
+ class ResultPiece
3
+
4
+ class Runner
5
+ def initialize
6
+ @stdread, @stdwrite = IO.pipe
7
+ @errread, @errwrite = IO.pipe
8
+ @stdread.close_on_exec = true
9
+ @stdwrite.close_on_exec = true
10
+ @errread.close_on_exec = true
11
+ @errwrite.close_on_exec = true
12
+ @stdout = []
13
+ @stderr = []
14
+ @stdboth = []
15
+ end
16
+
17
+ def stdin
18
+ @stdwrite
19
+ end
20
+
21
+ def errin
22
+ @errwrite
23
+ end
24
+
25
+ def start(following=nil)
26
+ @stdthread = Thread.new do
27
+ @stdread.each_line do |line|
28
+ @stdout << line
29
+ @stdboth << line
30
+ end
31
+ end
32
+ @errthread = Thread.new do
33
+ @errread.each_line do |line|
34
+ @stderr << line
35
+ @stdboth << line
36
+ end
37
+ end
38
+ end
39
+
40
+ def finish
41
+ @stdwrite.close
42
+ @errwrite.close
43
+ @stdthread.join
44
+ @errthread.join
45
+ @stdread.close
46
+ @errread.close
47
+ end
48
+
49
+ def stdout
50
+ @stdout.join("")
51
+ end
52
+
53
+ def stderr
54
+ @stderr.join("")
55
+ end
56
+
57
+ def stdboth
58
+ @stdboth.join("")
59
+ end
60
+
61
+ end
62
+
63
+ def runner
64
+ Runner.new
65
+ end
66
+
67
+ end
68
+ end
69
+
data/lib/pvc/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module PVC
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,48 @@
1
+ module PVC
2
+ class WithErrPiece
3
+
4
+ class Runner
5
+ def initialize
6
+ @stdread, @stdwrite = IO.pipe
7
+ @errread, @errwrite = IO.pipe
8
+ @stdread.close_on_exec = true
9
+ @stdwrite.close_on_exec = true
10
+ @errread.close_on_exec = true
11
+ @errwrite.close_on_exec = true
12
+ end
13
+
14
+ def stdin
15
+ @stdwrite
16
+ end
17
+
18
+ def errin
19
+ @errwrite
20
+ end
21
+
22
+ def start(following_piece)
23
+ @stdthread = Thread.new do
24
+ @stdread.each_line { |line| following_piece.stdin.puts line }
25
+ end
26
+ @errthread = Thread.new do
27
+ @errread.each_line { |line| following_piece.stdin.puts line }
28
+ end
29
+ end
30
+
31
+ def finish
32
+ @stdwrite.close
33
+ @errwrite.close
34
+ @stdthread.join
35
+ @errthread.join
36
+ @stdread.close
37
+ @errread.close
38
+ end
39
+
40
+ end
41
+
42
+ def runner
43
+ Runner.new
44
+ end
45
+
46
+ end
47
+ end
48
+
data/lib/pvc.rb CHANGED
@@ -0,0 +1,12 @@
1
+ require "childprocess"
2
+
3
+ require "pvc/pipeline"
4
+
5
+ module PVC
6
+
7
+ def self.new(*args, &block)
8
+ Pipeline.new(*args, &block)
9
+ end
10
+
11
+ end
12
+
data/pvc.gemspec CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.version = PVC::VERSION
8
8
  s.authors = ["Chris Berkhout"]
9
9
  s.email = ["chrisberkhout@gmail.com"]
10
- s.homepage = "http://chrisberkhout.com"
10
+ s.homepage = "http://github.com/chrisberkhout/pvc"
11
11
  s.summary = %q{Easy piping between processes}
12
12
 
13
13
  s.rubyforge_project = "pvc"
@@ -17,7 +17,8 @@ Gem::Specification.new do |s|
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
  s.require_paths = ["lib"]
19
19
 
20
- # specify any dependencies here; for example:
20
+ s.add_runtime_dependency "childprocess"
21
+
21
22
  s.add_development_dependency "rspec"
22
23
 
23
24
  s.required_ruby_version = '>= 1.9.0'
@@ -0,0 +1,109 @@
1
+ require "pvc"
2
+
3
+ describe "pvc" do
4
+
5
+ describe "(synopsis tests)" do
6
+
7
+ it "should run a single process" do
8
+ PVC.new("echo hello").run.stdout.should == "hello\n"
9
+ end
10
+
11
+ it "should pipe from one process to another" do
12
+ PVC.new("echo hello").to("tr h H").run.stdout.should == "Hello\n"
13
+ end
14
+
15
+ it "should let you get stdout" do
16
+ PVC.new("echo hello && ls doesnotexist").run.stdout.should == "hello\n"
17
+ end
18
+
19
+ it "should let you get stderr" do
20
+ PVC.new("echo hello && ls doesnotexist").run.stderr.should == "ls: doesnotexist: No such file or directory\n"
21
+ end
22
+
23
+ it "should let you get stdout and stderr together" do
24
+ PVC.new("echo hello && ls doesnotexist").run.stdboth.should == "hello\nls: doesnotexist: No such file or directory\n"
25
+ end
26
+
27
+ it "should let you get the exit code of the last process" do
28
+ PVC.new("echo hello").run.code.should == 0
29
+ PVC.new("echo hello && ls doesnotexist").run.code.should == 1
30
+ end
31
+
32
+ it "should let you get several outputs from the final result" do
33
+ PVC.new("echo hello && ls doesnotexist").run.get(:stderr, :code).should == ["ls: doesnotexist: No such file or directory\n", 1]
34
+ end
35
+
36
+ it "should let you input into the stdin" do
37
+ PVC.new.input("one\ntwo\nthree\n").to("sort -r").run.stdout.should == "two\nthree\none\n"
38
+ end
39
+
40
+ it "should let you process intermediate results with Ruby" do
41
+ PVC.new.input("one\ntwo\nthree\n").to do |i,o|
42
+ i.each_line { |line| o.puts line if line.match(/^t/) }
43
+ end.to("cat").run.stdout.should == "two\nthree\n"
44
+ end
45
+
46
+ it "should let you mix stderr and stdin at some point in a pipeline" do
47
+ PVC.new("echo hello && ls doesnotexist").with_err.to("wc -l").run.stdout.should == " 2\n"
48
+ end
49
+
50
+ it "should let you pass on only stderr at some point in a pipeline" do
51
+ PVC.new("echo hello && ls doesnotexist").only_err.to("wc -l").run.stdout.should == " 1\n"
52
+ end
53
+
54
+ it "should let you insert one pipeline into another" do
55
+ upcase_unique_pipeline = PVC.new("tr a-z A-Z").to("uniq")
56
+ string = "hello\nHeLlO\nworld\nWoRlD\n"
57
+ PVC.new.input(string).to(upcase_unique_pipeline).to("sort -r").run.stdout.should == "WORLD\nHELLO\n"
58
+ end
59
+
60
+ end
61
+
62
+ describe "(original manual tests)" do
63
+
64
+ let(:log) { [] }
65
+
66
+ it "should work with 2 shell commands and a block" do
67
+ PVC.new.
68
+ to("echo BBB && echo AAA").
69
+ to("sort").
70
+ to do |input, output|
71
+ input.each_line { |line| log << line.chomp }
72
+ end.run
73
+
74
+ log.should == %w{AAA BBB}
75
+ end
76
+
77
+ it "should work with sevearal blocks" do
78
+ PVC.new.
79
+ to("echo BBB && echo AAA").
80
+ to("sort").
81
+ to do |input, output|
82
+ input.each_line { |line| output.write line }
83
+ end.
84
+ to do |input, output|
85
+ input.each_line { |line| log << line.chomp }
86
+ end.run
87
+
88
+ log.should == %w{AAA BBB}
89
+ end
90
+
91
+ it "should work with sevearal blocks separated by a shell command" do
92
+ PVC.new.
93
+ to("echo BBB && echo AAA").
94
+ to("sort").
95
+ to do |input, output|
96
+ input.each_line { |line| output.write line }
97
+ end.
98
+ to("cat").
99
+ to do |input, output|
100
+ input.each_line { |line| log << line.chomp }
101
+ end.run
102
+
103
+ log.should == %w{AAA BBB}
104
+ end
105
+
106
+ end
107
+
108
+ end
109
+
@@ -0,0 +1,64 @@
1
+ require "childprocess"
2
+
3
+ describe "pipe io" do
4
+
5
+ def fork_childprocess
6
+ ChildProcess.unix?.should == true && ChildProcess.posix_spawn?.should == false # to ensure this does fork+exec
7
+ process = ChildProcess.build("cat")
8
+ process.duplex = true # to make stdin available on start
9
+ process.start
10
+ yield if block_given?
11
+ process.io.stdin.close
12
+ process.wait
13
+ end
14
+
15
+ # see also the example at: http://rubydoc.info/stdlib/core/1.9.3/IO.pipe
16
+
17
+ it "will not show EOF on close if a fork has an open copy of the file handle" do
18
+ read, write = IO.pipe
19
+ fork_childprocess do
20
+ write.close
21
+ expect { read.read_nonblock(1) }.to raise_error(Errno::EAGAIN) # not yet EOF
22
+ end
23
+ end
24
+
25
+ it "should show EOF on close if the fork has closed its copy of the file handle (by exiting)" do
26
+ read, write = IO.pipe
27
+ fork_childprocess
28
+ write.close
29
+ expect { read.read_nonblock(1) }.to raise_error(EOFError)
30
+ end
31
+
32
+ it "should show EOF on close if the fork has closed its copy of the file handle (by closing on exec)" do
33
+ read, write = IO.pipe
34
+ write.close_on_exec = true
35
+ fork_childprocess do
36
+ write.close
37
+ expect { read.read_nonblock(1) }.to raise_error(EOFError)
38
+ end
39
+ end
40
+
41
+ it "should not close everywhere if closed in a fork" do
42
+ read, write = IO.pipe
43
+ read.close_on_exec = true
44
+ write.close_on_exec = true
45
+ fork_childprocess do
46
+ read.closed?.should be_false
47
+ end
48
+ end
49
+
50
+ it "should get a final unterminated line via #each_line" do
51
+ read, write = IO.pipe
52
+ lines_read = []
53
+ thread = Thread.new do
54
+ read.each_line { |line| lines_read << line }
55
+ end
56
+ write.puts "terminated line"
57
+ write.print "unterminated line"
58
+ write.close
59
+ thread.join
60
+ lines_read.should == ["terminated line\n", "unterminated line"]
61
+ end
62
+
63
+ end
64
+
data/spec/spec_helper.rb CHANGED
@@ -0,0 +1,18 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = 'random'
17
+ end
18
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pvc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-26 00:00:00.000000000 Z
12
+ date: 2013-02-11 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: childprocess
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
14
30
  - !ruby/object:Gem::Dependency
15
31
  name: rspec
16
32
  requirement: !ruby/object:Gem::Requirement
@@ -35,15 +51,27 @@ extensions: []
35
51
  extra_rdoc_files: []
36
52
  files:
37
53
  - .gitignore
54
+ - .rspec
38
55
  - Gemfile
39
56
  - Gemfile.lock
40
57
  - README.md
41
58
  - Rakefile
42
59
  - lib/pvc.rb
60
+ - lib/pvc/block_piece.rb
61
+ - lib/pvc/input_piece.rb
62
+ - lib/pvc/null_piece.rb
63
+ - lib/pvc/only_err_piece.rb
64
+ - lib/pvc/pipeline.rb
65
+ - lib/pvc/process_piece.rb
66
+ - lib/pvc/result.rb
67
+ - lib/pvc/result_piece.rb
43
68
  - lib/pvc/version.rb
69
+ - lib/pvc/with_err_piece.rb
44
70
  - pvc.gemspec
71
+ - spec/pvc/integration_spec.rb
72
+ - spec/ruby/pipe_io_spec.rb
45
73
  - spec/spec_helper.rb
46
- homepage: http://chrisberkhout.com
74
+ homepage: http://github.com/chrisberkhout/pvc
47
75
  licenses: []
48
76
  post_install_message:
49
77
  rdoc_options: []
@@ -68,5 +96,7 @@ signing_key:
68
96
  specification_version: 3
69
97
  summary: Easy piping between processes
70
98
  test_files:
99
+ - spec/pvc/integration_spec.rb
100
+ - spec/ruby/pipe_io_spec.rb
71
101
  - spec/spec_helper.rb
72
102
  has_rdoc: