awesome_spawn 1.1.1 → 1.2.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.
@@ -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