Class: RSpec::Mocks::MethodDouble Private
Relationships & Source Files | |
Extension / Inclusion / Inheritance Descendants | |
Subclasses:
RSpec::Mocks::VerifyingExistingClassNewMethodDouble, RSpec::Mocks::VerifyingExistingMethodDouble, RSpec::Mocks::VerifyingMethodDouble
|
|
Inherits: | Object |
Defined in: | rspec-mocks/lib/rspec/mocks/method_double.rb |
Constant Summary
-
FROZEN_ERROR_MSG =
# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 6/can't modify frozen/
-
RSpecPrependedModule =
We subclass
Module
in order to be able to easily detect our prepended module.Class.new(Module)
Class Method Summary
- .new(object, method_name, proxy) ⇒ MethodDouble constructor Internal use only
Instance Attribute Summary
- #expectations readonly Internal use only
- #method_name readonly Internal use only
- #method_stasher readonly Internal use only
- #object readonly Internal use only
- #stubs readonly Internal use only
Instance Method Summary
- #add_default_stub(*args, &implementation) Internal use only
- #add_expectation(error_generator, expectation_ordering, expected_from, opts, &implementation) Internal use only
- #add_simple_expectation(method_name, response, error_generator, backtrace_line) Internal use only
-
#add_simple_stub(method_name, response)
Internal use only
A simple stub can only return a concrete value for a message, and cannot match on arguments.
- #add_stub(error_generator, expectation_ordering, expected_from, opts = {}, &implementation) Internal use only
- #build_expectation(error_generator, expectation_ordering) Internal use only
- #clear Internal use only
- #configure_method Internal use only
- #define_proxy_method Internal use only
-
#message_expectation_class
Internal use only
The type of message expectation to create has been extracted to its own method so that subclasses can override it.
- #method_missing_block Internal use only
- #object_singleton_class Internal use only
- #original_implementation_callable (also: #save_original_implementation_callable!) Internal use only
- #original_method Internal use only
-
#proxy_method_invoked(_obj, *args, &block)
Internal use only
The implementation of the proxied method.
- #raise_method_not_stubbed_error Internal use only
- #remove_stub Internal use only
- #remove_stub_if_present Internal use only
- #reset Internal use only
- #restore_original_method Internal use only
- #restore_original_visibility Internal use only
-
#save_original_implementation_callable!
Alias for #original_implementation_callable.
- #setup_simple_method_double(method_name, response, collection, error_generator = nil, backtrace_line = nil) Internal use only
- #show_frozen_warning Internal use only
- #verify Internal use only
- #visibility Internal use only
-
#definition_target
private
See additional method definition at line 255.
- #new_rspec_prepended_module private Internal use only
- #remove_method_from_definition_target private Internal use only
- #usable_rspec_prepended_module private Internal use only
Instance Attribute Details
#expectations (readonly)
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 9
attr_reader :method_name, :object, :expectations, :stubs, :method_stasher
#method_name (readonly)
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 9
attr_reader :method_name, :object, :expectations, :stubs, :method_stasher
#method_stasher (readonly)
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 9
attr_reader :method_name, :object, :expectations, :stubs, :method_stasher
#object (readonly)
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 9
attr_reader :method_name, :object, :expectations, :stubs, :method_stasher
#stubs (readonly)
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 9
attr_reader :method_name, :object, :expectations, :stubs, :method_stasher
Instance Method Details
#add_default_stub(*args, &implementation)
[ GitHub ]#add_expectation(error_generator, expectation_ordering, expected_from, opts, &implementation)
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 166
def add_expectation(error_generator, expectation_ordering, expected_from, opts, &implementation) configure_method expectation = .new(error_generator, expectation_ordering, expected_from, self, :expectation, opts, &implementation) expectations << expectation expectation end
#add_simple_expectation(method_name, response, error_generator, backtrace_line)
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 202
def add_simple_expectation(method_name, response, error_generator, backtrace_line) setup_simple_method_double method_name, response, expectations, error_generator, backtrace_line end
#add_simple_stub(method_name, response)
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.
# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 197
def add_simple_stub(method_name, response) setup_simple_method_double method_name, response, stubs end
#add_stub(error_generator, expectation_ordering, expected_from, opts = {}, &implementation)
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 181
def add_stub(error_generator, expectation_ordering, expected_from, opts={}, &implementation) configure_method stub = .new(error_generator, expectation_ordering, expected_from, self, :stub, opts, &implementation) stubs.unshift stub stub end
#build_expectation(error_generator, expectation_ordering)
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 175
def build_expectation(error_generator, expectation_ordering) expected_from = IGNORED_BACKTRACE_LINE .new(error_generator, expectation_ordering, expected_from, self) end
#clear
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 152
def clear expectations.clear stubs.clear end
#configure_method
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 61
def configure_method @original_visibility = visibility @method_stasher.stash unless @method_is_proxied define_proxy_method end
#define_proxy_method
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 68
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| define_method(method_name) do |*args, &block| method_double.proxy_method_invoked(self, *args, &block) 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 RuntimeError, TypeError => e # TODO: drop in favor of FrozenError in ruby 2.5+ # RuntimeError (and FrozenError) for ruby 2.x # TypeError for ruby 1.x if (defined?(FrozenError) && e.is_a?(FrozenError)) || FROZEN_ERROR_MSG === e. raise ArgumentError, "Cannot proxy frozen objects, rspec-mocks relies on proxies for method stubbing and expectations." end raise end
#definition_target (private)
See additional method definition at line 255.
# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 285
def definition_target @definition_target ||= usable_rspec_prepended_module || object_singleton_class end
#message_expectation_class
The type of message expectation to create has been extracted to its own method so that subclasses can override it.
# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 161
def MessageExpectation end
#method_missing_block
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 41
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
#new_rspec_prepended_module (private)
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 275
def new_rspec_prepended_module RSpecPrependedModule.new.tap do |mod| object_singleton_class.__send__ :prepend, mod end end
#object_singleton_class
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 56
def object_singleton_class class << @object; self; end end
#original_implementation_callable Also known as: #save_original_implementation_callable!
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 24
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?`, and also 1.8 which does not provide # method handles for missing methods even if `respond_to?` is correct. @original_implementation_callable ||= original_method || method_missing_block end
#original_method
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 34
def original_method @original_method ||= @method_stasher.original_method || @proxy.original_method_handle_for(method_name) end
#proxy_method_invoked(_obj, *args, &block)
The implementation of the proxied method. Subclasses may override this method to perform additional operations.
# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 97
def proxy_method_invoked(_obj, *args, &block) @proxy. method_name, *args, &block end
#raise_method_not_stubbed_error
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 233
def raise_method_not_stubbed_error RSpec::Mocks.error_generator.raise_method_not_stubbed_error(method_name) end
#remove_method_from_definition_target (private)
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 293
def remove_method_from_definition_target definition_target.__send__(:remove_method, @method_name) rescue NameError # This can happen when the method has been monkeyed with by # something outside RSpec. This happens, for example, when # `file.write` has been stubbed, and then `file.reopen(other_io)` # is later called, as `File#reopen` appears to redefine `write`. # # Note: we could avoid rescuing this by checking # `definition_target.instance_method(@method_name).owner == definition_target`, # saving us from the cost of the expensive exception, but this error is # extremely rare (it was discovered on 2014-12-30, only happens on # RUBY_VERSION < 2.0 and our spec suite only hits this condition once), # so we'd rather avoid the cost of that check for every method double, # and risk the rare situation where this exception will get raised. RSpec.warn_with( "WARNING: RSpec could not fully restore #{@object.inspect}." \ "#{@method_name}, possibly because the method has been redefined " \ "by something outside of RSpec." ) end
#remove_stub
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 222
def remove_stub raise_method_not_stubbed_error if stubs.empty? remove_stub_if_present end
#remove_stub_if_present
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 228
def remove_stub_if_present expectations.empty? ? reset : stubs.clear end
#reset
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 146
def reset restore_original_method clear end
#restore_original_method
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 103
def restore_original_method return unless @method_is_proxied remove_method_from_definition_target @method_stasher.restore if @method_stasher.method_is_stashed? restore_original_visibility @method_is_proxied = false rescue RuntimeError, TypeError => e # TODO: drop in favor of FrozenError in ruby 2.5+ # RuntimeError (and FrozenError) for ruby 2.x # TypeError for ruby 1.x if (defined?(FrozenError) && e.is_a?(FrozenError)) || FROZEN_ERROR_MSG === e. return show_frozen_warning end raise end
#restore_original_visibility
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 133
def restore_original_visibility return unless @original_visibility && MethodReference.method_defined_at_any_visibility?(object_singleton_class, @method_name) object_singleton_class.__send__(@original_visibility, method_name) end
#save_original_implementation_callable!
Alias for #original_implementation_callable.
# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 32
alias_method :save_original_implementation_callable!, :original_implementation_callable
#setup_simple_method_double(method_name, response, collection, error_generator = nil, backtrace_line = nil)
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 207
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
#show_frozen_warning
[ GitHub ]# 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
#usable_rspec_prepended_module (private)
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 259
def usable_rspec_prepended_module @proxy.prepended_modules_of_singleton_class.each do |mod| # If we have one of our modules prepended before one of the user's # modules that defines the method, use that, since our module's # definition will take precedence. return mod if RSpecPrependedModule === mod # If we hit a user module with the method defined first, # we must create a new prepend module, even if one exists later, # because ours will only take precedence if it comes first. return new_rspec_prepended_module if mod.method_defined?(method_name) end nil end
#verify
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 141
def verify expectations.each { |e| e. } end
#visibility
[ GitHub ]# File 'rspec-mocks/lib/rspec/mocks/method_double.rb', line 51
def visibility @proxy.visibility_for(@method_name) end