shexecutor 0.0.20 → 0.0.21
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/.gitignore +1 -0
- data/README.md +1 -7
- data/lib/shexecutor/version.rb +1 -1
- data/shexecutor.gemspec +5 -4
- data/spec/executor_spec.rb +133 -67
- metadata +27 -27
- data/Gemfile.lock +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b48ef2c0244538d77d5a160f7eebe7e04f9b0873
|
4
|
+
data.tar.gz: 9271240df64b7fbe672eb5c767eeaad99652db6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4ee1b26893798c3442f4bbe2d6127fcb08e43cc8b802d03761635d23063a7a9bf4f98fbfc9d39d2852dba836cfa8cd564013b3935e0af1b8358c76f077371e45
|
7
|
+
data.tar.gz: 46eae96106d2f392485787b549d8c0469261de3890014d2c51c1c662ed0dbf82f4aede4c6f96a7a765972891f12c3fc95d4d5f9e83ad3412e2d565a14ca47b62
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -161,12 +161,6 @@ end
|
|
161
161
|
|
162
162
|
Please send feedback and comments to the author at:
|
163
163
|
|
164
|
-
Ernst van Graan <
|
164
|
+
Ernst van Graan <ernstvangraan@gmail.com>
|
165
165
|
|
166
166
|
Thanks to Sheldon Hearn for review and great ideas that unblocked complex challenges (https://rubygems.org/profiles/sheldonh).
|
167
|
-
|
168
|
-
1. Fork it ( https://github.com/[my-github-username]/executor/fork )
|
169
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
170
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
171
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
172
|
-
5. Create a new Pull Request
|
data/lib/shexecutor/version.rb
CHANGED
data/shexecutor.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = "shexecutor"
|
8
8
|
spec.version = SHExecutor::VERSION
|
9
9
|
spec.authors = ["Ernst van Graan"]
|
10
|
-
spec.email = ["
|
10
|
+
spec.email = ["ernstvangraan@gmail.com"]
|
11
11
|
spec.summary = %q{Execute shell commands easily and securely}
|
12
12
|
spec.description = %q{Implements process replacement, forking, protection from shell injection, and a variety of output options}
|
13
13
|
spec.homepage = ""
|
@@ -17,10 +17,11 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
|
+
spec.required_ruby_version = '>= 2.0'
|
20
21
|
|
21
|
-
spec.add_development_dependency 'bundler'
|
22
|
-
spec.add_development_dependency 'rake'
|
23
|
-
spec.add_development_dependency 'rspec'
|
22
|
+
spec.add_development_dependency 'bundler', "~> 1.12.5"
|
23
|
+
spec.add_development_dependency 'rake', "~> 11.2.2"
|
24
|
+
spec.add_development_dependency 'rspec', "~> 3.5.0"
|
24
25
|
spec.add_development_dependency 'simplecov'
|
25
26
|
spec.add_development_dependency 'simplecov-rcov'
|
26
27
|
spec.add_development_dependency 'byebug'
|
data/spec/executor_spec.rb
CHANGED
@@ -3,12 +3,29 @@ require 'shexecutor.rb'
|
|
3
3
|
require 'tempfile'
|
4
4
|
require 'mocks/kernel.rb'
|
5
5
|
require 'mocks/result.rb'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
def temp_file_path(seed)
|
9
|
+
file = Tempfile.new(seed)
|
10
|
+
path = file.path
|
11
|
+
file.close
|
12
|
+
FileUtils.touch(path)
|
13
|
+
File.chmod(0744, path)
|
14
|
+
path
|
15
|
+
end
|
16
|
+
|
17
|
+
def ignore_tempfile_bug_on_older_rubies(ex)
|
18
|
+
if ex.message == 'stream closed'
|
19
|
+
puts "INDETERMINATE RESULT: Tempfile bug on older versions of ruby. Test result unreliable, but not a failure per se. Subsequent runs should succeed"
|
20
|
+
else
|
21
|
+
fail
|
22
|
+
end
|
23
|
+
end
|
6
24
|
|
7
25
|
describe 'Executor' do
|
8
|
-
before :
|
9
|
-
@executable_file =
|
10
|
-
|
11
|
-
`echo "ls" >> #{@executable_file.path}`
|
26
|
+
before :each do
|
27
|
+
@executable_file = temp_file_path("testingargumenterror")
|
28
|
+
`echo "ls" >> #{@executable_file}`
|
12
29
|
end
|
13
30
|
|
14
31
|
context 'when initialized with no options' do
|
@@ -61,17 +78,21 @@ describe 'Executor' do
|
|
61
78
|
expect{
|
62
79
|
iut.validate
|
63
80
|
}.to raise_error(ArgumentError, "Application path not found")
|
64
|
-
|
65
|
-
iut = SHExecutor::Executor.new({:application_path =>
|
66
|
-
|
81
|
+
path = temp_file_path("testingargumenterror")
|
82
|
+
iut = SHExecutor::Executor.new({:application_path => path})
|
83
|
+
error_received = false
|
84
|
+
begin
|
67
85
|
iut.validate
|
68
|
-
|
86
|
+
rescue => ex
|
87
|
+
error_received = (ex.class == ArgumentError) and (ex.message.include?("Suspected injection vulnerability due to space in application_path or the object being marked as 'tainted' by Ruby. Turn off strict checking if you are sure by setting :protect_against_injection to false"))
|
88
|
+
end
|
89
|
+
expect(error_received).to eq(true)
|
69
90
|
end
|
70
91
|
end
|
71
92
|
|
72
93
|
context 'when initialized with valid options' do
|
73
94
|
it 'validate should not raise an exception' do
|
74
|
-
iut = SHExecutor::Executor.new({:application_path => @executable_file
|
95
|
+
iut = SHExecutor::Executor.new({:application_path => @executable_file, :protect_against_injection => false})
|
75
96
|
iut.validate
|
76
97
|
end
|
77
98
|
end
|
@@ -209,74 +230,102 @@ describe 'Executor' do
|
|
209
230
|
|
210
231
|
context 'when asked to execute and block' do
|
211
232
|
it 'should raise a Timeout::Error if a timeout is specified and the process does not exit before' do
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
233
|
+
begin
|
234
|
+
test_command = "/bin/sleep"
|
235
|
+
test_params = ["5"]
|
236
|
+
iut = SHExecutor::Executor.new({:timeout => 1, :wait_for_completion => true, :application_path => test_command, :params => test_params})
|
237
|
+
before = Time.now
|
238
|
+
expect {
|
239
|
+
iut.execute
|
240
|
+
}.to raise_error(Timeout::Error, "execution expired")
|
241
|
+
after = Time.now
|
242
|
+
expect(after - before).to be < 2.1
|
243
|
+
rescue IOError => ex
|
244
|
+
ignore_tempfile_bug_on_older_rubies(ex)
|
245
|
+
end
|
221
246
|
end
|
222
247
|
|
223
248
|
it 'should kill the subprocess when a TimeoutError is raised' do
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
249
|
+
begin
|
250
|
+
test_command = "/bin/sleep"
|
251
|
+
test_params = ["2"]
|
252
|
+
iut = SHExecutor::Executor.new({:timeout => 1, :wait_for_completion => true, :application_path => test_command, :params => test_params})
|
253
|
+
expect(Process).to receive(:kill)
|
254
|
+
expect {
|
255
|
+
iut.execute
|
256
|
+
}.to raise_error(Timeout::Error, "execution expired")
|
257
|
+
rescue IOError => ex
|
258
|
+
ignore_tempfile_bug_on_older_rubies(ex)
|
259
|
+
end
|
231
260
|
end
|
232
261
|
|
233
262
|
it 'should call run_process with the command and parameters specified' do
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
263
|
+
begin
|
264
|
+
test_command = "/bin/ls"
|
265
|
+
test_params = ["/tmp/"]
|
266
|
+
iut = SHExecutor::Executor.new({:wait_for_completion => true, :application_path => test_command, :params => test_params})
|
267
|
+
stdin = stdout = stderr = StringIO.new
|
268
|
+
expect(iut).to receive(:run_process).with(test_command, *test_params).and_return([stdout, stderr, Result.new(true)])
|
269
|
+
iut.execute
|
270
|
+
rescue IOError => ex
|
271
|
+
ignore_tempfile_bug_on_older_rubies(ex)
|
272
|
+
end
|
240
273
|
end
|
241
274
|
|
242
275
|
it 'should use run_process with the command' do
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
276
|
+
begin
|
277
|
+
test_command = "/bin/ls"
|
278
|
+
iut = SHExecutor::Executor.new({:wait_for_completion => true, :application_path => test_command})
|
279
|
+
stdin = stdout = stderr = StringIO.new
|
280
|
+
expect(iut).to receive(:run_process).with(test_command).and_return([stdout, stderr, Result.new(true)])
|
281
|
+
iut.execute
|
282
|
+
rescue IOError => ex
|
283
|
+
ignore_tempfile_bug_on_older_rubies(ex)
|
284
|
+
end
|
248
285
|
end
|
249
286
|
|
250
287
|
it 'should block until completion' do
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
288
|
+
begin
|
289
|
+
test_command = "/bin/sleep"
|
290
|
+
test_params = ["2"]
|
291
|
+
iut = SHExecutor::Executor.new({:wait_for_completion => true, :application_path => test_command, :params => test_params})
|
292
|
+
before = Time.now
|
293
|
+
iut.execute
|
294
|
+
after = Time.now
|
295
|
+
expect(after - before).to be > 2
|
296
|
+
rescue IOError => ex
|
297
|
+
ignore_tempfile_bug_on_older_rubies(ex)
|
298
|
+
end
|
258
299
|
end
|
259
300
|
|
260
301
|
it 'should block until completion and still have access to the ouput' do
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
302
|
+
begin
|
303
|
+
path = temp_file_path("testingargumenterror")
|
304
|
+
`echo "sleep 2" >> #{path}`
|
305
|
+
`echo "echo 'this did run'" >> #{path}`
|
306
|
+
sleep 1
|
307
|
+
iut = SHExecutor::Executor.new({:protect_against_injection => false, :wait_for_completion => true, :application_path => path})
|
308
|
+
before = Time.now
|
309
|
+
iut.execute
|
310
|
+
iut.flush
|
311
|
+
expect(iut.stdout).to eq("this did run\n")
|
312
|
+
after = Time.now
|
313
|
+
expect(after - before).to be > 2
|
314
|
+
rescue IOError => ex
|
315
|
+
ignore_tempfile_bug_on_older_rubies(ex)
|
316
|
+
end
|
273
317
|
end
|
274
318
|
|
275
319
|
it 'should validate' do
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
320
|
+
begin
|
321
|
+
iut = SHExecutor::Executor.new({:wait_for_completion => true})
|
322
|
+
expect{
|
323
|
+
iut.execute
|
324
|
+
}.to raise_error(ArgumentError, "No application path provided")
|
325
|
+
|
326
|
+
rescue IOError => ex
|
327
|
+
ignore_tempfile_bug_on_older_rubies(ex)
|
328
|
+
end
|
280
329
|
end
|
281
330
|
end
|
282
331
|
|
@@ -311,9 +360,15 @@ describe 'Executor' do
|
|
311
360
|
|
312
361
|
it 'should raise an exception if one of the file operations fails' do
|
313
362
|
@stdout_test_path = "/tmp/thisdirectorydoesnotexistdshlgh58iyg89rlehg8y/gn.dfllgyls54gh57479gh"
|
314
|
-
|
363
|
+
error_received = false
|
364
|
+
begin
|
315
365
|
execute_stdout_test_command
|
316
|
-
|
366
|
+
rescue => ex
|
367
|
+
error_received = (ex.class == Errno::ENOENT) and
|
368
|
+
(ex.message.include?("No such file or directory")) and
|
369
|
+
(ex.message.include?("/tmp/thisdirectorydoesnotexistdshlgh58iyg89rlehg8y/gn.dfllgyls54gh57479gh"))
|
370
|
+
end
|
371
|
+
expect(error_received).to eq(true)
|
317
372
|
end
|
318
373
|
end
|
319
374
|
|
@@ -333,24 +388,34 @@ describe 'Executor' do
|
|
333
388
|
end
|
334
389
|
|
335
390
|
it 'should append stderr to the file specified, and create it if it does not exist' do
|
336
|
-
expect(execute_stderr_test_command
|
391
|
+
expect(execute_stderr_test_command.include?("/tmp/thisfiledoesnotexistsatgup80wh0hgoefhgohuo4whg4whg4w5hg0")).to eq(true)
|
392
|
+
expect(execute_stderr_test_command.include?("No such file or directory")).to eq(true)
|
337
393
|
end
|
338
394
|
|
339
395
|
it 'should append stderr to the file specified, if it exists' do
|
340
396
|
`echo "line 1" >> #{@stderr_test_path}`
|
341
|
-
expect(execute_stderr_test_command
|
397
|
+
expect(execute_stderr_test_command.include?("line 1")).to eq(true)
|
398
|
+
expect(execute_stderr_test_command.include?("/tmp/thisfiledoesnotexistsatgup80wh0hgoefhgohuo4whg4whg4w5hg0")).to eq(true)
|
399
|
+
expect(execute_stderr_test_command.include?("No such file or directory")).to eq(true)
|
342
400
|
end
|
343
401
|
|
344
402
|
it 'should delete if exists and create the specified file, then write to it if append is not set' do
|
345
403
|
`echo "line 1" >> #{@stderr_test_path}`
|
346
|
-
expect(execute_stderr_test_command(false)
|
404
|
+
expect(execute_stderr_test_command(false).include?("/tmp/thisfiledoesnotexistsatgup80wh0hgoefhgohuo4whg4whg4w5hg0")).to eq(true)
|
405
|
+
expect(execute_stderr_test_command(false).include?("No such file or directory")).to eq(true)
|
347
406
|
end
|
348
407
|
|
349
408
|
it 'should raise an exception if one of the file operations fails' do
|
350
409
|
@stderr_test_path = "/tmp/thisdirectorydoesnotexistdshlgh58iyg89rlehg8y/gn.dfllgyls54gh57479gh"
|
351
|
-
|
410
|
+
error_received = false
|
411
|
+
begin
|
352
412
|
execute_stderr_test_command
|
353
|
-
|
413
|
+
rescue => ex
|
414
|
+
error_received = (ex.class == Errno::ENOENT) and
|
415
|
+
(ex.message.include?("No such file or directory")) and
|
416
|
+
(ex.message.include?("/tmp/thisdirectorydoesnotexistdshlgh58iyg89rlehg8y/gn.dfllgyls54gh57479gh"))
|
417
|
+
end
|
418
|
+
expect(error_received).to eq(true)
|
354
419
|
end
|
355
420
|
end
|
356
421
|
|
@@ -372,7 +437,8 @@ describe 'Executor' do
|
|
372
437
|
iut.execute
|
373
438
|
iut.flush
|
374
439
|
expect(iut.stdout).to be_nil
|
375
|
-
expect(iut.stderr
|
440
|
+
expect(iut.stderr.include?("/tmp/thisfiledoesnotexistsatgup80wh0hgoefhgohuo4whg4whg4w5hg0")).to eq(true)
|
441
|
+
expect(iut.stderr.include?("No such file or directory")).to eq(true)
|
376
442
|
end
|
377
443
|
end
|
378
444
|
end
|
metadata
CHANGED
@@ -1,110 +1,109 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shexecutor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ernst van Graan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 1.12.5
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 1.12.5
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 11.2.2
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 11.2.2
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 3.5.0
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 3.5.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: simplecov
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: simplecov-rcov
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: byebug
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- -
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
description: Implements process replacement, forking, protection from shell injection,
|
98
98
|
and a variety of output options
|
99
99
|
email:
|
100
|
-
-
|
100
|
+
- ernstvangraan@gmail.com
|
101
101
|
executables: []
|
102
102
|
extensions: []
|
103
103
|
extra_rdoc_files: []
|
104
104
|
files:
|
105
|
-
- .gitignore
|
105
|
+
- ".gitignore"
|
106
106
|
- Gemfile
|
107
|
-
- Gemfile.lock
|
108
107
|
- LICENSE.txt
|
109
108
|
- README.md
|
110
109
|
- Rakefile
|
@@ -125,17 +124,17 @@ require_paths:
|
|
125
124
|
- lib
|
126
125
|
required_ruby_version: !ruby/object:Gem::Requirement
|
127
126
|
requirements:
|
128
|
-
- -
|
127
|
+
- - ">="
|
129
128
|
- !ruby/object:Gem::Version
|
130
|
-
version: '0'
|
129
|
+
version: '2.0'
|
131
130
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
131
|
requirements:
|
133
|
-
- -
|
132
|
+
- - ">="
|
134
133
|
- !ruby/object:Gem::Version
|
135
134
|
version: '0'
|
136
135
|
requirements: []
|
137
136
|
rubyforge_project:
|
138
|
-
rubygems_version: 2.
|
137
|
+
rubygems_version: 2.4.8
|
139
138
|
signing_key:
|
140
139
|
specification_version: 4
|
141
140
|
summary: Execute shell commands easily and securely
|
@@ -144,3 +143,4 @@ test_files:
|
|
144
143
|
- spec/mocks/kernel.rb
|
145
144
|
- spec/mocks/result.rb
|
146
145
|
- spec/spec_helper.rb
|
146
|
+
has_rdoc:
|
data/Gemfile.lock
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
shexecutor (0.0.19)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
byebug (4.0.5)
|
10
|
-
columnize (= 0.9.0)
|
11
|
-
columnize (0.9.0)
|
12
|
-
diff-lcs (1.2.5)
|
13
|
-
docile (1.1.5)
|
14
|
-
json (1.8.2)
|
15
|
-
rake (10.4.2)
|
16
|
-
rspec (3.2.0)
|
17
|
-
rspec-core (~> 3.2.0)
|
18
|
-
rspec-expectations (~> 3.2.0)
|
19
|
-
rspec-mocks (~> 3.2.0)
|
20
|
-
rspec-core (3.2.3)
|
21
|
-
rspec-support (~> 3.2.0)
|
22
|
-
rspec-expectations (3.2.1)
|
23
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
24
|
-
rspec-support (~> 3.2.0)
|
25
|
-
rspec-mocks (3.2.1)
|
26
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
27
|
-
rspec-support (~> 3.2.0)
|
28
|
-
rspec-support (3.2.2)
|
29
|
-
simplecov (0.10.0)
|
30
|
-
docile (~> 1.1.0)
|
31
|
-
json (~> 1.8)
|
32
|
-
simplecov-html (~> 0.10.0)
|
33
|
-
simplecov-html (0.10.0)
|
34
|
-
simplecov-rcov (0.2.3)
|
35
|
-
simplecov (>= 0.4.1)
|
36
|
-
|
37
|
-
PLATFORMS
|
38
|
-
ruby
|
39
|
-
|
40
|
-
DEPENDENCIES
|
41
|
-
bundler
|
42
|
-
byebug
|
43
|
-
rake
|
44
|
-
rspec
|
45
|
-
shexecutor!
|
46
|
-
simplecov
|
47
|
-
simplecov-rcov
|