123456789_123456789_123456789_123456789_123456789_

Class: RSpec::Mocks::Proxy Private

Do not use. This class is for internal use only.
Relationships & Source Files
Namespace Children
Classes:
Extension / Inclusion / Inheritance Descendants
Subclasses:
RSpec::Mocks::PartialClassDoubleProxy, RSpec::Mocks::PartialDoubleProxy, RSpec::Mocks::ProxyForNil, RSpec::Mocks::TestDoubleProxy, RSpec::Mocks::VerifyingPartialClassDoubleProxy, RSpec::Mocks::VerifyingPartialDoubleProxy, RSpec::Mocks::VerifyingProxy
Inherits: Object
Defined in: rspec-mocks/lib/rspec/mocks/proxy.rb

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Class Method Details

.prepended_modules_of(klass)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 244

def self.prepended_modules_of(klass)
  ancestors = klass.ancestors

  # `|| 0` is necessary for Ruby 2.0, where the singleton class
  # is only in the ancestor list when there are prepended modules.
  singleton_index = ancestors.index(klass) || 0

  ancestors[0, singleton_index]
end

Instance Attribute Details

#null_object?Boolean (readonly)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 45

def null_object?
  @null_object
end

#object (readonly)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 42

attr_reader :object

Instance Method Details

#add_message_expectation(method_name, opts = DEFAULT_MESSAGE_EXPECTATION_OPTS, &block)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 65

def add_message_expectation(method_name, opts=DEFAULT_MESSAGE_EXPECTATION_OPTS, &block)
  location = opts.fetch(:expected_from) { CallerFilter.first_non_rspec_line }
  meth_double = method_double_for(method_name)

  if null_object? && !block
    meth_double.add_default_stub(@error_generator, @order_group, location, opts) do
      @object
    end
  end

  meth_double.add_expectation @error_generator, @order_group, location, opts, &block
end

#add_simple_expectation(method_name, response, location)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 79

def add_simple_expectation(method_name, response, location)
  method_double_for(method_name).add_simple_expectation method_name, response, @error_generator, location
end

#add_simple_stub(method_name, response)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 140

def add_simple_stub(method_name, response)
  method_double_for(method_name).add_simple_stub method_name, response
end

#add_stub(method_name, opts = {}, &implementation)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 134

def add_stub(method_name, opts={}, &implementation)
  location = opts.fetch(:expected_from) { CallerFilter.first_non_rspec_line }
  method_double_for(method_name).add_stub @error_generator, @order_group, location, opts, &implementation
end

#as_null_object

Tells the object to ignore any messages that aren’t explicitly set as stubs or message expectations.

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 52

def as_null_object
  @null_object = true
  @object
end

#build_expectation(method_name)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 84

def build_expectation(method_name)
  meth_double = method_double_for(method_name)

  meth_double.build_expectation(
    @error_generator,
    @order_group
  )
end

#check_for_unexpected_arguments(expectation)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 117

def check_for_unexpected_arguments(expectation)
  @messages_received_mutex.synchronize do
    return if @messages_received.empty?

    return if @messages_received.any? { |method_name, args, _| expectation.matches?(method_name, *args) }

    name_but_not_args, others = @messages_received.partition do |(method_name, args, _)|
      expectation.matches_name_but_not_args(method_name, *args)
    end

    return if name_but_not_args.empty? && !others.empty?

    expectation.raise_unexpected_message_args_error(name_but_not_args.map { |args| args[1] })
  end
end

#ensure_can_be_proxied!(object)

Raises:

  • (ArgumentError)
[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 34

def ensure_can_be_proxied!(object)
  return unless object.is_a?(Symbol)

  msg = "Cannot proxy frozen objects. Symbols such as #{object} cannot be mocked or stubbed."
  raise ArgumentError, msg
end

#ensure_implemented(*_args)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 15

def ensure_implemented(*_args)
  # noop for basic proxies, see VerifyingProxy for behaviour.
end

#find_almost_matching_expectation(method_name, *args) (private)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 277

def find_almost_matching_expectation(method_name, *args)
  find_best_matching_expectation_for(method_name) do |expectation|
    expectation.matches_name_but_not_args(method_name, *args)
  end
end

#find_almost_matching_stub(method_name, *args) (private)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 301

def find_almost_matching_stub(method_name, *args)
  method_double_for(method_name).stubs.find { |stub| stub.matches_name_but_not_args(method_name, *args) }
end

#find_best_matching_expectation_for(method_name) (private)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 284

def find_best_matching_expectation_for(method_name)
  first_match = nil

  method_double_for(method_name).expectations.each do |expectation|
    next unless yield expectation
    return expectation unless expectation.called_max_times?
    first_match ||= expectation
  end

  first_match
end

#find_matching_expectation(method_name, *args) (private)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 270

def find_matching_expectation(method_name, *args)
  find_best_matching_expectation_for(method_name) do |expectation|
    expectation.matches?(method_name, *args)
  end
end

#find_matching_method_stub(method_name, *args) (private)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 296

def find_matching_method_stub(method_name, *args)
  method_double_for(method_name).stubs.find { |stub| stub.matches?(method_name, *args) }
end

#has_negative_expectation?(message) ⇒ Boolean

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 181

def has_negative_expectation?(message)
  method_double_for(message).expectations.find { |expectation| expectation.negative_expectation_for?(message) }
end

#message_received(message, *args, &block)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 195

def message_received(message, *args, &block)
  record_message_received message, *args, &block

  expectation = find_matching_expectation(message, *args)
  stub = find_matching_method_stub(message, *args)

  if (stub && expectation && expectation.called_max_times?) || (stub && !expectation)
    expectation.increase_actual_received_count! if expectation && expectation.actual_received_count_matters?
    if (expectation = find_almost_matching_expectation(message, *args))
      expectation.advise(*args) unless expectation.expected_messages_received?
    end
    stub.invoke(nil, *args, &block)
  elsif expectation
    expectation.unadvise(messages_arg_list)
    expectation.invoke(stub, *args, &block)
  elsif (expectation = find_almost_matching_expectation(message, *args))
    expectation.advise(*args) if null_object? unless expectation.expected_messages_received?

    if null_object? || !has_negative_expectation?(message)
      expectation.raise_unexpected_message_args_error([args])
    end
  elsif (stub = find_almost_matching_stub(message, *args))
    stub.advise(*args)
    raise_missing_default_stub_error(stub, [args])
  elsif Class === @object
    @object.superclass.__send__(message, *args, &block)
  else
    @object.__send__(:method_missing, message, *args, &block)
  end
end

#messages_arg_list

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 174

def messages_arg_list
  @messages_received_mutex.synchronize do
    @messages_received.map { |_, args, _| args }
  end
end

#method_double_for(message) (private)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 266

def method_double_for(message)
  @method_doubles[message.to_sym]
end

#method_double_if_exists_for_message(message)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 260

def method_double_if_exists_for_message(message)
  method_double_for(message) if @method_doubles.key?(message.to_sym)
end

#original_method_handle_for(_message)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 58

def original_method_handle_for(_message)
  nil
end

#prepended_modules_of_singleton_class

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 254

def prepended_modules_of_singleton_class
  @prepended_modules_of_singleton_class ||= RSpec::Mocks::Proxy.prepended_modules_of(@object.singleton_class)
end

#raise_missing_default_stub_error(expectation, args_for_multiple_calls)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 233

def raise_missing_default_stub_error(expectation, args_for_multiple_calls)
  @error_generator.raise_missing_default_stub_error(expectation, args_for_multiple_calls)
end

#raise_unexpected_message_error(method_name, args)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 228

def raise_unexpected_message_error(method_name, args)
  @error_generator.raise_unexpected_message_error method_name, args
end

#received_message?(method_name, *args, &block) ⇒ Boolean

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 167

def received_message?(method_name, *args, &block)
  @messages_received_mutex.synchronize do
    @messages_received.any? { |array| array == [method_name, args, block] }
  end
end

#record_message_received(message, *args, &block)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 186

def record_message_received(message, *args, &block)
  @order_group.invoked SpecificMessage.new(object, message, args)
  @messages_received_mutex.synchronize do
    @messages_received << [message, args, block]
  end
end

#remove_stub(method_name)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 145

def remove_stub(method_name)
  method_double_for(method_name).remove_stub
end

#remove_stub_if_present(method_name)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 150

def remove_stub_if_present(method_name)
  method_double_for(method_name).remove_stub_if_present
end

#replay_received_message_on(expectation, &block)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 94

def replay_received_message_on(expectation, &block)
  expected_method_name = expectation.message
  meth_double = method_double_for(expected_method_name)

  if meth_double.expectations.any?
    @error_generator.raise_expectation_on_mocked_method(expected_method_name)
  end

  unless null_object? || meth_double.stubs.any?
    @error_generator.raise_expectation_on_unstubbed_method(expected_method_name)
  end

  @messages_received_mutex.synchronize do
    @messages_received.each do |(actual_method_name, args, received_block)|
      next unless expectation.matches?(actual_method_name, *args)

      expectation.safe_invoke(nil)
      block.call(*args, &received_block) if block
    end
  end
end

#reset

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 160

def reset
  @messages_received_mutex.synchronize do
    @messages_received.clear
  end
end

#verify

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 155

def verify
  @method_doubles.each_value { |d| d.verify }
end

#visibility_for(_method_name)

[ GitHub ]

  
# File 'rspec-mocks/lib/rspec/mocks/proxy.rb', line 238

def visibility_for(_method_name)
  # This is the default (for test doubles). Subclasses override this.
  :public
end