stairs 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/.rubocop.yml +38 -0
- data/.travis.yml +4 -0
- data/Guardfile +10 -0
- data/README.md +39 -9
- data/Rakefile +5 -0
- data/lib/stairs/configuration.rb +1 -1
- data/lib/stairs/env_adapters/dotenv.rb +2 -2
- data/lib/stairs/env_adapters/rbenv.rb +2 -2
- data/lib/stairs/env_adapters/rvm.rb +2 -2
- data/lib/stairs/env_adapters.rb +2 -2
- data/lib/stairs/interactive_configuration.rb +25 -7
- data/lib/stairs/railtie.rb +7 -0
- data/lib/stairs/script.rb +3 -3
- data/lib/stairs/step.rb +49 -23
- data/lib/stairs/steps/secret_token.rb +1 -1
- data/lib/stairs/steps.rb +1 -1
- data/lib/stairs/tasks.rb +1 -1
- data/lib/stairs/util/cli.rb +50 -0
- data/lib/stairs/util/{file_utils.rb → file_mutation.rb} +10 -5
- data/lib/stairs/util.rb +3 -2
- data/lib/stairs/version.rb +1 -1
- data/lib/stairs.rb +3 -1
- data/spec/lib/configuration_spec.rb +12 -0
- data/spec/lib/stairs/env_adapters/dotenv_spec.rb +38 -0
- data/spec/lib/stairs/env_adapters/rbenv_spec.rb +40 -0
- data/spec/lib/stairs/env_adapters/rvm_spec.rb +40 -0
- data/spec/lib/stairs/env_adapters_spec.rb +28 -0
- data/spec/lib/stairs/interactive_configuration_spec.rb +36 -0
- data/spec/lib/stairs/script_spec.rb +29 -0
- data/spec/lib/stairs/step_spec.rb +293 -0
- data/spec/lib/stairs/steps/secret_token_spec.rb +13 -0
- data/spec/lib/stairs/util/cli_spec.rb +57 -0
- data/spec/lib/stairs/util/file_mutation_spec.rb +98 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/mock_stdout.rb +52 -0
- data/stairs.gemspec +8 -1
- metadata +138 -8
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Stairs::EnvAdapters do
|
4
|
+
subject { described_class }
|
5
|
+
let(:present_adapter) { double("adapter", present?: true) }
|
6
|
+
let(:other_adapter) { double("adapter", present?: false) }
|
7
|
+
let(:another_adapter) { double("adapter", present?: false) }
|
8
|
+
|
9
|
+
before do
|
10
|
+
stub_const "Stairs::EnvAdapters::ADAPTERS", {
|
11
|
+
one: other_adapter,
|
12
|
+
two: present_adapter,
|
13
|
+
three: another_adapter
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
describe ".recommended_adapter" do
|
18
|
+
it "returns the first adapter to be `present?`" do
|
19
|
+
expect(described_class.recommended_adapter).to eq present_adapter
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe ".name_for_adapter_class" do
|
24
|
+
it "returns the name" do
|
25
|
+
expect(described_class.name_for_adapter_class(present_adapter)).to eq :two
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Stairs::InteractiveConfiguration do
|
4
|
+
subject { described_class.new }
|
5
|
+
|
6
|
+
describe "metadata" do
|
7
|
+
it "has a title" do
|
8
|
+
expect(described_class.step_title).not_to be_nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it "has a description" do
|
12
|
+
expect(described_class.step_description).not_to be_nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#run!" do
|
17
|
+
before do
|
18
|
+
Stairs::EnvAdapters.stub recommended_adapter: Stairs::EnvAdapters::Rbenv
|
19
|
+
end
|
20
|
+
|
21
|
+
it "recommends an adapter" do
|
22
|
+
output = follow_prompts("Y") { subject.run! }
|
23
|
+
expect(output).to include "you're using rbenv"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "sets the adapter" do
|
27
|
+
follow_prompts("Y") { subject.run! }
|
28
|
+
expect(Stairs.configuration.env_adapter).to be_a Stairs::EnvAdapters::Rbenv
|
29
|
+
end
|
30
|
+
|
31
|
+
it "allows for specifying your desired adapter" do
|
32
|
+
follow_prompts("N", "dotenv") { subject.run! }
|
33
|
+
expect(Stairs.configuration.env_adapter).to be_a Stairs::EnvAdapters::Dotenv
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Stairs::Script do
|
4
|
+
let(:filename) { "setup.rb" }
|
5
|
+
subject { described_class.new(filename) }
|
6
|
+
|
7
|
+
context "with a script present" do
|
8
|
+
before do
|
9
|
+
File.open(filename, "w") do |file|
|
10
|
+
file.write("self.class")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
after { File.delete(filename) }
|
15
|
+
|
16
|
+
describe "#run!" do
|
17
|
+
it "outputs running message" do
|
18
|
+
output = capture_stdout { subject.run! }
|
19
|
+
expect(output).to include "= Running script setup.rb"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "evaluates the script in the context of an instance of Step" do
|
23
|
+
# because our test setup.rb only contains `self.class` we can check
|
24
|
+
# this way:
|
25
|
+
expect(subject.run!).to eq Stairs::Step
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,293 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Stairs::Step do
|
4
|
+
let(:anon_step) { Class.new(described_class) }
|
5
|
+
subject { anon_step.new }
|
6
|
+
|
7
|
+
describe "metadata" do
|
8
|
+
describe "step_title" do
|
9
|
+
it "can be set on the class using title class DSL" do
|
10
|
+
anon_step.title "Class Step Name"
|
11
|
+
expect(subject.step_title).to eq "Class Step Name"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can be set on the instance" do
|
15
|
+
subject.step_title = "Instance Step Name"
|
16
|
+
expect(subject.step_title).to eq "Instance Step Name"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "prefers the value set on instance" do
|
20
|
+
anon_step.title "Class Step Name"
|
21
|
+
subject.step_title = "Instance Step Name"
|
22
|
+
expect(subject.step_title).to eq "Instance Step Name"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "step_description" do
|
27
|
+
it "can be set on the class using description class DSL" do
|
28
|
+
anon_step.description "Class Step Description"
|
29
|
+
expect(subject.step_description).to eq "Class Step Description"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "can be set on the instance" do
|
33
|
+
subject.step_description = "Instance Step Description"
|
34
|
+
expect(subject.step_description).to eq "Instance Step Description"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "prefers the value set on instance" do
|
38
|
+
anon_step.title "Class Step Description"
|
39
|
+
subject.step_description = "Instance Step Description"
|
40
|
+
expect(subject.step_description).to eq "Instance Step Description"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#run!" do
|
46
|
+
before { subject.stub run: true }
|
47
|
+
before { anon_step.title "Step Name" }
|
48
|
+
|
49
|
+
it "outputs lead-in message" do
|
50
|
+
output = capture_stdout { subject.run! }
|
51
|
+
expect(output).to include "== Running Step Name"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "calls #run where the implementation lives" do
|
55
|
+
subject.should_receive(:run)
|
56
|
+
subject.run!
|
57
|
+
end
|
58
|
+
|
59
|
+
it "outputs completed message" do
|
60
|
+
output = capture_stdout { subject.run! }
|
61
|
+
expect(output).to include "== Completed Step Name"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#provide" do
|
66
|
+
it "prompts the user to provide input" do
|
67
|
+
output = follow_prompts("here") { subject.provide "Gimme" }
|
68
|
+
expect(output).to include "Gimme: "
|
69
|
+
end
|
70
|
+
|
71
|
+
it "returns the input" do
|
72
|
+
follow_prompts("here") do
|
73
|
+
expect(subject.provide("Gimme")).to eq "here"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it "requires user input" do
|
78
|
+
follow_prompts "", "", "", "finally" do
|
79
|
+
expect(subject.provide("Gimme")).to eq "finally"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "with a default" do
|
84
|
+
def call_method
|
85
|
+
subject.provide "Gimme", default: "adefault"
|
86
|
+
end
|
87
|
+
|
88
|
+
it "does not require input" do
|
89
|
+
output = follow_prompts("here") { call_method }
|
90
|
+
end
|
91
|
+
|
92
|
+
context "and required" do
|
93
|
+
it "does not require input" do
|
94
|
+
follow_prompts "" do
|
95
|
+
expect(subject.provide("Gimme", required: true, default: "adefault")).to eq "adefault"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "with no input" do
|
101
|
+
it "returns the default" do
|
102
|
+
follow_prompts("") do
|
103
|
+
expect(call_method).to eq "adefault"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context "with input" do
|
109
|
+
it "returns the input" do
|
110
|
+
follow_prompts("here") do
|
111
|
+
expect(call_method).to eq "here"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "optional" do
|
118
|
+
it "does not require input" do
|
119
|
+
follow_prompts "" do
|
120
|
+
expect(subject.provide("Gimme", required: false)).to eq nil
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "#choice" do
|
127
|
+
it "prompts the user to answer the question" do
|
128
|
+
output = follow_prompts("Y") { subject.choice("Should I?") }
|
129
|
+
expect(output).to include "Should I?"
|
130
|
+
end
|
131
|
+
|
132
|
+
it "defaults to a Y/N question" do
|
133
|
+
output = follow_prompts("Y") { subject.choice("Should I?") }
|
134
|
+
expect(output).to include "(Y/N)"
|
135
|
+
end
|
136
|
+
|
137
|
+
it "returns true for Y" do
|
138
|
+
follow_prompts("Y") { expect(subject.choice("Should I?")).to be_true }
|
139
|
+
end
|
140
|
+
|
141
|
+
it "returns true for Y" do
|
142
|
+
follow_prompts("N") { expect(subject.choice("Should I?")).to be_false }
|
143
|
+
end
|
144
|
+
|
145
|
+
context "with available choices provided" do
|
146
|
+
it "displays those choices" do
|
147
|
+
output = follow_prompts("Nick") { subject.choice("What's your name?", ["Nick", "Brendan"]) }
|
148
|
+
expect(output).to include "(Nick/Brendan)"
|
149
|
+
end
|
150
|
+
|
151
|
+
it "returns the user's choice" do
|
152
|
+
follow_prompts("Nick") do
|
153
|
+
expect(subject.choice("What's your name?", ["Nick", "Brendan"])).to eq "Nick"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
it "prompts repeatedly until it receives input in available choices" do
|
158
|
+
follow_prompts("Sally", "Frank", "Nick") do
|
159
|
+
expect(subject.choice("What's your name?", ["Nick", "Brendan"])).to eq "Nick"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context "with a block" do
|
165
|
+
it "calls the block with the user's choice" do
|
166
|
+
follow_prompts("Nick") do
|
167
|
+
expect do |block|
|
168
|
+
subject.choice("What's your name?", ["Nick", "Brendan"], &block)
|
169
|
+
end.to yield_with_args("Nick")
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "#bundle" do
|
176
|
+
before { subject.stub system: true }
|
177
|
+
|
178
|
+
it "outputs lead-in message" do
|
179
|
+
output = capture_stdout { subject.bundle }
|
180
|
+
expect(output).to include "== Running bundle"
|
181
|
+
end
|
182
|
+
|
183
|
+
it "runs bundle" do
|
184
|
+
subject.should_receive(:system).with("bundle")
|
185
|
+
subject.bundle
|
186
|
+
end
|
187
|
+
|
188
|
+
it "outputs completed message" do
|
189
|
+
output = capture_stdout { subject.bundle }
|
190
|
+
expect(output).to include "== Completed bundle"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "#rake" do
|
195
|
+
before { subject.stub system: true }
|
196
|
+
|
197
|
+
it "outputs lead-in message" do
|
198
|
+
output = capture_stdout { subject.rake "the_task" }
|
199
|
+
expect(output).to include "== Running the_task"
|
200
|
+
end
|
201
|
+
|
202
|
+
it "runs the rake task" do
|
203
|
+
subject.should_receive(:system).with("rake the_task")
|
204
|
+
subject.rake "the_task"
|
205
|
+
end
|
206
|
+
|
207
|
+
it "outputs completed message" do
|
208
|
+
output = capture_stdout { subject.rake "the_task" }
|
209
|
+
expect(output).to include "== Completed the_task"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "#env" do
|
214
|
+
let(:adapter) { double("adapter", set: true) }
|
215
|
+
before { Stairs.configuration.env_adapter = adapter }
|
216
|
+
|
217
|
+
it "delegates to the adapter" do
|
218
|
+
adapter.should_receive(:set).with("NAME", "value")
|
219
|
+
subject.env "NAME", "value"
|
220
|
+
end
|
221
|
+
|
222
|
+
it "writes to ENV simultaneously so Rubyland can access without a reload" do
|
223
|
+
ENV.should_receive(:[]=).with("NAME", "value")
|
224
|
+
subject.env "NAME", "value"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe "#write" do
|
229
|
+
it "delegates to the well tested FileMutation util" do
|
230
|
+
Stairs::Util::FileMutation.should_receive(:write).with("something", "file.txt")
|
231
|
+
subject.write("something", "file.txt")
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
describe "#write_line" do
|
236
|
+
it "delegates to the well tested FileMutation util" do
|
237
|
+
Stairs::Util::FileMutation.should_receive(:write_line).with("something", "file.txt")
|
238
|
+
subject.write_line("something", "file.txt")
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
describe "#finish" do
|
243
|
+
it "outputs lead-in message" do
|
244
|
+
output = capture_stdout { subject.finish "Message" }
|
245
|
+
expect(output).to include "== All done!"
|
246
|
+
end
|
247
|
+
|
248
|
+
it "outputs supplied message" do
|
249
|
+
output = capture_stdout { subject.finish "My message" }
|
250
|
+
expect(output).to include "My message"
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe "#stairs_info" do
|
255
|
+
it "outputs the message" do
|
256
|
+
output = capture_stdout { subject.stairs_info "Ohai" }
|
257
|
+
expect(output).to include "Ohai"
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
describe "#setup" do
|
262
|
+
context "with an invalid step_name" do
|
263
|
+
it "raises when step_name cannot be resolved in Stairs::Steps" do
|
264
|
+
expect { subject.setup :blahblahbefkj }.to raise_error
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
context "with a valid step_name" do
|
269
|
+
let!(:mock_step_class) { Stairs::Steps::MockStep = Class.new(Stairs::Step) }
|
270
|
+
|
271
|
+
it "instantiates and runs the step" do
|
272
|
+
mock_step_class.any_instance.should_receive(:run!)
|
273
|
+
subject.setup :mock_step
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
context "with a block" do
|
278
|
+
def call_method
|
279
|
+
subject.setup(:custom_step) { puts "I'm running in #{self.class}" }
|
280
|
+
end
|
281
|
+
|
282
|
+
it "sets the new step's title to a titleized version of step_name" do
|
283
|
+
output = capture_stdout { call_method }
|
284
|
+
expect(output).to include "Custom Step"
|
285
|
+
end
|
286
|
+
|
287
|
+
it "runs the block in the context of the new step" do
|
288
|
+
output = capture_stdout { call_method }
|
289
|
+
expect(output).to include "I'm running in Stairs::Step"
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Stairs::Steps::SecretToken do
|
4
|
+
subject { described_class.new }
|
5
|
+
|
6
|
+
describe "#run" do
|
7
|
+
it "generates a securerandom hex and sets to SECRET_TOKEN" do
|
8
|
+
SecureRandom.stub hex: "imtotallysecurebro"
|
9
|
+
subject.should_receive(:env).with("SECRET_TOKEN", "imtotallysecurebro")
|
10
|
+
subject.run
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Stairs::Util::CLI do
|
4
|
+
subject { described_class }
|
5
|
+
|
6
|
+
describe ".get" do
|
7
|
+
it "outputs the prompt to screen" do
|
8
|
+
output = follow_prompts("test") { subject.get("itefeffe") }
|
9
|
+
expect(output).to include "itefeffe"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "collects and returns trimmed input" do
|
13
|
+
follow_prompts "test" do
|
14
|
+
expect(subject.get("it")).to eq "test"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns nil for empty input" do
|
19
|
+
follow_prompts "" do
|
20
|
+
expect(subject.get("it")).to eq nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe ".collect" do
|
26
|
+
it "returns the user provided input" do
|
27
|
+
follow_prompts "test" do
|
28
|
+
expect(subject.collect("itefeffe")).to eq "test"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "required" do
|
33
|
+
it "repeatedly prompts until a non-empty value is received" do
|
34
|
+
follow_prompts "", "", "", "finally" do
|
35
|
+
expect(subject.collect("a value")).to eq "finally"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "not required" do
|
41
|
+
it "returns nil for empty input" do
|
42
|
+
follow_prompts "" do
|
43
|
+
expect(subject.collect("gimme", required: false)).to eq nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "with custom validation block" do
|
49
|
+
it "repeatedly prompts until a valid value is received" do
|
50
|
+
follow_prompts "", "", "wrong", "right" do
|
51
|
+
response = subject.collect("a value") { |v, i| v == "right" }
|
52
|
+
expect(response).to eq "right"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Stairs::Util::FileMutation do
|
4
|
+
let(:filename) { "file.txt" }
|
5
|
+
|
6
|
+
describe ".replace_or_append" do
|
7
|
+
context "when the pattern exists in the file" do
|
8
|
+
before do
|
9
|
+
File.open(filename, "w") do |file|
|
10
|
+
file.write("line1\nline2\nline3\n")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
after { File.delete(filename) }
|
15
|
+
|
16
|
+
it "replaces the match and writes back to the file" do
|
17
|
+
described_class.replace_or_append /line2/, "newLINE2", filename
|
18
|
+
expect(File.read(filename)).to eq "line1\nnewLINE2\nline3\n"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when the pattern does not exist in the file" do
|
23
|
+
before do
|
24
|
+
File.open(filename, "w") do |file|
|
25
|
+
file.write("line1\nline2\nline3\n")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
after { File.delete(filename) }
|
30
|
+
|
31
|
+
it "appends to the end of the file" do
|
32
|
+
described_class.replace_or_append /line4/, "line4", filename
|
33
|
+
expect(File.read(filename)).to eq "line1\nline2\nline3\nline4\n"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe ".write_line" do
|
39
|
+
before do
|
40
|
+
File.open(filename, "w") do |file|
|
41
|
+
file.write("line1\nline2\n")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
after { File.delete(filename) }
|
46
|
+
|
47
|
+
it "appends a line to the bottom of the file" do
|
48
|
+
described_class.write_line "line3", filename
|
49
|
+
expect(File.read(filename)).to eq "line1\nline2\nline3\n"
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when there is no newline at the bottom" do
|
53
|
+
before do
|
54
|
+
File.delete(filename) if File.exists?(filename)
|
55
|
+
|
56
|
+
File.open(filename, "w") do |file|
|
57
|
+
file.write("line1\nline2")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "adds a newline before appending the line" do
|
62
|
+
described_class.write_line "line3", filename
|
63
|
+
expect(File.read(filename)).to eq "line1\nline2\nline3\n"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe ".write" do
|
69
|
+
context "when the file exists" do
|
70
|
+
before do
|
71
|
+
File.open(filename, "w") do |file|
|
72
|
+
file.write("some content\n")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
after { File.delete(filename) }
|
77
|
+
|
78
|
+
it "replaces the contents of the file and leaves trailing newline" do
|
79
|
+
described_class.write "new content", filename
|
80
|
+
expect(File.read(filename)).to eq "new content\n"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "when the file doesn't exist" do
|
85
|
+
after { File.delete(filename) }
|
86
|
+
|
87
|
+
it "creates a file" do
|
88
|
+
described_class.write "other content", filename
|
89
|
+
expect(File.exists?(filename)).to be_true
|
90
|
+
end
|
91
|
+
|
92
|
+
it "writes the contents to the file" do
|
93
|
+
described_class.write "my favorite content", filename
|
94
|
+
expect(File.read(filename)).to eq "my favorite content\n"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "bundler"
|
2
|
+
Bundler.require
|
3
|
+
|
4
|
+
require "stairs"
|
5
|
+
|
6
|
+
Dir["./spec/support/**/*.rb"].each { |f| require f }
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
10
|
+
config.run_all_when_everything_filtered = true
|
11
|
+
config.filter_run :focus
|
12
|
+
|
13
|
+
config.include MockStdIO
|
14
|
+
|
15
|
+
config.before(:all, &:silence_output)
|
16
|
+
config.after(:all, &:enable_output)
|
17
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "stringio"
|
2
|
+
|
3
|
+
module MockStdIO
|
4
|
+
def follow_prompts(*responses, &block)
|
5
|
+
old_stdin = $stdin
|
6
|
+
old_stdout = $stdout
|
7
|
+
|
8
|
+
$stdin = StringIO.new("", "r+")
|
9
|
+
fake_stdout = StringIO.new
|
10
|
+
$stdout = fake_stdout
|
11
|
+
|
12
|
+
responses.each { |r| $stdin << "#{r}\n" }
|
13
|
+
$stdin.rewind
|
14
|
+
|
15
|
+
block.call
|
16
|
+
|
17
|
+
fake_stdout.string
|
18
|
+
ensure
|
19
|
+
$stdin = old_stdin
|
20
|
+
$stdout = old_stdout
|
21
|
+
end
|
22
|
+
|
23
|
+
def capture_stdout(&block)
|
24
|
+
old_stdout = $stdout
|
25
|
+
|
26
|
+
fake_stdout = StringIO.new
|
27
|
+
$stdout = fake_stdout
|
28
|
+
|
29
|
+
block.call
|
30
|
+
|
31
|
+
fake_stdout.string
|
32
|
+
ensure
|
33
|
+
$stdout = old_stdout
|
34
|
+
end
|
35
|
+
|
36
|
+
def silence_output
|
37
|
+
@orig_stderr = $stderr
|
38
|
+
@orig_stdout = $stdout
|
39
|
+
|
40
|
+
# redirect stderr and stdout to /dev/null
|
41
|
+
$stderr = File.new("/dev/null", "w")
|
42
|
+
$stdout = File.new("/dev/null", "w")
|
43
|
+
end
|
44
|
+
|
45
|
+
# Replace stdout and stderr so anything else is output correctly.
|
46
|
+
def enable_output
|
47
|
+
$stderr = @orig_stderr
|
48
|
+
$stdout = @orig_stdout
|
49
|
+
@orig_stderr = nil
|
50
|
+
@orig_stdout = nil
|
51
|
+
end
|
52
|
+
end
|
data/stairs.gemspec
CHANGED
@@ -20,8 +20,15 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
22
|
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "pry"
|
24
|
+
spec.add_development_dependency "rspec", "~> 2.14.1"
|
25
|
+
spec.add_development_dependency "guard-rspec", "~> 4.0.3"
|
26
|
+
spec.add_development_dependency "rb-fsevent", "~> 0.9.3"
|
27
|
+
spec.add_development_dependency "awesome_print", "~> 1.2.0"
|
28
|
+
spec.add_development_dependency "fakefs", "~> 0.4.3"
|
29
|
+
spec.add_development_dependency "rubocop", "~> 0.14.1"
|
30
|
+
spec.add_development_dependency "guard-rubocop", "~> 1.0.0"
|
23
31
|
|
24
|
-
spec.add_dependency "highline", "~> 1.6.20"
|
25
32
|
spec.add_dependency "activesupport", ">= 3.2.0"
|
26
33
|
spec.add_dependency "colorize", "~> 0.6.0"
|
27
34
|
end
|