class Spec::Mocks::Proxy
def __add(sym)
def __add(sym) $rspec_mocks.add(@target) unless $rspec_mocks.nil? define_expected_method(sym) end
def add_message_expectation(expected_from, sym, opts={}, &block)
def add_message_expectation(expected_from, sym, opts={}, &block) __add sym @expectations << MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil, 1, opts) @expectations.last end
def add_negative_message_expectation(expected_from, sym, &block)
def add_negative_message_expectation(expected_from, sym, &block) __add sym @expectations << NegativeMessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil) @expectations.last end
def add_stub(expected_from, sym, opts={})
def add_stub(expected_from, sym, opts={}) __add sym @stubs.unshift MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, nil, :any, opts) @stubs.first end
def clear_expectations
def clear_expectations @expectations.clear end
def clear_proxied_methods
def clear_proxied_methods @proxied_methods.clear end
def clear_stubs
def clear_stubs @stubs.clear end
def define_expected_method(sym)
def define_expected_method(sym) visibility_string = "#{visibility(sym)} :#{sym}" if target_responds_to?(sym) && !target_metaclass.method_defined?(munge(sym)) munged_sym = munge(sym) target_metaclass.instance_eval do alias_method munged_sym, sym if method_defined?(sym.to_s) end @proxied_methods << sym end target_metaclass.class_eval(<<-EOF, __FILE__, __LINE__) def #{sym}(*args, &block) __mock_proxy.message_received :#{sym}, *args, &block end #{visibility_string} EOF end
def find_almost_matching_expectation(sym, *args)
def find_almost_matching_expectation(sym, *args) @expectations.find {|expectation| expectation.matches_name_but_not_args(sym, args)} end
def find_matching_expectation(sym, *args)
def find_matching_expectation(sym, *args) @expectations.find {|expectation| expectation.matches(sym, args)} end
def find_matching_method_stub(sym, *args)
def find_matching_method_stub(sym, *args) @stubs.find {|stub| stub.matches(sym, args)} end
def has_negative_expectation?(sym)
def has_negative_expectation?(sym) @expectations.detect {|expectation| expectation.negative_expectation_for?(sym)} end
def initialize(target, name, options={})
def initialize(target, name, options={}) @target = target @name = name @error_generator = ErrorGenerator.new target, name @expectation_ordering = OrderGroup.new @error_generator @expectations = [] @messages_received = [] @stubs = [] @proxied_methods = [] @options = options ? DEFAULT_OPTIONS.dup.merge(options) : DEFAULT_OPTIONS end
def message_received(sym, *args, &block)
def message_received(sym, *args, &block) if expectation = find_matching_expectation(sym, *args) expectation.invoke(args, block) elsif (stub = find_matching_method_stub(sym, *args)) if expectation = find_almost_matching_expectation(sym, *args) expectation.advise(args, block) unless expectation.expected_messages_received? end stub.invoke([], block) elsif expectation = find_almost_matching_expectation(sym, *args) expectation.advise(args, block) if null_object? unless expectation.expected_messages_received? raise_unexpected_message_args_error(expectation, *args) unless (has_negative_expectation?(sym) or null_object?) else @target.send :method_missing, sym, *args, &block end end
def munge(sym)
def munge(sym) "proxied_by_rspec__#{sym.to_s}".to_sym end
def null_object?
def null_object? @options[:null_object] end
def raise_unexpected_message_args_error(expectation, *args)
def raise_unexpected_message_args_error(expectation, *args) @error_generator.raise_unexpected_message_args_error expectation, *args end
def raise_unexpected_message_error(sym, *args)
def raise_unexpected_message_error(sym, *args) @error_generator.raise_unexpected_message_error sym, *args end
def received_message?(sym, *args, &block)
def received_message?(sym, *args, &block) @messages_received.any? {|array| array == [sym, args, block]} end
def reset
def reset clear_expectations clear_stubs reset_proxied_methods clear_proxied_methods end
def reset_proxied_methods
def reset_proxied_methods @proxied_methods.each do |sym| munged_sym = munge(sym) target_metaclass.instance_eval do if method_defined?(munged_sym.to_s) alias_method sym, munged_sym undef_method munged_sym else undef_method sym end end end end
def target_metaclass
def target_metaclass class << @target; self; end end
def target_responds_to?(sym)
def target_responds_to?(sym) return @target.send(munge(:respond_to?),sym) if @already_proxied_respond_to return @already_proxied_respond_to = true if sym == :respond_to? return @target.respond_to?(sym) end
def verify #:nodoc:
def verify #:nodoc: verify_expectations ensure reset end
def verify_expectations
def verify_expectations @expectations.each do |expectation| expectation.verify_messages_received end end
def visibility(sym)
def visibility(sym) if Mock === @target 'public' elsif target_metaclass.private_method_defined?(sym) 'private' elsif target_metaclass.protected_method_defined?(sym) 'protected' else 'public' end end