class RSpec::Mocks::MethodDouble
@private
Constants
- RSpecPrependedModule
-
We subclass ‘Module` in order to be able to easily detect our prepended module.
Attributes
@private
@private
@private
@private
@private
Public Class Methods
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 9 def initialize(object, method_name, proxy) @method_name = method_name @object = object @proxy = proxy @original_visibility = nil @method_stasher = InstanceMethodStasher.new(object, method_name) @method_is_proxied = false @expectations = [] @stubs = [] end
Public Instance Methods
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 213 def add_default_stub(*args, &implementation) return if stubs.any? add_stub(*args, &implementation) end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 163 def add_expectation(error_generator, expectation_ordering, expected_from, opts, &implementation) configure_method expectation = message_expectation_class.new(error_generator, expectation_ordering, expected_from, self, :expectation, opts, &implementation) expectations << expectation expectation end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 199 def add_simple_expectation(method_name, response, error_generator, backtrace_line) setup_simple_method_double method_name, response, expectations, error_generator, backtrace_line end
A simple stub can only return a concrete value for a message, and cannot match on arguments. It is used as an optimization over ‘add_stub` / `add_expectation` where it is known in advance that this is all that will be required of a stub, such as when passing attributes to the `double` example method. They do not stash or restore existing method definitions.
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 194 def add_simple_stub(method_name, response) setup_simple_method_double method_name, response, stubs end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 178 def add_stub(error_generator, expectation_ordering, expected_from, opts={}, &implementation) configure_method stub = message_expectation_class.new(error_generator, expectation_ordering, expected_from, self, :stub, opts, &implementation) stubs.unshift stub stub end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 172 def build_expectation(error_generator, expectation_ordering) expected_from = IGNORED_BACKTRACE_LINE message_expectation_class.new(error_generator, expectation_ordering, expected_from, self) end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 149 def clear expectations.clear stubs.clear end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 59 def configure_method @original_visibility = visibility @method_stasher.stash unless @method_is_proxied define_proxy_method end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 66 def define_proxy_method return if @method_is_proxied save_original_implementation_callable! definition_target.class_exec(self, method_name, @original_visibility || visibility) do |method_double, method_name, visibility| if RUBY_VERSION.to_f > 3 && method_name == :respond_to? define_method(method_name) do |*args, &block| # This is a work around for a respond_to? check within kernel_inspect if caller_locations[0].label == "Kernel#inspect" super(*args, &block) else method_double.proxy_method_invoked(self, *args, &block) end end else define_method(method_name) do |*args, &block| method_double.proxy_method_invoked(self, *args, &block) end end # This can't be `if respond_to?(:ruby2_keywords, true)`, # see https://github.com/rspec/rspec-mocks/pull/1385#issuecomment-755340298 ruby2_keywords(method_name) if Module.private_method_defined?(:ruby2_keywords) __send__(visibility, method_name) end @method_is_proxied = true rescue FrozenError raise ArgumentError, "Cannot proxy frozen objects, rspec-mocks relies on proxies for method stubbing and expectations." end
The type of message expectation to create has been extracted to its own method so that subclasses can override it.
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 158 def message_expectation_class MessageExpectation end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 37 def method_missing_block block = Proc.new do |*args, &b| @object.__send__(:method_missing, @method_name, *args, &b) end block.ruby2_keywords if block.respond_to?(:ruby2_keywords) block end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 52 def object_singleton_class # We can't use @object.singleton_class because this method # creates a new singleton class if the object doesn't have one. class << @object; self; end end
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 21 def original_implementation_callable # If original method is not present, uses the `method_missing` # handler of the object. This accounts for cases where the user has not # correctly defined `respond_to?`. @original_implementation_callable ||= original_method || method_missing_block end
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 30 def original_method @original_method ||= @method_stasher.original_method || @proxy.original_method_handle_for(method_name) end
The implementation of the proxied method. Subclasses may override this method to perform additional operations.
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 100 def proxy_method_invoked(_obj, *args, &block) @proxy.message_received method_name, *args, &block end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 230 def raise_method_not_stubbed_error RSpec::Mocks.error_generator.raise_method_not_stubbed_error(method_name) end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 219 def remove_stub raise_method_not_stubbed_error if stubs.empty? remove_stub_if_present end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 225 def remove_stub_if_present expectations.empty? ? reset : stubs.clear end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 143 def reset restore_original_method clear end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 106 def restore_original_method return unless @method_is_proxied remove_method_from_definition_target if @method_stasher.method_is_stashed? @method_stasher.restore restore_original_visibility end @method_is_proxied = false rescue FrozenError return show_frozen_warning end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 133 def restore_original_visibility method_owner.__send__(@original_visibility, @method_name) end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 204 def setup_simple_method_double(method_name, response, collection, error_generator=nil, backtrace_line=nil) define_proxy_method me = SimpleMessageExpectation.new(method_name, response, error_generator, backtrace_line) collection.unshift me me end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 122 def show_frozen_warning RSpec.warn_with( "WARNING: rspec-mocks was unable to restore the original `#{@method_name}` " \ "method on #{@object.inspect} because it has been frozen. If you reuse this " \ "object, `#{@method_name}` will continue to respond with its stub implementation.", :call_site => nil, :use_spec_location_as_call_site => true ) end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 138 def verify expectations.each { |e| e.verify_messages_received } end
@private
# File rspec-mocks/lib/rspec/mocks/method_double.rb, line 47 def visibility @proxy.visibility_for(@method_name) end