class RSpec::Mocks::AnyInstance::Recorder
def already_observing?(method_name)
def already_observing?(method_name) @observed_methods.include?(method_name) end
def backup_method!(method_name)
def backup_method!(method_name) alias_method_name = build_alias_method_name(method_name) @klass.class_eval do if method_defined?(method_name) alias_method alias_method_name, method_name end end end
def build_alias_method_name(method_name)
def build_alias_method_name(method_name) "__#{method_name}_without_any_instance__" end
def each_expectation_filfilled?
def each_expectation_filfilled? @message_chains.all? do |method_name, chain| chain.expectation_filfilled? end end
def has_expectation?(method_name)
def has_expectation?(method_name) @message_chains[method_name].is_a?(ExpectationChain) end
def initialize(klass)
def initialize(klass) @message_chains = {} @observed_methods = [] @played_methods = {} @klass = klass @expectation_set = false end
def instance_that_received(method_name)
def instance_that_received(method_name) @played_methods[method_name] end
def mark_invoked!(method_name)
def mark_invoked!(method_name) backup_method!(method_name) @klass.class_eval(<<-EOM, __FILE__, __LINE__) def #{method_name}(*args, &blk) method_name = :#{method_name} current_instance = self invoked_instance = self.class.__recorder.instance_that_received(method_name) raise RSpec::Mocks::MockExpectationError, "The message '#{method_name}' was received by \#{self.inspect} but has already been received by \#{invoked_instance}" end EOM end
def observe!(method_name)
def observe!(method_name) stop_observing!(method_name) if already_observing?(method_name) @observed_methods << method_name backup_method!(method_name) @klass.class_eval(<<-EOM, __FILE__, __LINE__) def #{method_name}(*args, &blk) self.class.__recorder.playback!(self, :#{method_name}) self.send(:#{method_name}, *args, &blk) end EOM end
def playback!(instance, method_name)
def playback!(instance, method_name) RSpec::Mocks::space.add(instance) @message_chains[method_name].playback!(instance) @played_methods[method_name] = instance received_expected_message!(method_name) if has_expectation?(method_name) end
def received_expected_message!(method_name)
def received_expected_message!(method_name) @message_chains[method_name].expectation_fulfilled! restore_method!(method_name) mark_invoked!(method_name) end
def remove_dummy_method!(method_name)
def remove_dummy_method!(method_name) @klass.class_eval do remove_method method_name end end
def restore_method!(method_name)
def restore_method!(method_name) if @klass.method_defined?(build_alias_method_name(method_name)) restore_original_method!(method_name) else remove_dummy_method!(method_name) end end
def restore_original_method!(method_name)
def restore_original_method!(method_name) alias_method_name = build_alias_method_name(method_name) @klass.class_eval do alias_method method_name, alias_method_name remove_method alias_method_name end end
def should_receive(method_name, *args, &block)
def should_receive(method_name, *args, &block) observe!(method_name) @expectation_set = true @message_chains[method_name] = ExpectationChain.new(method_name, *args, &block) end
def stop_all_observation!
def stop_all_observation! @observed_methods.each do |method_name| restore_method!(method_name) end end
def stop_observing!(method_name)
def stop_observing!(method_name) restore_method!(method_name) @observed_methods.delete(method_name) end
def stub(method_name, *args, &block)
def stub(method_name, *args, &block) observe!(method_name) @message_chains[method_name] = StubChain.new(method_name, *args, &block) end
def unfulfilled_expectations
def unfulfilled_expectations @message_chains.map do |method_name, chain| method_name.to_s if chain.is_a?(ExpectationChain) unless chain.expectation_filfilled? end.compact end
def verify
def verify if @expectation_set && !each_expectation_filfilled? raise RSpec::Mocks::MockExpectationError, "Exactly one instance should have received the following message(s) but didn't: #{unfulfilled_expectations.sort.join(', ')}" end end