Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make
any_instance
update existing instance stubs.
Fixes #613.
- Loading branch information
1 parent
37447c3
commit e00d6d7
Showing
16 changed files
with
227 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
module RSpec | ||
module Mocks | ||
module AnyInstance | ||
# @private | ||
# The `AnyInstance::Recorder` is responsible for redefining the klass's | ||
# instance method in order to add any stubs/expectations the first time | ||
# the method is called. It's not capable of updating a stub on an instance | ||
# that's already been previously stubbed (either directly, or via | ||
# `any_instance`). | ||
# | ||
# This proxy sits in front of the recorder and delegates both to it | ||
# and to the `RSpec::Mocks::Proxy` for each already mocked or stubbed | ||
# instance of the class, in order to propogates changes to the instances. | ||
# | ||
# Note that unlike `RSpec::Mocks::Proxy`, this proxy class is stateless | ||
# and is not persisted in `RSpec::Mocks.space`. | ||
# | ||
# Proxying for the message expectation fluent interface (typically chained | ||
# off of the return value of one of these methods) is provided by the | ||
# `FluentInterfaceProxy` class below. | ||
class Proxy | ||
def initialize(recorder, target_proxies) | ||
@recorder = recorder | ||
@target_proxies = target_proxies | ||
end | ||
|
||
def klass | ||
@recorder.klass | ||
end | ||
|
||
def stub(method_name_or_method_map, &block) | ||
if Hash === method_name_or_method_map | ||
method_name_or_method_map.each do |method_name, return_value| | ||
stub(method_name).and_return(return_value) | ||
end | ||
else | ||
perform_proxying(__method__, [method_name_or_method_map], block) do |proxy| | ||
proxy.add_stub(method_name_or_method_map, &block) | ||
end | ||
end | ||
end | ||
|
||
def unstub(method_name) | ||
perform_proxying(__method__, [method_name], nil) do |proxy| | ||
proxy.remove_stub_if_present(method_name) | ||
end | ||
end | ||
|
||
def stub_chain(*chain, &block) | ||
perform_proxying(__method__, chain, block) do |proxy| | ||
Mocks::StubChain.stub_chain_on(proxy.object, *chain, &block) | ||
end | ||
end | ||
|
||
def expect_chain(*chain, &block) | ||
perform_proxying(__method__, chain, block) do |proxy| | ||
Mocks::ExpectChain.expect_chain_on(proxy.object, *chain, &block) | ||
end | ||
end | ||
|
||
def should_receive(method_name, &block) | ||
perform_proxying(__method__, [method_name], block) do |proxy| | ||
proxy.add_message_expectation(method_name, &block) | ||
end | ||
end | ||
|
||
def should_not_receive(method_name, &block) | ||
perform_proxying(__method__, [method_name], block) do |proxy| | ||
proxy.add_message_expectation(method_name, &block).never | ||
end | ||
end | ||
|
||
private | ||
|
||
def perform_proxying(method_name, args, block, &target_proxy_block) | ||
recorder_value = @recorder.__send__(method_name, *args, &block) | ||
proxy_values = @target_proxies.map(&target_proxy_block) | ||
FluentInterfaceProxy.new([recorder_value] + proxy_values) | ||
end | ||
end | ||
|
||
# @private | ||
# Delegates messages to each of the given targets in order to | ||
# provide the fluent interface that is available off of message | ||
# expectations when dealing with `any_instance`. | ||
# | ||
# `targets` will typically contain 1 of the `AnyInstance::Recorder` | ||
# return values and N `MessageExpectation` instances (one per instance | ||
# of the `any_instance` klass). | ||
class FluentInterfaceProxy | ||
def initialize(targets) | ||
@targets = targets | ||
end | ||
|
||
def method_missing(*args, &block) | ||
return_values = @targets.map { |t| t.__send__(*args, &block) } | ||
FluentInterfaceProxy.new(return_values) | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.