1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
require 'metaclass'
module Mocha
class ClassMethod
attr_reader :stubbee, :method
def initialize(stubbee, method)
@stubbee, @original_method = stubbee, nil
@method = RUBY_VERSION < '1.9' ? method.to_s : method.to_sym
end
def stub
hide_original_method
define_new_method
end
def unstub
remove_new_method
restore_original_method
mock.unstub(method.to_sym)
unless mock.any_expectations?
reset_mocha
end
end
def mock
stubbee.mocha
end
def reset_mocha
stubbee.reset_mocha
end
def hide_original_method
if method_exists?(method)
begin
@original_method = stubbee._method(method)
if @original_method && @original_method.owner == stubbee.__metaclass__
@original_visibility = :public
if stubbee.__metaclass__.protected_instance_methods.include?(method)
@original_visibility = :protected
elsif stubbee.__metaclass__.private_instance_methods.include?(method)
@original_visibility = :private
end
stubbee.__metaclass__.send(:remove_method, method)
end
rescue NameError
# deal with nasties like ActiveRecord::Associations::AssociationProxy
end
end
end
def define_new_method
stubbee.__metaclass__.class_eval(%{
def #{method}(*args, &block)
mocha.method_missing(:#{method}, *args, &block)
end
}, __FILE__, __LINE__)
end
def remove_new_method
stubbee.__metaclass__.send(:remove_method, method)
end
def restore_original_method
if @original_method && @original_method.owner == stubbee.__metaclass__
original_method = @original_method
stubbee.__metaclass__.send(:define_method, method) do |*args, &block|
original_method.call(*args, &block)
end
stubbee.__metaclass__.send(@original_visibility, method)
end
end
def matches?(other)
return false unless (other.class == self.class)
(stubbee.object_id == other.stubbee.object_id) and (method == other.method)
end
alias_method :==, :eql?
def to_s
"#{stubbee}.#{method}"
end
def method_exists?(method)
symbol = method.to_sym
__metaclass__ = stubbee.__metaclass__
__metaclass__.public_method_defined?(symbol) || __metaclass__.protected_method_defined?(symbol) || __metaclass__.private_method_defined?(symbol)
end
end
end
|