awesome_spawn 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,10 @@
1
1
  require "awesome_spawn/version"
2
+ require "awesome_spawn/command_line_builder"
2
3
  require "awesome_spawn/command_result"
3
4
  require "awesome_spawn/command_result_error"
4
5
  require "awesome_spawn/no_such_file_error"
5
6
 
6
- require "shellwords"
7
+ require "open3"
7
8
 
8
9
  module AwesomeSpawn
9
10
  extend self
@@ -61,18 +62,14 @@ module AwesomeSpawn
61
62
  params = options.delete(:params)
62
63
  in_data = options.delete(:in_data)
63
64
 
64
- output = ""
65
- error = ""
66
- status = nil
67
- command_line = build_command_line(command, params)
65
+ output, error, status = "", "", nil
66
+ command_line = build_command_line(command, params)
68
67
 
69
68
  begin
70
- output, error = launch(command_line, in_data, options)
71
- status = exitstatus
69
+ output, error, status = launch(command_line, in_data, options)
72
70
  ensure
73
71
  output ||= ""
74
72
  error ||= ""
75
- self.exitstatus = nil
76
73
  end
77
74
  rescue Errno::ENOENT => err
78
75
  raise NoSuchFileError.new(err.message) if NoSuchFileError.detected?(err.message)
@@ -103,109 +100,17 @@ module AwesomeSpawn
103
100
  command_result
104
101
  end
105
102
 
106
- # Build the full command line.
107
- #
108
- # @param [String] command The command to run
109
- # @param [Hash,Array] params Optional command line parameters. They can
110
- # be passed as a Hash or associative Array. The values are sanitized to
111
- # prevent command line injection. Keys as symbols are prefixed with `--`,
112
- # and `_` is replaced with `-`.
113
- #
114
- # - `{:key => "value"}` generates `--key value`
115
- # - `{"--key" => "value"}` generates `--key value`
116
- # - `{:key= => "value"}` generates `--key=value`
117
- # - `{"--key=" => "value"}` generates `--key=value`
118
- # - `{:key_name => "value"}` generates `--key-name value`
119
- # - `{:key => nil}` generates `--key`
120
- # - `{"-f" => ["file1", "file2"]}` generates `-f file1 file2`
121
- # - `{nil => ["file1", "file2"]}` generates `file1 file2`
122
- #
123
- # @return [String] The full command line
103
+ # (see CommandLineBuilder#build)
124
104
  def build_command_line(command, params = nil)
125
- return command.to_s if params.nil? || params.empty?
126
- "#{command} #{assemble_params(sanitize(params))}"
105
+ CommandLineBuilder.new.build(command, params)
127
106
  end
128
107
 
129
108
  private
130
109
 
131
- def sanitize(params)
132
- return [] if params.nil? || params.empty?
133
- params.collect do |k, v|
134
- [sanitize_key(k), sanitize_value(v)]
135
- end
136
- end
137
-
138
- def sanitize_key(key)
139
- case key
140
- when Symbol then "--#{key.to_s.tr("_", "-")}"
141
- else key
142
- end
143
- end
144
-
145
- def sanitize_value(value)
146
- case value
147
- when Array then value.collect { |i| i.to_s.shellescape }
148
- when NilClass then value
149
- else value.to_s.shellescape
150
- end
151
- end
152
-
153
- def assemble_params(sanitized_params)
154
- sanitized_params.collect do |pair|
155
- pair_joiner = pair.first.to_s.end_with?("=") ? "" : " "
156
- pair.flatten.compact.join(pair_joiner)
157
- end.join(" ")
158
- end
159
-
160
- # IO pipes have a maximum size of 64k before blocking,
161
- # so we need to read and write synchronously.
162
- # http://stackoverflow.com/questions/13829830/ruby-process-spawn-stdout-pipe-buffer-size-limit/13846146#13846146
163
- THREAD_SYNC_KEY = "#{self.name}-exitstatus"
164
-
165
110
  def launch(command, in_data, spawn_options = {})
166
- out_r, out_w = IO.pipe
167
- err_r, err_w = IO.pipe
168
- in_r, in_w = IO.pipe if in_data
169
-
170
- spawn_options[:out] = out_w
171
- spawn_options[:err] = err_w
172
- spawn_options[:in] = in_r if in_data
173
-
174
- pid = Kernel.spawn(command, spawn_options)
175
-
176
- write_to_input(in_w, in_data) if in_data
177
- wait_for_process(pid, out_w, err_w, in_r)
178
- wait_for_pipes(out_r, err_r)
179
- end
180
-
181
- def write_to_input(in_w, in_data)
182
- in_w.write(in_data)
183
- in_w.close
184
- end
185
-
186
- def wait_for_process(pid, out_w, err_w, in_r)
187
- self.exitstatus = :not_done
188
- Thread.new(Thread.current) do |parent_thread|
189
- _, status = Process.wait2(pid)
190
- out_w.close
191
- err_w.close
192
- in_r.close if in_r
193
- parent_thread[THREAD_SYNC_KEY] = status.exitstatus
194
- end
195
- end
196
-
197
- def wait_for_pipes(out_r, err_r)
198
- out = out_r.read
199
- err = err_r.read
200
- sleep(0.1) while exitstatus == :not_done
201
- return out, err
202
- end
203
-
204
- def exitstatus
205
- Thread.current[THREAD_SYNC_KEY]
206
- end
207
-
208
- def exitstatus=(value)
209
- Thread.current[THREAD_SYNC_KEY] = value
111
+ spawn_options = spawn_options.merge(:stdin_data => in_data) if in_data
112
+ output, error, status = Open3.capture3(command, spawn_options)
113
+ status &&= status.exitstatus
114
+ return output, error, status
210
115
  end
211
116
  end
@@ -0,0 +1,107 @@
1
+ require "shellwords"
2
+
3
+ module AwesomeSpawn
4
+ class CommandLineBuilder
5
+ # Build the full command line.
6
+ #
7
+ # @param [String] command The command to run
8
+ # @param [Hash,Array] params Optional command line parameters. They can
9
+ # be passed as a Hash or associative Array. The values are sanitized to
10
+ # prevent command line injection. Keys as Symbols are prefixed with `--`,
11
+ # and `_` is replaced with `-`.
12
+ #
13
+ # - `{:key => "value"}` generates `--key value`
14
+ # - `[[:key, "value"]]` generates `--key value`
15
+ # - `{:key= => "value"}` generates `--key=value`
16
+ # - `[[:key=, "value"]]` generates `--key=value` <br /><br />
17
+ #
18
+ # - `{"--key" => "value"}` generates `--key value`
19
+ # - `[["--key", "value"]]` generates `--key value`
20
+ # - `{"--key=" => "value"}` generates `--key=value`
21
+ # - `[["--key=", "value"]]` generates `--key=value` <br /><br />
22
+ #
23
+ # - `{:key_name => "value"}` generates `--key-name value`
24
+ # - `[[:key_name, "value"]]` generates `--key-name value`
25
+ # - `{:key_name= => "value"}` generates `--key-name=value`
26
+ # - `[[:key_name=, "value"]]` generates `--key-name=value` <br /><br />
27
+ #
28
+ # - `{"-f" => ["file1", "file2"]}` generates `-f file1 file2`
29
+ # - `[["-f", "file1", "file2"]]` generates `-f file1 file2` <br /><br />
30
+ #
31
+ # - `{:key => nil}` generates `--key`
32
+ # - `[[:key, nil]]` generates `--key`
33
+ # - `[[:key]]` generates `--key` <br /><br />
34
+ #
35
+ # - `{nil => ["file1", "file2"]}` generates `file1 file2`
36
+ # - `[[nil, ["file1", "file2"]]]` generates `file1 file2`
37
+ # - `[[nil, "file1", "file2"]]` generates `file1 file2`
38
+ # - `[["file1", "file2"]]` generates `file1 file2`
39
+ #
40
+ # @return [String] The full command line
41
+ def build(command, params = nil)
42
+ params = assemble_params(sanitize(params))
43
+ params.empty? ? command.to_s : "#{command} #{params}"
44
+ end
45
+
46
+ private
47
+
48
+ def assemble_params(sanitized_params)
49
+ sanitized_params.collect do |group|
50
+ joiner = group.first.to_s.end_with?("=") ? "" : " "
51
+ group.compact.join(joiner)
52
+ end.join(" ")
53
+ end
54
+
55
+ def sanitize(params)
56
+ return [] if params.nil? || params.empty?
57
+ sanitize_associative_array(params.to_a)
58
+ end
59
+
60
+ def sanitize_associative_array(array)
61
+ array.collect { |a| sanitize_item(a) }
62
+ end
63
+
64
+ def sanitize_item(item)
65
+ case item
66
+ when Array then sanitize_key_values(item[0], item[1..-1])
67
+ when Hash then sanitize_associative_array(item.to_a)
68
+ else sanitize_item([item])
69
+ end
70
+ end
71
+
72
+ def sanitize_key_values(key, values)
73
+ [sanitize_key(key), *sanitize_value(values)]
74
+ end
75
+
76
+ KEY_REGEX = /^((?:--?)?)(.+?)(=?)$/
77
+
78
+ def sanitize_key(key)
79
+ return key if key.nil?
80
+ key = convert_symbol_key(key) if key.kind_of?(Symbol)
81
+
82
+ case key
83
+ when String
84
+ return key if key.empty?
85
+ prefix, key, suffix = KEY_REGEX.match(key)[1..3]
86
+ "#{prefix}#{sanitize_value(key)}#{suffix}"
87
+ else
88
+ sanitize_value(key)
89
+ end
90
+ end
91
+
92
+ def convert_symbol_key(key)
93
+ "--#{key.to_s.tr("_", "-")}"
94
+ end
95
+
96
+ def sanitize_value(value)
97
+ case value
98
+ when Enumerable
99
+ value.to_a.collect { |i| sanitize_value(i) }.compact
100
+ when NilClass
101
+ value
102
+ else
103
+ value.to_s.shellescape
104
+ end
105
+ end
106
+ end
107
+ end
@@ -9,6 +9,14 @@ module AwesomeSpawn
9
9
  @exit_status = exit_status
10
10
  end
11
11
 
12
+ def success?
13
+ exit_status == 0
14
+ end
15
+
16
+ def failure?
17
+ exit_status != 0
18
+ end
19
+
12
20
  def inspect
13
21
  "#{to_s.chop} @exit_status=#{@exit_status}>"
14
22
  end
@@ -1,3 +1,3 @@
1
1
  module AwesomeSpawn
2
- VERSION = "1.1.1"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -4,31 +4,12 @@ require 'pathname' # For Pathname specific specs
4
4
  describe AwesomeSpawn do
5
5
  subject { described_class }
6
6
 
7
- let(:params) do
8
- {
9
- "--user" => "bob",
10
- "--pass" => "P@$sw0^& |<>/-+*d%",
11
- "--db" => nil,
12
- "--desc=" => "Some Description",
13
- :symkey => nil,
14
- :symkey_dash => nil,
15
- nil => ["pkg1", "some pkg"]
16
- }
17
- end
18
-
19
- let (:modified_params) do
20
- params.to_a + [123, 456].collect {|pool| ["--pool", pool]}
21
- end
22
-
23
7
  shared_examples_for "run" do
24
8
  context "options" do
25
- before do
26
- subject.stub(:exitstatus => 0)
27
- end
28
-
29
9
  it ":params won't be modified" do
10
+ params = {:user => "bob"}
30
11
  orig_params = params.dup
31
- subject.stub(:launch)
12
+ subject.stub(:launch => ["", "", 0])
32
13
  subject.send(run_method, "true", :params => params)
33
14
  expect(orig_params).to eq(params)
34
15
  end
@@ -49,7 +30,7 @@ describe AwesomeSpawn do
49
30
  context "with real execution" do
50
31
  before do
51
32
  # Re-enable actual spawning just for these specs.
52
- Kernel.stub(:spawn).and_call_original
33
+ enable_spawning
53
34
  end
54
35
 
55
36
  it "command ok exit ok" do
@@ -132,71 +113,4 @@ describe AwesomeSpawn do
132
113
  let(:run_method) {"run!"}
133
114
  end
134
115
  end
135
-
136
- context ".build_command_line" do
137
- it "sanitizes crazy params" do
138
- cl = subject.build_command_line("true", modified_params)
139
- expect(cl).to eq "true --user bob --pass P@\\$sw0\\^\\&\\ \\|\\<\\>/-\\+\\*d\\% --db --desc=Some\\ Description --symkey --symkey-dash pkg1 some\\ pkg --pool 123 --pool 456"
140
- end
141
-
142
- it "handles Symbol keys" do
143
- cl = subject.build_command_line("true", :abc => "def")
144
- expect(cl).to eq "true --abc def"
145
- end
146
-
147
- it "handles Symbol keys with tailing '='" do
148
- cl = subject.build_command_line("true", :abc= => "def")
149
- expect(cl).to eq "true --abc=def"
150
- end
151
-
152
- it "handles Symbol keys with underscore" do
153
- cl = subject.build_command_line("true", :abc_def => "ghi")
154
- expect(cl).to eq "true --abc-def ghi"
155
- end
156
-
157
- it "handles Symbol keys with underscore and tailing '='" do
158
- cl = subject.build_command_line("true", :abc_def= => "ghi")
159
- expect(cl).to eq "true --abc-def=ghi"
160
- end
161
-
162
- it "sanitizes Fixnum array param value" do
163
- cl = subject.build_command_line("true", nil => [1])
164
- expect(cl).to eq "true 1"
165
- end
166
-
167
- it "sanitizes Pathname param value" do
168
- cl = subject.build_command_line("true", nil => [Pathname.new("/usr/bin/ruby")])
169
- expect(cl).to eq "true /usr/bin/ruby"
170
- end
171
-
172
- it "sanitizes Pathname param key" do
173
- cl = subject.build_command_line("true", Pathname.new("/usr/bin/ruby") => nil)
174
- expect(cl).to eq "true /usr/bin/ruby"
175
- end
176
-
177
- it "with params as empty Hash" do
178
- cl = subject.build_command_line("true", {})
179
- expect(cl).to eq "true"
180
- end
181
-
182
- it "with params as nil" do
183
- cl = subject.build_command_line("true", nil)
184
- expect(cl).to eq "true"
185
- end
186
-
187
- it "without params" do
188
- cl = subject.build_command_line("true")
189
- expect(cl).to eq "true"
190
- end
191
-
192
- it "with Pathname command" do
193
- cl = subject.build_command_line(Pathname.new("/usr/bin/ruby"))
194
- expect(cl).to eq "/usr/bin/ruby"
195
- end
196
-
197
- it "with Pathname command and params" do
198
- cl = subject.build_command_line(Pathname.new("/usr/bin/ruby"), "-v" => nil)
199
- expect(cl).to eq "/usr/bin/ruby -v"
200
- end
201
- end
202
116
  end
@@ -0,0 +1,255 @@
1
+ require 'spec_helper'
2
+
3
+ describe AwesomeSpawn::CommandLineBuilder do
4
+ subject { described_class.new }
5
+
6
+ context "#build" do
7
+ def assert_params(params, expected_params)
8
+ expect(subject.build("true", params)).to eq "true #{expected_params}".strip
9
+ end
10
+
11
+ it "without params" do
12
+ expect(subject.build("true")).to eq "true"
13
+ end
14
+
15
+ it "with nil" do
16
+ expect(subject.build("true", nil)).to eq "true"
17
+ end
18
+
19
+ it "with Pathname command" do
20
+ actual = subject.build(Pathname.new("/usr/bin/ruby"))
21
+ expect(actual).to eq "/usr/bin/ruby"
22
+ end
23
+
24
+ it "with Pathname command and params" do
25
+ actual = subject.build(Pathname.new("/usr/bin/ruby"), "-v" => nil)
26
+ expect(actual).to eq "/usr/bin/ruby -v"
27
+ end
28
+
29
+ context "with Hash" do
30
+ it "that is empty" do
31
+ assert_params({}, "")
32
+ end
33
+
34
+ it "with normal params" do
35
+ assert_params({"--user" => "bob"}, "--user bob")
36
+ end
37
+
38
+ it "with key with tailing '='" do
39
+ assert_params({"--user=" => "bob"}, "--user=bob")
40
+ end
41
+
42
+ it "with value requiring sanitization" do
43
+ assert_params({"--pass" => "P@$s w0rd%"}, "--pass P@\\$s\\ w0rd\\%")
44
+ end
45
+
46
+ it "with key requiring sanitization" do
47
+ assert_params({"--h&x0r=" => "xxx"}, "--h\\&x0r=xxx")
48
+ end
49
+
50
+ it "with key as Symbol" do
51
+ assert_params({:abc => "def"}, "--abc def")
52
+ end
53
+
54
+ it "with key as Symbol with tailing '='" do
55
+ assert_params({:abc= => "def"}, "--abc=def")
56
+ end
57
+
58
+ it "with key as Symbol with underscore" do
59
+ assert_params({:abc_def => "ghi"}, "--abc-def ghi")
60
+ end
61
+
62
+ it "with key as Symbol with underscore and tailing '='" do
63
+ assert_params({:abc_def= => "ghi"}, "--abc-def=ghi")
64
+ end
65
+
66
+ it "with key as nil" do
67
+ assert_params({nil => "def"}, "def")
68
+ end
69
+
70
+ it "with value as nil" do
71
+ assert_params({"--abc" => nil}, "--abc")
72
+ end
73
+
74
+ it "with key and value nil" do
75
+ assert_params({nil => nil}, "")
76
+ end
77
+
78
+ it "with key of '--'" do
79
+ assert_params({"--" => nil}, "--")
80
+ end
81
+
82
+ it "with value as Symbol" do
83
+ assert_params({"--abc" => :def}, "--abc def")
84
+ end
85
+
86
+ it "with value as Array" do
87
+ assert_params({"--abc" => ["def", "ghi"]}, "--abc def ghi")
88
+ end
89
+
90
+ it "with value as Fixnum" do
91
+ assert_params({"--abc" => 1}, "--abc 1")
92
+ end
93
+
94
+ it "with value as Fixnum Array" do
95
+ assert_params({"--abc" => [1, 2]}, "--abc 1 2")
96
+ end
97
+
98
+ it "with value as Range" do
99
+ assert_params({"--abc" => (1..4)}, "--abc 1 2 3 4")
100
+ end
101
+
102
+ it "with value as Pathname" do
103
+ assert_params({"--abc" => Pathname.new("/usr/bin/ruby")}, "--abc /usr/bin/ruby")
104
+ end
105
+ end
106
+
107
+ context "with associative Array" do
108
+ it "that is empty" do
109
+ assert_params([], "")
110
+ end
111
+
112
+ it "that is nested empty" do
113
+ assert_params([[]], "")
114
+ end
115
+
116
+ it "with normal params" do
117
+ assert_params([["--user", "bob"]], "--user bob")
118
+ end
119
+
120
+ it "with key with tailing '='" do
121
+ assert_params([["--user=", "bob"]], "--user=bob")
122
+ end
123
+
124
+ it "with value requiring sanitization" do
125
+ assert_params([["--pass", "P@$s w0rd%"]], "--pass P@\\$s\\ w0rd\\%")
126
+ end
127
+
128
+ it "with key requiring sanitization" do
129
+ assert_params([["--h&x0r=", "xxx"]], "--h\\&x0r=xxx")
130
+ end
131
+
132
+ it "with key as Symbol" do
133
+ assert_params([[:abc, "def"]], "--abc def")
134
+ end
135
+
136
+ it "with key as Symbol with tailing '='" do
137
+ assert_params([[:abc=, "def"]], "--abc=def")
138
+ end
139
+
140
+ it "with key as Symbol with underscore" do
141
+ assert_params([[:abc_def, "ghi"]], "--abc-def ghi")
142
+ end
143
+
144
+ it "with key as Symbol with underscore and tailing '='" do
145
+ assert_params([[:abc_def=, "ghi"]], "--abc-def=ghi")
146
+ end
147
+
148
+ it "with key as nil" do
149
+ assert_params([[nil, "def"]], "def")
150
+ end
151
+
152
+ it "with value as nil" do
153
+ assert_params([["--abc", nil]], "--abc")
154
+ end
155
+
156
+ it "with key and value nil" do
157
+ assert_params([[nil, nil]], "")
158
+ end
159
+
160
+ it "with key as nil and multiple values" do
161
+ assert_params([[nil, "def", "ghi"]], "def ghi")
162
+ end
163
+
164
+ it "with key of '--'" do
165
+ assert_params([["--", nil]], "--")
166
+ end
167
+
168
+ it "key alone" do
169
+ assert_params([["--abc"]], "--abc")
170
+ end
171
+
172
+ it "key as Symbol alone" do
173
+ assert_params([[:abc]], "--abc")
174
+ end
175
+
176
+ it "key as a bareword" do
177
+ assert_params(["--abc"], "--abc")
178
+ end
179
+
180
+ it "key as bareword Symbol" do
181
+ assert_params([:abc], "--abc")
182
+ end
183
+
184
+ it "value as a bareword" do
185
+ assert_params(["abc"], "abc")
186
+ end
187
+
188
+ it "with value as Symbol" do
189
+ assert_params([["--abc" => :def]], "--abc def")
190
+ end
191
+
192
+ it "with value as Array" do
193
+ assert_params([["--abc", ["def", "ghi"]]], "--abc def ghi")
194
+ end
195
+
196
+ it "with value as flattened Array" do
197
+ assert_params([["--abc", "def", "ghi"]], "--abc def ghi")
198
+ end
199
+
200
+ it "with value as Fixnum" do
201
+ assert_params([["--abc", 1]], "--abc 1")
202
+ end
203
+
204
+ it "with value as Fixnum Array" do
205
+ assert_params([["--abc", [1, 2]]], "--abc 1 2")
206
+ end
207
+
208
+ it "with value as Range" do
209
+ assert_params([["--abc", (1..4)]], "--abc 1 2 3 4")
210
+ end
211
+
212
+ it "with value as Pathname" do
213
+ assert_params([["--abc", Pathname.new("/usr/bin/ruby")]], "--abc /usr/bin/ruby")
214
+ end
215
+
216
+ it "with duplicate keys" do
217
+ assert_params([["--abc", 1], ["--abc", 2]], "--abc 1 --abc 2")
218
+ end
219
+ end
220
+
221
+ context "with multiple params" do # real-world cases
222
+ let(:expected) { "log feature -E --oneline --grep abc" }
223
+
224
+ it "as full Hash" do
225
+ params = {"log" => nil, "feature" => nil, "-E" => nil, :oneline => nil, "--grep" => "abc"}
226
+ assert_params(params, expected)
227
+ end
228
+
229
+ it "as grouped Hash" do
230
+ params = {nil => ["log", "feature"], "-E" => nil, :oneline => nil, :grep => "abc"}
231
+ assert_params(params, expected)
232
+ end
233
+
234
+ it "as associative Array" do
235
+ params = [[nil, "log", "feature"], ["-E", nil], [:oneline, nil], [:grep, "abc"]]
236
+ assert_params(params, expected)
237
+ end
238
+
239
+ it "as associative Array without nil values" do
240
+ params = [["log", "feature"], ["-E"], [:oneline], [:grep, "abc"]]
241
+ assert_params(params, expected)
242
+ end
243
+
244
+ it "as mixed Array with barewords" do
245
+ params = ["log", "feature", "-E", :oneline, [:grep, "abc"]]
246
+ assert_params(params, expected)
247
+ end
248
+
249
+ it "as mixed Array with nested Hashes" do
250
+ params = ["log", "feature", "-E", :oneline, {:grep => "abc"}]
251
+ assert_params(params, expected)
252
+ end
253
+ end
254
+ end
255
+ end
@@ -5,9 +5,19 @@ describe AwesomeSpawn::CommandResult do
5
5
  it "will not display sensitive information" do
6
6
  str = described_class.new("aaa", "bbb", "ccc", 0).inspect
7
7
 
8
- expect(str.include?("aaa")).to be_false
9
- expect(str.include?("bbb")).to be_false
10
- expect(str.include?("ccc")).to be_false
8
+ expect(str).to_not include("aaa")
9
+ expect(str).to_not include("bbb")
10
+ expect(str).to_not include("ccc")
11
+ end
12
+
13
+ it "will know if a command succeeded" do
14
+ expect(described_class.new("c", "o", "e", 0)).to be_a_success
15
+ expect(described_class.new("c", "o", "e", 0)).not_to be_a_failure
16
+ end
17
+
18
+ it "will know if a command failed" do
19
+ expect(described_class.new("c", "o", "e", 1)).to be_a_failure
20
+ expect(described_class.new("c", "o", "e", 1)).not_to be_a_success
11
21
  end
12
22
  end
13
23
  end
@@ -15,9 +15,15 @@ RSpec.configure do |config|
15
15
  # --seed 1234
16
16
  config.order = 'random'
17
17
 
18
- config.before do
19
- Kernel.stub(:spawn).and_raise("Spawning is not permitted in specs. Please change your spec to use expectations/stubs.")
20
- end
18
+ config.before { disable_spawning }
19
+ end
20
+
21
+ def disable_spawning
22
+ Open3.stub(:capture3).and_raise("Spawning is not permitted in specs. Please change your spec to use expectations/stubs.")
23
+ end
24
+
25
+ def enable_spawning
26
+ Open3.stub(:capture3).and_call_original
21
27
  end
22
28
 
23
29
  begin
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: awesome_spawn
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2014-02-03 00:00:00.000000000 Z
15
+ date: 2014-07-09 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: bundler
@@ -90,6 +90,7 @@ extensions: []
90
90
  extra_rdoc_files: []
91
91
  files:
92
92
  - lib/awesome_spawn.rb
93
+ - lib/awesome_spawn/command_line_builder.rb
93
94
  - lib/awesome_spawn/command_result.rb
94
95
  - lib/awesome_spawn/command_result_error.rb
95
96
  - lib/awesome_spawn/no_such_file_error.rb
@@ -98,6 +99,7 @@ files:
98
99
  - README.md
99
100
  - LICENSE.txt
100
101
  - spec/awesome_spawn_spec.rb
102
+ - spec/command_line_builder_spec.rb
101
103
  - spec/command_result_spec.rb
102
104
  - spec/spec_helper.rb
103
105
  - .rspec
@@ -128,6 +130,7 @@ specification_version: 3
128
130
  summary: AwesomeSpawn is a module that provides some useful features over Ruby's Kernel.spawn.
129
131
  test_files:
130
132
  - spec/awesome_spawn_spec.rb
133
+ - spec/command_line_builder_spec.rb
131
134
  - spec/command_result_spec.rb
132
135
  - spec/spec_helper.rb
133
136
  - .rspec