class RSpec::Mocks::MethodDouble

@private

Constants

IGNORED_BACKTRACE_LINE

@private

Attributes

method_name[R]

@private

object[R]

@private

Public Class Methods

new(object, method_name, proxy) click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 9
def initialize(object, method_name, proxy)
  @method_name = method_name
  @object = object
  @proxy = proxy

  @method_stasher = InstanceMethodStasher.new(object_singleton_class, @method_name)
  @method_is_proxied = false
  store(:expectations, [])
  store(:stubs, [])
end

Public Instance Methods

add_default_stub(*args, &implementation) click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 245
def add_default_stub(*args, &implementation)
  return if stubs.any?
  add_stub(*args, &implementation)
end
add_expectation(error_generator, expectation_ordering, expected_from, opts, &implementation) click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 221
def add_expectation(error_generator, expectation_ordering, expected_from, opts, &implementation)
  configure_method
  expectation = MessageExpectation.new(error_generator, expectation_ordering,
                                       expected_from, self, 1, opts, &implementation)
  expectations << expectation
  expectation
end
add_stub(error_generator, expectation_ordering, expected_from, opts={}, &implementation) click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 236
def add_stub(error_generator, expectation_ordering, expected_from, opts={}, &implementation)
  configure_method
  stub = MessageExpectation.new(error_generator, expectation_ordering, expected_from,
                                self, :any, opts, &implementation)
  stubs.unshift stub
  stub
end
any_instance_class_recorder_observing_method?(klass) click to toggle source
# File lib/rspec/mocks/method_double.rb, line 83
def any_instance_class_recorder_observing_method?(klass)
  return true if ::RSpec::Mocks.any_instance_recorder_for(klass).already_observing?(@method_name)
  superklass = klass.superclass
  return false if superklass.nil?
  any_instance_class_recorder_observing_method?(superklass)
end
build_expectation(error_generator, expectation_ordering) click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 230
def build_expectation(error_generator, expectation_ordering)
  expected_from = IGNORED_BACKTRACE_LINE
  MessageExpectation.new(error_generator, expectation_ordering, expected_from, self)
end
clear() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 215
def clear
  expectations.clear
  stubs.clear
end
configure_method() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 162
def configure_method
  @original_visibility = visibility_for_method
  @method_stasher.stash unless @method_is_proxied
  define_proxy_method
end
define_proxy_method() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 169
      def define_proxy_method
        return if @method_is_proxied

        object_singleton_class.class_eval <<-EOF, __FILE__, __LINE__ + 1
          def #{@method_name}(*args, &block)
            ::RSpec::Mocks.proxy_for(self).message_received :#{@method_name}, *args, &block
          end
          #{visibility_for_method}
        EOF
        @method_is_proxied = true
      end
expectations() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 21
def expectations
  self[:expectations]
end
object_singleton_class() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 157
def object_singleton_class
  class << @object; self; end
end
original_method() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 52
def original_method
  if @method_stasher.method_is_stashed?
    # Example: a singleton method defined on @object
    ::RSpec::Mocks.method_handle_for(@object, @method_stasher.stashed_method_name)
  elsif meth = original_unrecorded_any_instance_method
    # Example: a method that has been mocked through
    #   klass.any_instance.should_receive(:msg).and_call_original
    # any_instance.should_receive(:msg) causes the method to be
    # replaced with a proxy method, and then `and_call_original`
    # is recorded and played back on the object instance. We need
    # special handling here to get a handle on the original method
    # object rather than the proxy method.
    meth
  else
    # Example: an instance method defined on one of @object's ancestors.
    original_method_from_ancestry
  end
rescue NameError
  # We have no way of knowing if the object's method_missing
  # will handle this message or not...but we can at least try.
  # If it's not handled, a `NoMethodError` will be raised, just
  # like normally.
  ProcWithBlock.new(@object,@method_name)
end
original_method_from_ancestor(ancestors) click to toggle source
# File lib/rspec/mocks/method_double.rb, line 118
def original_method_from_ancestor(ancestors)
  klass, *rest = ancestors
  klass.instance_method(@method_name).bind(@object)
rescue NameError
  raise if rest.empty?
  original_method_from_ancestor(rest)
end
original_method_from_ancestry() click to toggle source

In Ruby 2.1, ancestors include the correct ancestors, including the singleton classes

# File lib/rspec/mocks/method_double.rb, line 93
def original_method_from_ancestry
  # Lookup in the ancestry, skipping over the singleton class itself
  original_method_from_ancestor(object_singleton_class.ancestors.drop(1))
end
original_method_from_superclass() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 128
def original_method_from_superclass
  @object.superclass.
          singleton_class.
          instance_method(@method_name).
          bind(@object)
end
original_unrecorded_any_instance_method() click to toggle source
# File lib/rspec/mocks/method_double.rb, line 77
def original_unrecorded_any_instance_method
  return nil unless any_instance_class_recorder_observing_method?(@object.class)
  alias_name = ::RSpec::Mocks.any_instance_recorder_for(@object.class).build_alias_method_name(@method_name)
  @object.method(alias_name)
end
raise_method_not_stubbed_error() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 263
def raise_method_not_stubbed_error
  raise MockExpectationError, "The method `#{method_name}` was not stubbed or was already unstubbed"
end
remove_single_stub(stub) click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 257
def remove_single_stub(stub)
  stubs.delete(stub)
  restore_original_method if stubs.empty? && expectations.empty?
end
remove_stub() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 251
def remove_stub
  raise_method_not_stubbed_error if stubs.empty?
  expectations.empty? ? reset : stubs.clear
end
reset() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 209
def reset
  restore_original_method
  clear
end
restore_original_method() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 187
def restore_original_method
  return unless @method_is_proxied

  object_singleton_class.__send__(:remove_method, @method_name)
  @method_stasher.restore
  restore_original_visibility

  @method_is_proxied = false
end
restore_original_visibility() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 198
def restore_original_visibility
  return unless object_singleton_class.method_defined?(@method_name) || object_singleton_class.private_method_defined?(@method_name)
  object_singleton_class.class_eval(@original_visibility, __FILE__, __LINE__)
end
stubs() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 26
def stubs
  self[:stubs]
end
verify() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 204
def verify
  expectations.each {|e| e.verify_messages_received}
end
visibility() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 31
def visibility
  if TestDouble === @object
    'public'
  elsif object_singleton_class.private_method_defined?(@method_name)
    'private'
  elsif object_singleton_class.protected_method_defined?(@method_name)
    'protected'
  else
    'public'
  end
end
visibility_for_method() click to toggle source

@private

# File lib/rspec/mocks/method_double.rb, line 182
def visibility_for_method
  "#{visibility} :#{method_name}"
end