Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ Command.run("date")

And that's all!

*But* if you need more information about what happened, the return value is a `Command` object with all the goodies that you would expect.
*But* if you need more information about what happened, the return value is a `Command::Result` object with all the goodies that you would expect.

```ruby
command = Command.run("date")
command.stdout # => "Tue Nov 26 14:45:03 EST 2013\n"
command.stderr # => ""
command.status # => 0
command.success? # => true
command.pid # => 32157
result = Command.run("date")
result.stdout # => "Tue Nov 26 14:45:03 EST 2013\n"
result.stderr # => ""
result.status # => 0
result.success? # => true
result.pid # => 32157
```

Now, drawing boundaries in your tests is easy.
Expand All @@ -56,7 +56,7 @@ describe DateGetter do
date = "Tue Nov 26 14:45:03 EST 2013"

expect(Command).to receive(:run).with("date") do
double(:command, success?: true, stdout: "#{date}\n")
double(:result, success?: true, stdout: "#{date}\n")
end

expect(DateGetter.get).to eq(date)
Expand Down
39 changes: 12 additions & 27 deletions lib/command.rb
Original file line number Diff line number Diff line change
@@ -1,32 +1,17 @@
require "open3"

class Command
attr_reader :stdin, :stdout, :stderr

def self.run(stdin)
new(stdin).run
end

def initialize(stdin)
@stdin = stdin
require "command/definition"
require "command/runner"
require "command/result"

module Command

# @param [String] cmd
# @return [Command::Result]
def self.run(cmd)
definition = Command::Definition.new(cmd)
runner = Command::Runner.new
runner.run(definition)
end

def run
@stdout, @stderr, @status = Open3.capture3(stdin)
self
end

def exitstatus
@status && @status.exitstatus
end

alias_method :status, :exitstatus

def success?
@status && @status.success?
end

def pid
@status && @status.pid
end
end
12 changes: 12 additions & 0 deletions lib/command/definition.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module Command
class Definition

attr_reader :cmd

# @param [String] cmd
def initialize(cmd)
@cmd = cmd
end

end
end
36 changes: 36 additions & 0 deletions lib/command/result.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module Command
class Result

# @param [Hash] output
# @option output_streams [String] :stdout
# @option output_streams [String] :stderr
# @param [Process::Status] status
def initialize(output, status)
@output = output
@status = status
end

def stdout
@output[:stdout]
end

def stderr
@output[:stderr]
end

def exitstatus
@status.exitstatus
end

alias_method :status, :exitstatus

def success?
@status.success?
end

def pid
@status.pid
end

end
end
13 changes: 13 additions & 0 deletions lib/command/runner.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module Command
class Runner

# @param [Command::Definition] definition
# @return [Command::Result]
def run(definition)
stdout, stderr, status = Open3.capture3(definition.cmd)
output = {:stdout => stdout, :stderr => stderr}
Command::Result.new(output, status)
end

end
end
14 changes: 14 additions & 0 deletions spec/lib/command/definition_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require "spec_helper"

describe Command::Definition do

describe "#initialize" do
let(:cmd) { "my command" }
let(:definition) { Command::Definition.new(cmd) }

it "sets the cmd" do
expect(definition.cmd).to eq(cmd)
end
end

end
48 changes: 48 additions & 0 deletions spec/lib/command/result_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
require "spec_helper"

describe Command::Result do

describe "#initialize" do
let(:output) { {:stdout => "my stdout", :stderr => "my stderr"} }
let(:status) { double(Process::Status, exitstatus: 12, success?: false, pid: 123) }
let(:result) { Command::Result.new(output, status) }

it "sets the output" do
expect(result.stdout).to eq("my stdout")
expect(result.stderr).to eq("my stderr")
end

it "sets the status" do
expect(result.exitstatus).to be(12)
end
end

describe "#exitstatus" do
let(:status) { double(Process::Status, exitstatus: 12) }
let(:result) { Command::Result.new({}, status) }

it "returns the exit status" do
expect(result.exitstatus).to eq(12)
expect(result.status).to eq(12)
end
end

describe "#success" do
let(:status) { double(Process::Status, success?: false) }
let(:result) { Command::Result.new({}, status) }

it "returns the success" do
expect(result.success?).to eq(false)
end
end

describe "#pid" do
let(:status) { double(Process::Status, pid: 123) }
let(:result) { Command::Result.new({}, status) }

it "returns the success" do
expect(result.pid).to eq(123)
end
end

end
66 changes: 66 additions & 0 deletions spec/lib/command/runner_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
require "spec_helper"

describe Command::Runner do

describe "#run" do

context "when command exits successfully" do
let(:cmd) { "ruby -e 'STDOUT.print \"hello\"; STDERR.print \"world\";'" }
let(:definition) { Command::Definition.new(cmd) }
let(:runner) { Command::Runner.new }
let(:result) { runner.run(definition) }

it "returns a result" do
expect(result).to be_a(Command::Result)
end

it "sets the standard output" do
expect(result.stdout).to eq("hello")
end

it "sets the standard error" do
expect(result.stderr).to eq("world")
end

it "sets the exit status" do
expect(result.exitstatus).to eq(0)
end

it "sets the success" do
expect(result.success?).to eq(true)
end

it "sets the PID" do
expect(result.pid).to be_a(Fixnum)
end
end

context "when command fails" do
let(:cmd) { "ruby -e 'STDOUT.print \"hello\"; STDERR.print \"world\"; exit(1);'" }
let(:definition) { Command::Definition.new(cmd) }
let(:runner) { Command::Runner.new }
let(:result) { runner.run(definition) }

it "returns a result" do
expect(result).to be_a(Command::Result)
end

it "sets the standard output" do
expect(result.stdout).to eq("hello")
end

it "sets the standard error" do
expect(result.stderr).to eq("world")
end

it "sets the exit status" do
expect(result.exitstatus).to eq(1)
end

it "sets the success" do
expect(result.success?).to eq(false)
end
end

end
end
86 changes: 9 additions & 77 deletions spec/lib/command_spec.rb
Original file line number Diff line number Diff line change
@@ -1,88 +1,20 @@
require "spec_helper"

describe Command do

describe ".run" do
let!(:stdin) { double(:stdin) }
let(:command) { double(:command) }
let(:cmd) { double(:cmd) }
let(:runner) { double(Command::Runner) }
let(:definition) { double(Command::Definition) }
let(:result) { double(Command::Result) }

it "initializes, runs and returns a new command" do
expect(Command).to receive(:new).once.with(stdin) { command }
expect(command).to receive(:run).once.with(no_args) { command }

expect(Command.run(stdin)).to eq(command)
end
end

describe "#initialize" do
let!(:stdin) { "man touch" }

it "sets the standard input" do
command = Command.new(stdin)
expect(Command::Runner).to receive(:new).once.with(no_args) { runner }
expect(Command::Definition).to receive(:new).once.with(cmd) { definition }
expect(runner).to receive(:run).once.with(definition) { result }

expect(command.stdin).to eq(stdin)
expect(Command.run(cmd)).to eq(result)
end
end

describe "#run" do
let!(:stdin) { "man touch" }
let!(:command) { Command.new(stdin) }
let(:stdout) { double(:stdout) }
let(:stderr) { double(:stderr) }
let(:status) { double(:status, exitstatus: 1, success?: false, pid: 123) }
let(:result) { [stdout, stderr, status] }

before do
Open3.stub(:capture3) { result }
end

it "runs the given input" do
expect(Open3).to receive(:capture3).once.with(stdin) { result }

command.run
end

it "sets the standard output" do
expect {
command.run
}.to change {
command.stdout
}.from(nil).to(stdout)
end

it "sets the standard error" do
expect {
command.run
}.to change {
command.stdout
}.from(nil).to(stdout)
end

it "sets the exit status" do
expect {
command.run
}.to change {
command.exitstatus
}.from(nil).to(status.exitstatus)
end

it "sets the success" do
expect {
command.run
}.to change {
command.success?
}.from(nil).to(status.success?)
end

it "sets the PID" do
expect {
command.run
}.to change {
command.pid
}.from(nil).to(status.pid)
end

it "returns the command" do
expect(command.run).to eq(command)
end
end
end