README.md in backticks-0.1.1 vs README.md in backticks-0.3.0
- old
+ new
@@ -1,12 +1,31 @@
# Backticks
Backticks is an intuitive OOP wrapper for invoking command-line processes and
-interacting with them. It uses PTYs
+interacting with them. It improves on Ruby's built-in invocation methods in a
+few ways:
+ - Uses [pseudoterminals](https://en.wikipedia.org/wiki/Pseudoterminal) for unbuffered I/O
+ - Captures input as well as output
+ - Intuitive API that accepts CLI parameters as Ruby positional and keyword args
-By default, processes that you invoke
+If you want to write a record/playback application for the terminal, or write
+functional tests that verify your program's output in real time, Backticks is
+exactly what you've been looking for!
+For an example of the intuitive API, let's consider how we list a bunch of
+files or search for some text with Backticks:
+
+```ruby
+# invokes "ls -l -R"
+Backticks.run 'ls', l:true, R:true
+
+# invokes "grep -H --context=2 --regexp=needle haystack.txt"
+Backticks.run 'grep', {H:true, context:2, regexp:'needle'}, 'haystack.txt'
+```
+
+Notice how running commands feels like a plain old Ruby method call.
+
## Installation
Add this line to your application's Gemfile:
```ruby
@@ -24,43 +43,75 @@
## Usage
```ruby
require 'backticks'
-# The lazy way; provides no CLI sugar, but benefits from unbuffered output.
-# Many Unix utilities produce colorized output when stdout is a TTY; be
-# prepared to handle escape codes in the output.
+# The lazy way; provides no CLI sugar, but benefits from unbuffered output,
+# and allows you to override Ruby's built-in backticks method.
shell = Object.new ; shell.extend(Backticks::Ext)
shell.instance_eval do
puts `ls -l`
raise 'Oh no!' unless $?.success?
end
+# The just-as-lazy but less-magical way.
+Backticks.system('ls -l') || raise('Oh no!')
-# The easy way.
-output = Backticks.command('ls', R:true, '*.rb')
+# The easy way. Uses default options; returns the command's output as a String.
+output = Backticks.run('ls', R:true, '*.rb')
puts "Exit status #{$?.to_i}. Output:"
puts output
-# The hard way; allows customization such as interactive mode, which proxies
-# the child process's stdin, stdout and stderr to the parent process.
+# The hard way. Allows customized behavior; returns a Command object that
+# allows you to interact with the running command.
command = Backticks::Runner.new(interactive:true).command('ls', R:true, '*.rb')
command.join
puts "Exit status: #{command.status.to_i}. Output:"
puts command.captured_output
```
### Buffering
-By default, Backticks allocates a pseudo-TTY for stdout and two Unix pipes for
-stderr/stdin; this captures stdout in real-time, but stderr and
-stdin are subject to unavoidable Unix pipe buffering.
+By default, Backticks allocates a pseudo-TTY for stdin/stdout and a Unix pipe
+for stderr; this captures the program's output and the user's input in realtime,
+but stderr is buffered according to the whim of the kernel's pipe subsystem.
-To use pipes for all io streams, enable buffering when you construct your
-Runner:
+To use pipes for all I/O streams, enable buffering on the Runner:
```ruby
-Backticks::Runner.new(buffered:true)
+# at initialize-time
+r = Backticks::Runner.new(buffered:true)
+
+# or later on
+r.buffered = false
```
+
+### Interactivity
+
+If you set `interactive:true` on the Runner, the console of the calling (Ruby)
+process is "tied" to the child's I/O streams, allowing the user to interact
+with the child process even as its input and output are captured for later use.
+
+If the child process will use raw input, you need to set the parent's console
+accordingly:
+
+```ruby
+require 'io/console'
+# In IRB, call raw! on same line as command; IRB prompt uses raw I/O
+STDOUT.raw! ; Backticks::Runner.new(interactive:true).command('vi').join
+```
+
+### Literally Overriding Ruby's Backticks
+
+It's a terrible idea, but you can use this gem to change the behavior of
+backticks system-wide by mixing it into Kernel.
+
+```ruby
+require 'backticks'
+include Backticks::Ext
+`echo Ruby lets me shoot myself in the foot`
+```
+
+If you do this, I will hunt you down and scoff at you. You have been warned!
## Development
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.