PVC
Pipe between processes as easily as in the shell
Check it out
# run the specs
bundle exec rspec spec
Install it as a RubyGem
This code is packaged as a Gem. If you like, you can build and install it by running:
gem build pvc.gemspec
gem install pvc-*.gem
Synopsis - implemented
# Run a single process
PVC.new("echo", "hello").run
# Or pipe from one process to another
PVC.new("echo", "hello").to(*%w{tr h H}).run
# Get individual or several outputs from the final result
PVC.new("bash", "-c", "echo hello && ls doesnotexist").run.stdout # => "hello\n"
PVC.new("bash", "-c", "echo hello && ls doesnotexist").run.stderr # => "ls: doesnotexist: No such file or directory\n"
PVC.new("bash", "-c", "echo hello && ls doesnotexist").run.stdboth # => "hello\nls: doesnotexist: No such file or directory\n"
PVC.new("bash", "-c", "echo hello && ls doesnotexist").run.code # => 1
stderr, code = PVC.new("bash", "-c", "echo hello && ls doesnotexist").run.get(:stderr, :code) # => ["ls: doesnotexist: No such file or directory\n", 1]
# Input a string into stdin
PVC.new.input("one\ntwo\nthree\n").to("sort", "-r").run.stdout # => "two\nthree\none\n"
# Process intermediate results with Ruby
PVC.new("cat", "some.log").to { |i,o| i.each_line { |line| o.puts line if line.match(/ERROR/) } }.to("tail", "-n10").run
# Mix stderr and stdin at some point in a pipeline
PVC.new("bash", "-c", "echo hello && ls doesnotexist").with_err.to("wc", "-l").run.stdout # => " 2\n"
# Pass on only stderr at some point in a pipeline
PVC.new("bash", "-c", "echo hello && ls doesnotexist").only_err.to("wc", "-l").run.stdout # => " 1\n"
# Insert one pipeline into another
upcase_unique_pipeline = PVC.new("tr", "a-z", "A-Z").to("uniq")
PVC.new.input("hello\nHeLlO\nworld\nWoRlD\n").to(upcase_unique_pipeline).to("sort", "-r").run.stdout # => "WORLD\nHELLO"
# Shorthand for linewise rewriting
PVC.new.input("hello\nworld").lines_map { |l| l.upcase }.run.stdout "HELLO\nWORLD"
# Shorthand for linewise processing (without modifying the stream)
count = 0
result = PVC.new.input("hello\nworld").lines_tap { |l| count += 1 }.run
count # => 2
result.stdout # => "hello\nworld"
Synopsis - unimplemented
# Kill run if it does not finish in time (miliseconds)
PVC.new("sleep", "2").run(:timeout => 1000)
Compatibility
Written and tested with Ruby 1.9.3.