Skip to content
This repository has been archived by the owner on Oct 27, 2021. It is now read-only.

Commit

Permalink
Add Foo.any_instance.stub!
Browse files Browse the repository at this point in the history
Closes LH[#28] (patch from Scott Taylor)
  • Loading branch information
Pat Maddox committed May 24, 2008
1 parent 7af69e3 commit 45a6837
Show file tree
Hide file tree
Showing 7 changed files with 399 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/spec/mocks.rb
Expand Up @@ -2,13 +2,15 @@
require 'spec/mocks/argument_constraint_matchers'
require 'spec/mocks/spec_methods'
require 'spec/mocks/proxy'
require 'spec/mocks/any_instance'
require 'spec/mocks/mock'
require 'spec/mocks/argument_expectation'
require 'spec/mocks/message_expectation'
require 'spec/mocks/order_group'
require 'spec/mocks/errors'
require 'spec/mocks/error_generator'
require 'spec/mocks/extensions/object'
require 'spec/mocks/extensions/class'
require 'spec/mocks/space'


Expand Down
27 changes: 27 additions & 0 deletions lib/spec/mocks/any_instance.rb
@@ -0,0 +1,27 @@
require File.dirname(__FILE__) + "/any_instance/method_stubber"
require File.dirname(__FILE__) + "/any_instance/any_instance_proxy"
require File.dirname(__FILE__) + "/any_instance/methods"

module Spec
module Mocks
# An addition to rspec's mock/stub library which
# will allow stubs to be included to all instances of a class.
#
# MyClass.any_instance.stub!(:foo).and_return :my_value
#
# MyClass.new.foo #=> :my_value
# MyClass.new.foo #=> :my_value
#
#
# Regular instance level stubs will still work as usual,
# overriding the behavior of stubbing all instances of a class:
#
# MyClass.any_instance.stub!(:my_method).and_return :foo
# instance = MyClass.new
# instance.stub!(:my_method).and_return :bar
# instance.my_method #=> :bar
#
module AnyInstance
end
end
end
31 changes: 31 additions & 0 deletions lib/spec/mocks/any_instance/any_instance_proxy.rb
@@ -0,0 +1,31 @@
module Spec
module Mocks
module AnyInstance
class AnyInstanceProxy

def initialize(target)
@target = target
@stubbed_methods = []
end

def stub!(message)
stubber = MethodStubber.new @target, message
stubber.add_stub
register_stub stubber
stubber
end

def reset
@stubbed_methods.each { |object| object.reset! }
end

private

def register_stub(stubber)
$rspec_mocks.add stubber
@stubbed_methods << stubber
end
end
end
end
end
67 changes: 67 additions & 0 deletions lib/spec/mocks/any_instance/method_stubber.rb
@@ -0,0 +1,67 @@
module Spec
module Mocks
module AnyInstance
class MethodStubber

def initialize(target, message)
@target = target
@message = message
@munged_sym = "__rspec_proxy_any_instance_#{message}".to_sym
end

def add_stub
add_stub_with_value nil
end

def and_return(value)
add_stub_with_value value
end

def and_raise(*raise_params)
add_stub_with_error *raise_params
end

def reset!
swap_methods @munged_sym, @message
@target.send(:remove_method, @munged_sym) if @target.method_defined?(@munged_sym)
end
alias_method :rspec_reset, :reset!

def verified?
@verified
end

def rspec_verify
@verified = true
end

private
def define_stub(&impl)
store_current_instance_method do |message|
@target.send(:define_method, message, &impl)
end
end

def add_stub_with_value(value)
define_stub { value }
end

def add_stub_with_error(*raise_params)
define_stub { raise *raise_params }
end

def store_current_instance_method(&block)
swap_methods @message, @munged_sym, &block
end

def swap_methods(first, second)
@target.class_eval do
alias_method second, first if method_defined?(first)
end
yield first if block_given?
end

end
end
end
end
22 changes: 22 additions & 0 deletions lib/spec/mocks/any_instance/methods.rb
@@ -0,0 +1,22 @@
module Spec
module Mocks
module AnyInstance
module Methods
# See the documentation under Spec::Mocks::AnyInstance
def any_instance
yield __any_instance_proxy__ if block_given?
__any_instance_proxy__
end

def __rspec_clear_instances__
__any_instance_proxy__.reset
end

private
def __any_instance_proxy__
@__any_instance_proxy__ ||= AnyInstanceProxy.new(self)
end
end
end
end
end
3 changes: 3 additions & 0 deletions lib/spec/mocks/extensions/class.rb
@@ -0,0 +1,3 @@
class Class
include Spec::Mocks::AnyInstance::Methods
end

0 comments on commit 45a6837

Please sign in to comment.