shell_mock 0.4.0 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0774052a9e5d9c22ec4c25344e620d68cddc8604
4
- data.tar.gz: 76f022bcb48ff0558e5f4e4564a9a0ff63ddc30c
3
+ metadata.gz: b756c372c9477ca0a21a3894fb4d07c35e87c14e
4
+ data.tar.gz: 565cb68f40d84a3f2d97ccaa50cad9aa41f16eb1
5
5
  SHA512:
6
- metadata.gz: 5ce25833d01a646e100d285ce32f9810e15f348d760db2dacd669c8f045c600a16475026429226d6e10b7086c79485bfe73b0c48e2217bc272960c8eea6c479b
7
- data.tar.gz: 1f0547eb74bbfd0296a5ad37e07b66eb15ce5f516ff78ad2c2f1abb4acbe792d4fb51a3d3c5614b294a8d164cf0c7ca8066ce8a128ac10078c6fa1fba494bd46
6
+ metadata.gz: 40cf06dcafcc3e976cedac4a59623a1d47fc4c4f90f437a149d90f26ef62a3b200b6a342273bdd96036070107fa031d234a34a6fc56b457c9b0be99645257383
7
+ data.tar.gz: 9cdd1c5d0e1a1d8630aa03506493b2e847ad142fe47b4a56bfd5623522b1e8268369e045ea55fa9518f596b77a002730d3e50b5dc4e1d7597848b4a5e87baf5c
data/CHANGELOG.md CHANGED
@@ -1,12 +1,20 @@
1
1
  ## ROADMAP 1.0.0
2
2
 
3
- * add `CommandStub#with_side_effect(&blk)` for specifying desired side effects
4
- * add `CommandStub#with_stdout(str)` & `CommandStub#with_stderr(str)`. these will work differently for backtick than it will for system & exec.
3
+ * convert `CommandStub#and_exit` to `CommandStub#will_exit`
4
+ * convert `CommandStub#and_output` to `CommandStub#will_output`
5
+ * convert `CommandStub#and_return` to `CommandStub#will_return`
6
+ * add `CommandStub#will_cause(&blk)` for specifying desired side effects
7
+ * add `CommandStub#will_stdout(str)` & `CommandStub#will_stderr(str)`. these will work differently for backtick than it will for system & exec.
5
8
  * maybe add `CommandStub#with_stdin(str)` for `spawn`?
6
9
 
10
+ ## RELEASE 0.5.0
11
+
12
+ * FEATURE: `CommandStub#and_output` can be used on command stubs to set the output of a command without setting the exit status.
13
+ * ENHANCEMENT: `Kernel#spawn`, `Kernel.spawn`, & `Process.spawn` are now implemented well enough that `Open3.capture3` behaves as though spawn is not being monkey-patched when ShellMock is enabled (and therefore, spawn most definitely is being monkey-patched). This should apply to all of `Open3`'s methods, since they all delegate to `Open3.popen_run` or `Open3.pipeline_run`, both of which internally use `Kernel#spawn`, **however I only have a spec for `Open3.capture3`**.
14
+
7
15
  ## RELEASE 0.4.0
8
16
 
9
- * FEATURE: `Kernel#spawn` and `Kernel.spawn` are now supported, which means all of Open3 is, as all of that library eventually results in a `spawn` call.
17
+ * FEATURE: `Kernel#spawn` and `Kernel.spawn` are now supported
10
18
 
11
19
  ## RELEASE 0.3.3
12
20
 
data/README.md CHANGED
@@ -1,50 +1,80 @@
1
1
  # ShellMock
2
+ [![Gem Version](https://badge.fury.io/rb/shell_mock.png)](http://badge.fury.io/rb/shell_mock)
3
+ [![Build Status](https://secure.travis-ci.org/yarmiganosca/shell_mock.png)](http://travis-ci.org/yarmiganosca/shell_mock)
2
4
 
3
5
  It's [webmock](http://github.com/bblimke/webmock) for shell commands. It's pretty simple. You can do things like this:
4
6
 
5
7
  ```ruby
6
8
  require 'shell_mock/rspec'
7
9
 
8
- describe 'something' do
9
- stub = ShellMock.stub_command('ls')
10
+ RSpec.describe "shelling out to run 'ls'" do
11
+ before { ShellMock.enable }
12
+ after { ShellMock.disable }
10
13
 
11
- expect(system('ls')).to eq true
14
+ let(:stub) { ShellMock.stub_command('ls') }
12
15
 
13
- expect(stub).to have_been_called
16
+ it "works"
17
+ expect(system('ls')).to eq true
18
+
19
+ expect(stub).to have_been_called
20
+ end
14
21
  end
15
22
  ```
16
23
 
17
- Currently, `` ` ``, `exec`, and `system` are supported. Nothing in the `Open3` standard library module is currently supported.
24
+ This:
25
+ 1. enables ShellMock's monkey patches during the test
26
+ 2. creates a command stub that will match the command `"ls"` (by default it will exit `0` and have no output)
27
+ 3. shells out to run `"ls"` (in this case using `Kernel#system`)
28
+ 4. correctly expects that our command stub for `"ls"` will have recorded an invocation
18
29
 
19
- ### More complex expectations are also supported.
30
+ ### You can narrow what invocations are matched to your command stub:
20
31
 
21
- Called exactly once: `expect(stub).to have_been_called.once`
32
+ **Match env vars as well as the command:** `ShellMock.stub_command('ls').with_env({'FOO' => 'bar'})`
22
33
 
23
- Not called: `expect(stub).to_not have_been_called` or `expect(stub).to have_been_called.never`
34
+ **Provide a more complete invocation:** `ShellMock.stub_command('ls $HOME')`
24
35
 
25
- Called exactly `n` times: `expect(stub).to have_been_called.times(n)`
36
+ Shelling out to run `"ls"` won't match this command stub, but shelling out to run `"ls $HOME"` will. ShellMock always matches as strictly as possible, so if you stubbed `"ls"` and `"ls $HOME"`, invocations of `"ls $HOME'` would only ever match against the latter.
26
37
 
27
- Called more than `n` times: `expect(stub).to have_been_called.more_than(n)`
38
+ ### Setting the behavior of the command invocation:
28
39
 
29
- Called fewer than `n` times: `expect(stub).to have_been_called.fewer_than(n)`
40
+ **Have the mock command invocation write to stdout:** `ShellMock.stub_command('ls').and_output("\n")`
30
41
 
31
- `less_than` is also an alias for `fewer_than`.
42
+ **Set the mock command invocation's exit status:** `ShellMock.stub_command('ls').and_exit(2)`
32
43
 
33
- Right now, only exact command string matches are supported.
44
+ If you want to both write to stdout and set the exit code (a common pair), `ShellMock.stub_command('ls').and_return("\n")` will both have the command invocation write the passed string to stdout, and will set the mock command invocation's exit status to `0`.
34
45
 
35
- ### You can also set the output of the command invocation:
46
+ ### Specifying the expected number of command invocations:
36
47
 
37
- ```ruby
38
- require 'shell_mock/rspec'
48
+ **Called exactly once:** `expect(stub).to have_been_called.once`
39
49
 
40
- describe 'something' do
41
- stub = ShellMock.stub_commmand('ls').and_return("\n")
50
+ **Not called:** `expect(stub).to have_been_called.never`
42
51
 
43
- expect(`ls`).to eq "\n"
52
+ **Not called (using RSpec expectation negation):** `expect(stub).to_not have_been_called`
44
53
 
45
- expect(stub).to have_been_called.once
46
- end
47
- ```
54
+ **Called exactly `n` times:** `expect(stub).to have_been_called.times(n)`
55
+
56
+ **Called more than `n` times:** `expect(stub).to have_been_called.more_than(n)`
57
+
58
+ **Called fewer than `n` times:** `expect(stub).to have_been_called.fewer_than(n)`
59
+
60
+ `less_than` can be used as an alias for `fewer_than`
61
+ ## Limitations
62
+
63
+ Currently, only exact string matches of the stubbed command string are supported. Basic regex support or more complex matching for arguments and flags may be added later.
64
+
65
+ ShellMock supports stubbing these ways of shelling out in Ruby:
66
+ * [`` Kernel#` ``](https://ruby-doc.org/core/Kernel.html#method-i-60) (aka "backticks")
67
+ * [`%x` command literal](https://ruby-doc.org/docs/ruby-doc-bundle/Manual/man-1.4/syntax.html#command) (which delegates to backticks)
68
+ * [`Kernel#system`](https://ruby-doc.org/core/Kernel.html#method-i-system)
69
+ * [`Kernel#exec`](https://ruby-doc.org/core/Kernel.html#method-i-exec)
70
+ * [`Kernel#spawn`](https://ruby-doc.org/core/Kernel.html#method-i-spawn)
71
+ * [`Process.spawn`](https://ruby-doc.org/core/Process.html#method-c-spawn)
72
+ * [the `Open3` module](https://ruby-doc.org/stdlib/libdoc/open3/rdoc/Open3.html) (since all its methods use `spawn`)
73
+
74
+ ShellMock currently DOES NOT support stubbing these ways of shelling out in Ruby (but will):
75
+ * [`IO.popen`](https://ruby-doc.org/core/IO.html#method-c-popen)
76
+ * [`PTY.spawn`](https://ruby-doc.org/stdlib/libdoc/pty/rdoc/PTY.html#method-c-spawn)
77
+ * [passing a string that starts with `"|"`](https://devver.wordpress.com/2009/07/13/a-dozen-or-so-ways-to-start-sub-processes-in-ruby-part-2/) to [`Kernel#open`](https://ruby-doc.org/core/Kernel.html#method-i-open)
48
78
 
49
79
  ## Installation
50
80
 
data/lib/shell_mock.rb CHANGED
@@ -24,32 +24,39 @@ module ShellMock
24
24
  @let_commands_run
25
25
  end
26
26
 
27
+ # smell; this is a mistake of a method that will only confuse people
27
28
  def self.dont_let_commands_run?
28
29
  !let_commands_run?
29
30
  end
30
31
 
31
32
  def self.enable
32
- ShellMock.monkey_patches.each do |patch|
33
- patch.enable_for(Kernel.eigenclass) unless Kernel.respond_to?(patch.alias_for_original, true)
34
- patch.enable_for(Kernel) unless Object.new.respond_to?(patch.alias_for_original, true)
35
- end
33
+ ShellMock.monkey_patches.each(&:enable)
34
+
35
+ @enabled = true
36
+
37
+ true
36
38
  end
37
39
 
38
40
  def self.disable
39
- ShellMock.monkey_patches.each do |patch|
40
- patch.disable_for(Kernel.eigenclass) if Kernel.respond_to?(patch.alias_for_original, true)
41
- patch.disable_for(Kernel) if Object.new.respond_to?(patch.alias_for_original, true)
42
- end
41
+ ShellMock.monkey_patches.each(&:disable)
43
42
 
44
43
  StubRegistry.clear
44
+
45
+ @enabled = false
46
+
47
+ true
48
+ end
49
+
50
+ def self.enabled?
51
+ @enabled
45
52
  end
46
53
 
47
54
  def self.monkey_patches
48
- [
49
- SpawnMonkeyPatch,
50
- SystemMonkeyPatch,
51
- ExecMonkeyPatch,
52
- BacktickMonkeyPatch
55
+ @monkey_patches ||= [
56
+ SpawnMonkeyPatch.new,
57
+ SystemMonkeyPatch.new,
58
+ ExecMonkeyPatch.new,
59
+ BacktickMonkeyPatch.new,
53
60
  ]
54
61
  end
55
62
  end
@@ -0,0 +1,33 @@
1
+ require 'shell_mock/monkey_patch'
2
+ require 'shell_mock/stub_registry'
3
+ require 'shell_mock/no_stub_specified'
4
+
5
+ module ShellMock
6
+ class BacktickMonkeyPatch < MonkeyPatch
7
+ def method_name
8
+ "`"
9
+ end
10
+
11
+ def interpolatable_name
12
+ :backtick
13
+ end
14
+
15
+ def override(command)
16
+ stub = StubRegistry.stub_matching({}, command, {})
17
+
18
+ if stub
19
+ stub.called_with({}, command, {})
20
+
21
+ stub.side_effect.call
22
+
23
+ __un_shell_mocked_backtick(stub.to_oneliner)
24
+ else
25
+ if ShellMock.let_commands_run?
26
+ __un_shell_mocked_backtick(command)
27
+ else
28
+ raise NoStubSpecified.new({}, command, {})
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,21 +1,26 @@
1
1
  module ShellMock
2
2
  class CallVerifier
3
3
  def initialize
4
- match_calls_when { |calls| calls.any? }
4
+ more_than(0)
5
5
  end
6
6
 
7
- def matches?(actual)
8
- @actual = actual
7
+ def times(n)
8
+ match_calls_when { |calls| calls == n }
9
9
 
10
- condition.call(actual.calls)
10
+ self
11
11
  end
12
12
 
13
- def failure_message
14
- "#{actual.command} was expected."
13
+ def fewer_than(n)
14
+ match_calls_when { |calls| calls < n }
15
+
16
+ self
15
17
  end
18
+ alias less_than fewer_than
16
19
 
17
- def failure_message_when_negated
18
- "#{actual.command} was not expected."
20
+ def more_than(n)
21
+ match_calls_when { |calls| calls > n }
22
+
23
+ self
19
24
  end
20
25
 
21
26
  def once
@@ -26,28 +31,23 @@ module ShellMock
26
31
  times(0)
27
32
  end
28
33
 
29
- def times(n)
30
- match_calls_when { |calls| calls.size == n }
34
+ def matches?(command_stub)
35
+ @command_stub = command_stub
31
36
 
32
- self
37
+ condition.call(command_stub.calls)
33
38
  end
34
39
 
35
- def fewer_than(n)
36
- match_calls_when { |calls| calls.size < n }
37
-
38
- self
40
+ def failure_message
41
+ "#{command_stub.command} was expected."
39
42
  end
40
- alias less_than fewer_than
41
-
42
- def more_than(n)
43
- match_calls_when { |calls| calls.size > n }
44
43
 
45
- self
44
+ def failure_message_when_negated
45
+ "#{command_stub.command} was not expected."
46
46
  end
47
47
 
48
48
  private
49
49
 
50
- attr_reader :actual, :condition
50
+ attr_reader :command_stub, :condition
51
51
 
52
52
  def match_calls_when(&blk)
53
53
  @condition = blk
@@ -3,7 +3,7 @@ require 'shell_mock/stub_registry'
3
3
 
4
4
  module ShellMock
5
5
  class CommandStub
6
- attr_reader :command, :expected_output, :exitstatus, :env, :options, :side_effect, :writer
6
+ attr_reader :command, :output, :exitstatus, :env, :options, :side_effect
7
7
 
8
8
  def initialize(command)
9
9
  @command = command
@@ -21,19 +21,24 @@ module ShellMock
21
21
  self
22
22
  end
23
23
 
24
- def with_option(option)
24
+ def with_options(options)
25
25
  @options = options
26
26
 
27
27
  self
28
28
  end
29
29
 
30
- def and_return(expected_output)
31
- @expected_output = expected_output
32
- @exitstatus = 0
30
+ def and_output(output)
31
+ @output = output
33
32
 
34
33
  self
35
34
  end
36
35
 
36
+ def and_return(output)
37
+ self.
38
+ and_output(output).
39
+ and_exit(0)
40
+ end
41
+
37
42
  def and_exit(exitstatus)
38
43
  @exitstatus = exitstatus
39
44
 
@@ -41,24 +46,26 @@ module ShellMock
41
46
  end
42
47
 
43
48
  def calls
44
- @calls ||= []
49
+ @calls ||= 0
45
50
 
46
51
  marshaled_signatures.each do |marshaled_signature|
47
- @calls << Marshal.load(marshaled_signature)
52
+ @calls += 1
48
53
  end
49
54
 
50
55
  @calls
51
56
  end
52
57
 
53
58
  def called_with(env, command, options)
54
- signature = Marshal.dump([env, command, options])
59
+ writer.puts("called\n")
60
+ end
55
61
 
56
- writer.puts(signature)
62
+ def to_oneliner
63
+ "echo '#{output}' && exit #{exitstatus}"
57
64
  end
58
65
 
59
66
  private
60
67
 
61
- attr_reader :reader
68
+ attr_reader :reader, :writer
62
69
 
63
70
  def marshaled_signatures
64
71
  messages = ""
@@ -0,0 +1,33 @@
1
+ require 'shell_mock/monkey_patch'
2
+ require 'shell_mock/stub_registry'
3
+ require 'shell_mock/no_stub_specified'
4
+
5
+ module ShellMock
6
+ class ExecMonkeyPatch < MonkeyPatch
7
+ def method_name
8
+ :exec
9
+ end
10
+
11
+ def override(env, command = nil, **options)
12
+ env, command = {}, env if command.nil?
13
+
14
+ # other arg manipulation can go here if necessary
15
+
16
+ stub = StubRegistry.stub_matching(env, command, options)
17
+
18
+ if stub
19
+ stub.called_with(env, command, options)
20
+
21
+ stub.side_effect.call
22
+
23
+ __un_shell_mocked_exec(stub.to_oneliner)
24
+ else
25
+ if ShellMock.let_commands_run?
26
+ __un_shell_mocked_exec(env, command, **options)
27
+ else
28
+ raise NoStubSpecified.new(env, command, options)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -2,42 +2,49 @@ require 'shell_mock/no_stub_specified'
2
2
 
3
3
  module ShellMock
4
4
  class MonkeyPatch
5
- attr_reader :original, :alias_for_original
5
+ def enable
6
+ enable_for(Kernel.eigenclass) unless Kernel.respond_to?(method_alias, true)
7
+ enable_for(Kernel) unless Object.new.respond_to?(method_alias, true)
8
+ end
9
+
10
+ def disable
11
+ disable_for(Kernel.eigenclass) if Kernel.respond_to?(method_alias, true)
12
+ disable_for(Kernel) if Object.new.respond_to?(method_alias, true)
13
+ end
14
+
15
+ private
6
16
 
7
- def initialize(original_name, interpolatable_name = original_name, &block)
8
- @original = original_name
9
- @alias_for_original = "__un_shell_mocked_#{interpolatable_name}"
10
- @replacement = "__shell_mocked_#{interpolatable_name}"
11
- @block = block
17
+ def method_alias
18
+ "__un_shell_mocked_#{interpolatable_name}"
12
19
  end
13
20
 
14
- def to_proc
15
- @block.to_proc
21
+ def interpolatable_name
22
+ method_name
16
23
  end
17
24
 
18
25
  def enable_for(class_or_module)
19
- class_or_module.send(:alias_method, alias_for_original, original)
26
+ class_or_module.send(:alias_method, method_alias, method_name)
20
27
 
21
28
  begin
22
29
  # so we don't have to see method redefinition warnings
23
- class_or_module.send(:remove_method, original)
30
+ class_or_module.send(:remove_method, method_name)
24
31
  rescue NameError
25
32
  end
26
33
 
27
- class_or_module.send(:define_method, original, &to_proc)
34
+ class_or_module.send(:define_method, method_name, &method(:override))
28
35
  end
29
36
 
30
37
  def disable_for(class_or_module)
31
38
  begin
32
39
  # so we don't have to see method redefinition warnings
33
- class_or_module.send(:remove_method, original)
40
+ class_or_module.send(:remove_method, method_name)
34
41
  rescue NameError
35
42
  end
36
43
 
37
- class_or_module.send(:alias_method, original, alias_for_original)
44
+ class_or_module.send(:alias_method, method_name, method_alias)
38
45
 
39
46
  begin
40
- class_or_module.send(:remove_method, alias_for_original)
47
+ class_or_module.send(:remove_method, method_alias)
41
48
  rescue NameError
42
49
  end
43
50
  end
@@ -1,91 +1,4 @@
1
- require 'shell_mock/monkey_patch'
2
- require 'shell_mock/stub_registry'
3
- require 'shell_mock/no_stub_specified'
4
-
5
- module ShellMock
6
- SpawnMonkeyPatch = MonkeyPatch.new(:spawn) do |env, command = nil, **options|
7
- env, command = {}, env if command.nil?
8
-
9
- # other arg manipulation can go here if necessary
10
-
11
- stub = StubRegistry.stub_matching(env, command, options)
12
-
13
- if stub
14
- stub.side_effect.call
15
- stub.called_with(env, command, options)
16
-
17
- __un_shell_mocked_spawn("exit #{stub.exitstatus}")
18
- else
19
- if ShellMock.let_commands_run?
20
- __un_shell_mocked_spawn(env, command, **options)
21
- else
22
- raise NoStubSpecified.new(env, command, options)
23
- end
24
- end
25
- end
26
-
27
- SystemMonkeyPatch = MonkeyPatch.new(:system) do |env, command = nil, **options|
28
- env, command = {}, env if command.nil?
29
-
30
- # other arg manipulation can go here if necessary
31
-
32
- stub = StubRegistry.stub_matching(env, command, options)
33
-
34
- if stub
35
- stub.side_effect.call
36
- stub.called_with(env, command, options)
37
- __un_shell_mocked_backtick("exit #{stub.exitstatus}")
38
-
39
- return stub.exitstatus == 0
40
- else
41
- if ShellMock.let_commands_run?
42
- __un_shell_mocked_system(env, command, **options)
43
- else
44
- raise NoStubSpecified.new(env, command, options)
45
- end
46
- end
47
- end
48
-
49
- # This feels very boilerplatey because Kernel::system and Kernel::exec
50
- # have very similar if not identical method signatures. I'm not sure
51
- # whether extracting the commonalities would be worth it or would just
52
- # confuse.
53
- ExecMonkeyPatch = MonkeyPatch.new(:exec) do |env, command = nil, **options|
54
- env, command = {}, env if command.nil?
55
-
56
- # other arg manipulation can go here if necessary
57
-
58
- stub = StubRegistry.stub_matching(env, command, options)
59
-
60
- if stub
61
- stub.side_effect.call
62
- stub.called_with(env, command, options)
63
-
64
- exit stub.exitstatus
65
- else
66
- if ShellMock.let_commands_run?
67
- __un_shell_mocked_exec(env, command, **options)
68
- else
69
- raise NoStubSpecified.new(env, command, options)
70
- end
71
- end
72
- end
73
-
74
- BacktickMonkeyPatch = MonkeyPatch.new('`', :backtick) do |command|
75
- stub = StubRegistry.stub_matching({}, command, {})
76
-
77
- if stub
78
- stub.side_effect.call
79
- stub.called_with({}, command, {})
80
- __un_shell_mocked_backtick("exit #{stub.exitstatus}")
81
-
82
- return stub.expected_output
83
- else
84
- if ShellMock.let_commands_run?
85
- __un_shell_mocked_backtick(command)
86
- else
87
- raise NoStubSpecified.new({}, command, {})
88
- end
89
- end
90
- end
91
- end
1
+ require 'shell_mock/spawn_monkey_patch'
2
+ require 'shell_mock/system_monkey_patch'
3
+ require 'shell_mock/backtick_monkey_patch'
4
+ require 'shell_mock/exec_monkey_patch'
@@ -0,0 +1,45 @@
1
+ require 'shell_mock/monkey_patch'
2
+ require 'shell_mock/stub_registry'
3
+ require 'shell_mock/no_stub_specified'
4
+
5
+ module ShellMock
6
+ class SpawnMonkeyPatch < MonkeyPatch
7
+ def method_name
8
+ :spawn
9
+ end
10
+
11
+ def override(env, command = nil, **options)
12
+ env, command = {}, env if command.nil?
13
+
14
+ # other arg manipulation can go here if necessary
15
+
16
+ stub = StubRegistry.stub_matching(env, command, options)
17
+
18
+ if stub
19
+ stub.called_with(env, command, options)
20
+
21
+ stub.side_effect.call
22
+
23
+ __un_shell_mocked_spawn(stub.to_oneliner, **options)
24
+ else
25
+ if ShellMock.let_commands_run?
26
+ __un_shell_mocked_spawn(env, command, **options)
27
+ else
28
+ raise NoStubSpecified.new(env, command, options)
29
+ end
30
+ end
31
+ end
32
+
33
+ def enable
34
+ enable_for(Process.eigenclass) unless Process.respond_to?(method_alias, true)
35
+
36
+ super
37
+ end
38
+
39
+ def disable
40
+ super
41
+
42
+ disable_for(Process.eigenclass) if Process.respond_to?(method_alias, true)
43
+ end
44
+ end
45
+ end
@@ -9,11 +9,14 @@ module ShellMock
9
9
 
10
10
  def stub_matching(env, command, options)
11
11
  matching_stubs = command_stubs.select do |command_stub|
12
- command_stub.env <= env &&
13
- command_stub.options <= options &&
14
- command_stub.command == command
12
+ command_stub.command == command &&
13
+ command_stub.env <= env &&
14
+ command_stub.options <= options
15
15
  end
16
16
 
17
+ # question: Should we increment all the stubs that match?
18
+ # What should users expect when they register a stub that
19
+ # wholly "covers" another already-registered stub?
17
20
  matching_stubs.max_by do |command_stub|
18
21
  [env.size, options.size]
19
22
  end
@@ -0,0 +1,33 @@
1
+ require 'shell_mock/monkey_patch'
2
+ require 'shell_mock/stub_registry'
3
+ require 'shell_mock/no_stub_specified'
4
+
5
+ module ShellMock
6
+ class SystemMonkeyPatch < MonkeyPatch
7
+ def method_name
8
+ :system
9
+ end
10
+
11
+ def override(env, command = nil, **options)
12
+ env, command = {}, env if command.nil?
13
+
14
+ # other arg manipulation can go here if necessary
15
+
16
+ stub = StubRegistry.stub_matching(env, command, options)
17
+
18
+ if stub
19
+ stub.called_with(env, command, options)
20
+
21
+ stub.side_effect.call
22
+
23
+ __un_shell_mocked_system(stub.to_oneliner)
24
+ else
25
+ if ShellMock.let_commands_run?
26
+ __un_shell_mocked_system(env, command, **options)
27
+ else
28
+ raise NoStubSpecified.new(env, command, options)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,3 +1,3 @@
1
1
  module ShellMock
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shell_mock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Hoffman
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-09-18 00:00:00.000000000 Z
11
+ date: 2018-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -114,15 +114,19 @@ files:
114
114
  - bin/console
115
115
  - bin/setup
116
116
  - lib/shell_mock.rb
117
+ - lib/shell_mock/backtick_monkey_patch.rb
117
118
  - lib/shell_mock/call_verifier.rb
118
119
  - lib/shell_mock/command_stub.rb
119
120
  - lib/shell_mock/core_ext/module.rb
121
+ - lib/shell_mock/exec_monkey_patch.rb
120
122
  - lib/shell_mock/monkey_patch.rb
121
123
  - lib/shell_mock/monkey_patches.rb
122
124
  - lib/shell_mock/no_stub_specified.rb
123
125
  - lib/shell_mock/rspec.rb
124
126
  - lib/shell_mock/rspec/matchers.rb
127
+ - lib/shell_mock/spawn_monkey_patch.rb
125
128
  - lib/shell_mock/stub_registry.rb
129
+ - lib/shell_mock/system_monkey_patch.rb
126
130
  - lib/shell_mock/version.rb
127
131
  - shell_mock.gemspec
128
132
  homepage: http://www.github.com/yarmiganosca/shell_mock