blue-shell 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,14 @@
1
+ The MIT License (MIT)
2
+ Copyright (c) 2013 Pivotal Labs
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5
+ documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
7
+ persons to whom the Software is furnished to do so, subject to the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
14
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
@@ -0,0 +1,6 @@
1
+ require 'blue-shell/errors'
2
+ require 'blue-shell/matchers'
3
+ require 'blue-shell/matchers/exit_code_matcher'
4
+ require 'blue-shell/matchers/output_matcher'
5
+ require 'blue-shell/runner'
6
+ require 'blue-shell/buffered_reader_expector'
@@ -0,0 +1,73 @@
1
+ module BlueShell
2
+ class BufferedReaderExpector
3
+ attr_reader :output
4
+
5
+ def initialize(out, debug = false)
6
+ @out = out
7
+ @debug = debug
8
+ @unused = ""
9
+ @output = ""
10
+ end
11
+
12
+ def expect(pattern, timeout = 5)
13
+ buffer = ''
14
+
15
+ case pattern
16
+ when String
17
+ pattern = Regexp.new(Regexp.quote(pattern))
18
+ when Regexp
19
+ else
20
+ raise TypeError, "unsupported pattern class: #{pattern.class}"
21
+ end
22
+
23
+ result = nil
24
+ position = 0
25
+ @unused ||= ""
26
+
27
+ while true
28
+ if !@unused.empty?
29
+ c = @unused.slice!(0).chr
30
+ elsif output_ended?(timeout)
31
+ @unused = buffer
32
+ break
33
+ else
34
+ c = @out.getc.chr
35
+ end
36
+
37
+ STDOUT.putc c if @debug
38
+
39
+ # wear your flip flops
40
+ unless (c == "\e") .. (c == "m")
41
+ if c == "\b"
42
+ if position > 0 && buffer[position - 1] && buffer[position - 1].chr != "\n"
43
+ position -= 1
44
+ end
45
+ else
46
+ if buffer.size > position
47
+ buffer[position] = c
48
+ else
49
+ buffer << c
50
+ end
51
+
52
+ position += 1
53
+ end
54
+ end
55
+
56
+ if matches = pattern.match(buffer)
57
+ result = [buffer, *matches.to_a[1..-1]]
58
+ break
59
+ end
60
+ end
61
+
62
+ @output << buffer
63
+
64
+ result
65
+ end
66
+
67
+ private
68
+
69
+ def output_ended?(timeout)
70
+ (@out.is_a?(IO) && !IO.select([@out], nil, nil, timeout)) || @out.eof?
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,12 @@
1
+ module BlueShell
2
+ module Errors
3
+ class InvalidInputError < StandardError; end
4
+
5
+ class NonZeroExitCodeError < StandardError
6
+ attr_reader :exit_code
7
+ def initialize(exit_code)
8
+ @exit_code = exit_code
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module BlueShell
2
+ module Matchers
3
+ def say(expected_output, timeout = 30)
4
+ OutputMatcher.new(expected_output, timeout)
5
+ end
6
+
7
+ def have_exited_with(expected_code)
8
+ ExitCodeMatcher.new(expected_code)
9
+ end
10
+
11
+ alias :exit_with :have_exited_with
12
+ end
13
+ end
@@ -0,0 +1,40 @@
1
+ module BlueShell
2
+ module Matchers
3
+ class ExitCodeMatcher
4
+ def initialize(expected_code)
5
+ @expected_code = expected_code
6
+ end
7
+
8
+ def matches?(runner)
9
+ raise Errors::InvalidInputError unless runner.respond_to?(:exit_code)
10
+
11
+ begin
12
+ Timeout.timeout(5) do
13
+ @actual_code = runner.exit_code
14
+ end
15
+
16
+ @actual_code == @expected_code
17
+ rescue Timeout::Error
18
+ @timed_out = true
19
+ false
20
+ end
21
+ end
22
+
23
+ def failure_message
24
+ if @timed_out
25
+ "expected process to exit with status #@expected_code, but it did not exit within 5 seconds"
26
+ else
27
+ "expected process to exit with status #{@expected_code}, but it exited with status #{@actual_code}"
28
+ end
29
+ end
30
+
31
+ def negative_failure_message
32
+ if @timed_out
33
+ "expected process to exit with status #@expected_code, but it did not exit within 5 seconds"
34
+ else
35
+ "expected process to not exit with status #{@expected_code}, but it did"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,38 @@
1
+ module BlueShell
2
+ module Matchers
3
+ class OutputMatcher
4
+ attr_reader :timeout
5
+
6
+ def initialize(expected_output, timeout = 30)
7
+ @expected_output = expected_output
8
+ @timeout = timeout
9
+ end
10
+
11
+ def matches?(runner)
12
+ raise Errors::InvalidInputError unless runner.respond_to?(:expect)
13
+ @matched = runner.expect(@expected_output, @timeout)
14
+ @full_output = runner.output
15
+ !!@matched
16
+ end
17
+
18
+ def failure_message
19
+ if @expected_output.is_a?(Hash)
20
+ expected_keys = @expected_output.keys.map{|key| "'#{key}'"}.join(', ')
21
+ "expected one of #{expected_keys} to be printed, but it wasn't. full output:\n#@full_output"
22
+ else
23
+ "expected '#{@expected_output}' to be printed, but it wasn't. full output:\n#@full_output"
24
+ end
25
+ end
26
+
27
+ def negative_failure_message
28
+ if @expected_output.is_a?(Hash)
29
+ match = @matched
30
+ else
31
+ match = @expected_output
32
+ end
33
+
34
+ "expected '#{match}' to not be printed, but it was. full output:\n#@full_output"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,98 @@
1
+ require 'pty'
2
+ require 'timeout'
3
+
4
+ module BlueShell
5
+ class Runner
6
+ def initialize(*args)
7
+ @stdout, slave = PTY.open
8
+ system('stty raw', :in => slave)
9
+ read, @stdin = IO.pipe
10
+
11
+ @pid = spawn(*(args.push(:in => read, :out => slave, :err => slave)))
12
+
13
+ @expector = BufferedReaderExpector.new(@stdout, ENV['DEBUG_BACON'])
14
+
15
+ if block_given?
16
+ yield self
17
+ else
18
+ code = exit_code
19
+ raise Errors::NonZeroExitCodeError.new(code) unless code == 0
20
+ end
21
+ end
22
+
23
+ class << self
24
+ alias_method :run, :new
25
+ end
26
+
27
+ def expect(matcher, timeout = 30)
28
+ case matcher
29
+ when Hash
30
+ expect_branches(matcher, timeout)
31
+ else
32
+ @expector.expect(matcher, timeout)
33
+ end
34
+ end
35
+
36
+ def send_keys(text_to_send)
37
+ @stdin.puts(text_to_send)
38
+ end
39
+
40
+ def exit_code
41
+ return @code if @code
42
+
43
+ code = nil
44
+ Timeout.timeout(5) do
45
+ _, code = Process.waitpid2(@pid)
46
+ end
47
+
48
+ @code = numeric_exit_code(code)
49
+ end
50
+
51
+ alias_method :wait_for_exit, :exit_code
52
+
53
+ def exited?
54
+ !running?
55
+ end
56
+
57
+ def success?
58
+ @code.zero?
59
+ end
60
+
61
+ alias_method :successful?, :success?
62
+
63
+ def running?
64
+ !!Process.getpgid(@pid)
65
+ end
66
+
67
+ def output
68
+ @expector.output
69
+ end
70
+
71
+ def debug
72
+ @expector.debug
73
+ end
74
+
75
+ def debug=(x)
76
+ @expector.debug = x
77
+ end
78
+
79
+ private
80
+
81
+ def expect_branches(branches, timeout)
82
+ branch_names = /#{branches.keys.collect { |k| Regexp.quote(k) }.join('|')}/
83
+ expected = @expector.expect(branch_names, timeout)
84
+ return unless expected
85
+
86
+ data = expected.first.match(/(#{branch_names})$/)
87
+ matched = data[1]
88
+ branches[matched].call
89
+ matched
90
+ end
91
+
92
+ def numeric_exit_code(status)
93
+ status.exitstatus
94
+ rescue NoMethodError
95
+ status
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,3 @@
1
+ module BlueShell
2
+ VERSION = "0.0.1".freeze
3
+ end
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $stdout.sync = true
4
+ print "started"
5
+ typed = gets
6
+ print "received #{typed}"
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ print "started"
4
+ sleep 0.5
5
+ print " finished"
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ module BlueShell
4
+ module Matchers
5
+ describe ExitCodeMatcher, :ruby19 => true do
6
+ let(:expected_code) { 0 }
7
+
8
+ subject { ExitCodeMatcher.new(expected_code) }
9
+
10
+ describe "#matches?" do
11
+ context "with something that isn't a runner" do
12
+ it "raises an exception" do
13
+ expect {
14
+ subject.matches?("c'est ne pas une specker runner")
15
+ }.to raise_exception(Errors::InvalidInputError)
16
+ end
17
+ end
18
+
19
+ context "with a valid runner" do
20
+ context "and the command exited with the expected exit code" do
21
+ it "returns true" do
22
+ BlueShell::Runner.run("true") do |runner|
23
+ subject.matches?(runner).should be_true
24
+ end
25
+ end
26
+ end
27
+
28
+ context "and the command exits with a different exit code" do
29
+ it "returns false" do
30
+ BlueShell::Runner.run("false") do |runner|
31
+ subject.matches?(runner).should be_false
32
+ end
33
+ end
34
+ end
35
+
36
+ context "and the command runs for a while" do
37
+ it "waits for it to exit" do
38
+ BlueShell::Runner.run("sleep 0.5") do |runner|
39
+ subject.matches?(runner).should be_true
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ context "failure messages" do
47
+ context "with a command that's exited" do
48
+ it "has a correct failure message" do
49
+ BlueShell::Runner.run("false") do |runner|
50
+ subject.matches?(runner)
51
+ runner.wait_for_exit
52
+ subject.failure_message.should == "expected process to exit with status 0, but it exited with status 1"
53
+ end
54
+ end
55
+
56
+ it "has a correct negative failure message" do
57
+ BlueShell::Runner.run("false") do |runner|
58
+ subject.matches?(runner)
59
+ runner.wait_for_exit
60
+ subject.negative_failure_message.should == "expected process to not exit with status 0, but it did"
61
+ end
62
+ end
63
+ end
64
+
65
+ context "with a command that's still running" do
66
+ it "waits for it to exit" do
67
+ BlueShell::Runner.run("ruby -e 'sleep 1; exit 1'") do |runner|
68
+ subject.matches?(runner)
69
+ subject.failure_message.should == "expected process to exit with status 0, but it exited with status 1"
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ module BlueShell
4
+ module Matchers
5
+ describe OutputMatcher, :ruby19 => true do
6
+ let(:expected_output) { "expected_output" }
7
+ let(:timeout) { 1 }
8
+
9
+ subject { OutputMatcher.new(expected_output, timeout) }
10
+
11
+ describe "#matches?" do
12
+ context "with something that isn't a runner" do
13
+ it "raises an exception" do
14
+ expect {
15
+ subject.matches?("c'est ne pas une specker runner")
16
+ }.to raise_exception(Errors::InvalidInputError)
17
+ end
18
+ end
19
+
20
+ context "with a valid runner" do
21
+ context "when the expected output is in the process output" do
22
+ it "finds the expected output" do
23
+ BlueShell::Runner.run("echo -n expected_output") do |runner|
24
+ subject.matches?(runner).should be_true
25
+ end
26
+ end
27
+ end
28
+
29
+ context "when the expected output is not in the process output" do
30
+ let(:runner) { Runner.new('echo -n not_what_we_were_expecting') }
31
+
32
+ it "does not find the expected output" do
33
+ BlueShell::Runner.run("echo -n not_what_we_were_expecting") do |runner|
34
+ subject.matches?(runner).should be_false
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ context "failure messages" do
42
+ it "has a correct failure message" do
43
+ BlueShell::Runner.run("echo -n actual_output") do |runner|
44
+ subject.matches?(runner)
45
+ subject.failure_message.should == "expected 'expected_output' to be printed, but it wasn't. full output:\nactual_output"
46
+ end
47
+ end
48
+
49
+ it "has a correct negative failure message" do
50
+ BlueShell::Runner.run("echo -n actual_output") do |runner|
51
+ subject.matches?(runner)
52
+ subject.negative_failure_message.should == "expected 'expected_output' to not be printed, but it was. full output:\nactual_output"
53
+ end
54
+ end
55
+
56
+ context "when expecting branching output" do
57
+ let(:expected_output) { {
58
+ "expected_output" => proc {},
59
+ "other_expected_output" => proc {}
60
+ } }
61
+
62
+ it "has a correct failure message" do
63
+ BlueShell::Runner.run("echo -n actual_output") do |runner|
64
+ subject.matches?(runner)
65
+ subject.failure_message.should == "expected one of 'expected_output', 'other_expected_output' to be printed, but it wasn't. full output:\nactual_output"
66
+ end
67
+ end
68
+
69
+ it "has a correct negative failure message" do
70
+ BlueShell::Runner.run("echo -n expected_output") do |runner|
71
+ subject.matches?(runner)
72
+ subject.negative_failure_message.should == "expected 'expected_output' to not be printed, but it was. full output:\nexpected_output"
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ module BlueShell
4
+ describe Matchers do
5
+ include Matchers
6
+
7
+ describe "#say" do
8
+ it "returns an ExpectOutputMatcher" do
9
+ say("").should be_a(Matchers::OutputMatcher)
10
+ end
11
+
12
+ context "with an explicit timeout" do
13
+ it "returns an ExpectOutputMatcher" do
14
+ matcher = say("", 30)
15
+ matcher.should be_a(Matchers::OutputMatcher)
16
+ matcher.timeout.should == 30
17
+ end
18
+ end
19
+ end
20
+
21
+ describe "#have_exited_with" do
22
+ it "returns an ExitCodeMatcher" do
23
+ have_exited_with(1).should be_a(Matchers::ExitCodeMatcher)
24
+ end
25
+
26
+ it "has synonyms" do
27
+ exit_with(1).should be_a(Matchers::ExitCodeMatcher)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,194 @@
1
+ require 'spec_helper'
2
+ require 'tempfile'
3
+
4
+ module BlueShell
5
+ describe Runner do
6
+ let(:timeout) { 1 }
7
+
8
+ describe "running a command" do
9
+ let(:file) do
10
+ file = Tempfile.new('blue-shell-runner')
11
+ sleep 1 # wait one second to make sure touching the file does something measurable
12
+ file
13
+ end
14
+
15
+ after { file.unlink }
16
+
17
+ context "with an invalid command" do
18
+ it "raises an exception" do
19
+ expect {
20
+ BlueShell::Runner.run("false")
21
+ }.to raise_error(Errors::NonZeroExitCodeError) { |error| error.exit_code.should == 1 }
22
+ end
23
+ end
24
+
25
+ context "with a valid command" do
26
+ it "runs a command" do
27
+ BlueShell::Runner.run("touch -a #{file.path}")
28
+ file.stat.atime.should > file.stat.mtime
29
+ end
30
+ end
31
+ end
32
+
33
+ describe "#success? and #successful?" do
34
+ context "when the command has a non-zero exit code" do
35
+ it "returns false" do
36
+ runner = BlueShell::Runner.run("false") { |runner|
37
+ runner.wait_for_exit
38
+ }
39
+ runner.should_not be_success
40
+ runner.should_not be_successful
41
+ end
42
+ end
43
+
44
+ context "when the command has a zero exit code" do
45
+ it "returns true" do
46
+ runner = BlueShell::Runner.run("true")
47
+ runner.should be_success
48
+ runner.should be_successful
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "#expect" do
54
+ context "when the expected output shows up" do
55
+ it "returns a truthy value" do
56
+ BlueShell::Runner.run("echo -n foo") do |runner|
57
+ expect(runner.expect('foo')).to be_true
58
+ end
59
+ end
60
+ end
61
+
62
+ context "when the expected output never shows up" do
63
+ it "returns nil" do
64
+ BlueShell::Runner.run("echo the spanish inquisition") do |runner|
65
+ expect(runner.expect("something else", 0.5)).to be_nil
66
+ end
67
+ end
68
+ end
69
+
70
+ context "when the output eventually shows up" do
71
+ it "returns a truthy value" do
72
+ BlueShell::Runner.run("ruby #{asset("pause.rb")}") do |runner|
73
+ expect(runner.expect("finished")).to be_true
74
+ end
75
+ end
76
+ end
77
+
78
+ context "backspace" do
79
+ it "respects the backspace character" do
80
+ BlueShell::Runner.run("ruby -e 'puts \"foo a\\bbar\"'") do |runner|
81
+ expect(runner.expect("foo bar")).to be_true
82
+ end
83
+ end
84
+
85
+ it "does not go beyond the beginning of the line" do
86
+ BlueShell::Runner.run("ruby -e 'print \"foo abc\nx\\b\\bd\"'") do |runner|
87
+ expect(runner.expect("foo abc\nd")).to be_true
88
+ end
89
+ end
90
+
91
+ it "does not go beyond the beginning of the string" do
92
+ BlueShell::Runner.run("ruby -e 'print \"f\\b\\bbar\"'") do |runner|
93
+ expect(runner.expect("bar")).to be_true
94
+ end
95
+ end
96
+
97
+ it "leaves backspaced characters in the buffer until they're overwritten" do
98
+ BlueShell::Runner.run("ruby -e 'print \"foo abc\\b\\bd\"'") do |runner|
99
+ expect(runner.expect("foo adc")).to be_true
100
+ end
101
+ end
102
+ end
103
+
104
+ context "ansi escape sequences" do
105
+ it "filters ansi color sequences" do
106
+ BlueShell::Runner.run("ruby -e 'puts \"\\e[36mblue\\e[0m thing\"'") do |runner|
107
+ expect(runner.expect("blue thing")).to be_true
108
+ end
109
+ end
110
+ end
111
+
112
+ context "expecting multiple branches" do
113
+ context "and one of them matches" do
114
+ it "can be passed a hash of values with callbacks, and returns the matched key" do
115
+ BlueShell::Runner.run("echo 1 3") do |runner|
116
+ branches = {
117
+ "1" => proc { 1 },
118
+ "2" => proc { 2 },
119
+ "3" => proc { 3 }
120
+ }
121
+
122
+ expect(runner.expect(branches)).to eq "1"
123
+ expect(runner.expect(branches)).to eq "3"
124
+ end
125
+ end
126
+
127
+ it "calls the matched callback" do
128
+ callback = mock!
129
+ BlueShell::Runner.run("echo 1 3") do |runner|
130
+ branches = {
131
+ "1" => proc { callback }
132
+ }
133
+ runner.expect(branches)
134
+ end
135
+ end
136
+ end
137
+
138
+ context "and none of them match" do
139
+ it "returns nil when none of the branches match" do
140
+ BlueShell::Runner.run("echo not_a_number") do |runner|
141
+ expect(runner.expect({"1" => proc { 1 }}, timeout)).to be_nil
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ describe "#output" do
149
+ it "makes the entire command output (so far) available" do
150
+ BlueShell::Runner.run("echo 0 1 2 3") do |runner|
151
+ runner.expect("1")
152
+ runner.expect("3")
153
+ expect(runner.output).to eq "0 1 2 3"
154
+ end
155
+
156
+ end
157
+ end
158
+
159
+ describe "#send_keys" do
160
+ it "sends input and expects more output afterward" do
161
+ BlueShell::Runner.run("ruby #{asset("input.rb")}") do |runner|
162
+ expect(runner.expect("started")).to be_true
163
+ runner.send_keys("foo")
164
+ expect(runner.expect("foo")).to be_true
165
+ end
166
+ end
167
+ end
168
+
169
+ context "#exit_code" do
170
+ it "returns the exit code" do
171
+ BlueShell::Runner.run("ruby -e 'exit 42'") do |runner|
172
+ runner.wait_for_exit
173
+ expect(runner.exit_code).to eq(42)
174
+ end
175
+ end
176
+
177
+ context "when the command is still running" do
178
+ it "waits for the command to exit" do
179
+ BlueShell::Runner.run("sleep 0.5") do |runner|
180
+ expect(runner.exit_code).to eq(0)
181
+ end
182
+ end
183
+ end
184
+ end
185
+
186
+ context "#exited?" do
187
+ it "returns false if the command is still running" do
188
+ BlueShell::Runner.run("sleep 10") do |runner|
189
+ expect(runner.exited?).to eq false
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,13 @@
1
+ require 'blue-shell'
2
+ require 'rr'
3
+
4
+ Dir[File.expand_path('../support/**/*.rb', __FILE__)].each do |file|
5
+ require file
6
+ end
7
+
8
+ RSpec.configure do |config|
9
+ config.mock_with :rr
10
+
11
+ config.include BlueShell::Helpers
12
+ end
13
+
@@ -0,0 +1,7 @@
1
+ module BlueShell
2
+ module Helpers
3
+ def asset(file)
4
+ File.expand_path("../../assets/#{file}", __FILE__)
5
+ end
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: blue-shell
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Pivotal Labs
9
+ - Cloud Foundry
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-04-09 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: rake
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rr
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ description:
64
+ email:
65
+ - cfpi-frontend@googlegroups.com
66
+ executables: []
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - LICENSE
71
+ - Rakefile
72
+ - lib/blue-shell/buffered_reader_expector.rb
73
+ - lib/blue-shell/errors.rb
74
+ - lib/blue-shell/matchers/exit_code_matcher.rb
75
+ - lib/blue-shell/matchers/output_matcher.rb
76
+ - lib/blue-shell/matchers.rb
77
+ - lib/blue-shell/runner.rb
78
+ - lib/blue-shell/version.rb
79
+ - lib/blue-shell.rb
80
+ - spec/assets/input.rb
81
+ - spec/assets/pause.rb
82
+ - spec/matchers/exit_code_matcher_spec.rb
83
+ - spec/matchers/output_matcher_spec.rb
84
+ - spec/matchers_spec.rb
85
+ - spec/runner_spec.rb
86
+ - spec/spec_helper.rb
87
+ - spec/support/helpers.rb
88
+ homepage: http://github.com/pivotal/blue-shell
89
+ licenses:
90
+ - MIT
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 1.8.24
110
+ signing_key:
111
+ specification_version: 3
112
+ summary: Friendly command-line test runner and matchers for shell scripting in ruby
113
+ using rspec.
114
+ test_files:
115
+ - spec/assets/input.rb
116
+ - spec/assets/pause.rb
117
+ - spec/matchers/exit_code_matcher_spec.rb
118
+ - spec/matchers/output_matcher_spec.rb
119
+ - spec/matchers_spec.rb
120
+ - spec/runner_spec.rb
121
+ - spec/spec_helper.rb
122
+ - spec/support/helpers.rb