Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fix `and_call_original` so that it looks for the method in all ancestors

...including those mixed into the singleton class (i.e.
via a module extended onto an object instance).

Fixes #212.
  • Loading branch information...
commit 14ae958db7ae9aeac82876085925653a0ae12ad9 1 parent 6356c92
@myronmarston myronmarston authored
View
8 Changelog.md
@@ -1,3 +1,11 @@
+### dev
+[full changelog](http://github.com/rspec/rspec-mocks/compare/v2.12.1...master)
+
+Bug fixes
+
+* Fix `and_call_original` to work properly for methods defined
+ on a module extended onto an object instance (Myron Marston).
+
### 2.12.1 / 2012-12-21
[full changelog](http://github.com/rspec/rspec-mocks/compare/v2.12.0...v2.12.1)
View
12 lib/rspec/mocks/method_double.rb
@@ -56,8 +56,8 @@ def original_method
meth
else
begin
- # Example: an instance method defined on @object's class.
- @object.class.instance_method(@method_name).bind(@object)
+ # Example: an instance method defined on one of @object's ancestors.
+ original_method_from_ancestor(object_singleton_class.ancestors)
rescue NameError
raise unless @object.respond_to?(:superclass)
@@ -97,6 +97,14 @@ def any_instance_class_recorder_observing_method?(klass)
any_instance_class_recorder_observing_method?(superklass)
end
+ def original_method_from_ancestor(ancestors)
+ klass, *rest = ancestors
+ klass.instance_method(@method_name).bind(@object)
+ rescue NameError
+ raise if rest.empty?
+ original_method_from_ancestor(rest)
+ end
+
if RUBY_VERSION.to_f > 1.8
# @private
def original_method_from_superclass
View
22 spec/rspec/mocks/and_call_original_spec.rb
@@ -37,6 +37,28 @@ def instance.foo; :bar; end
expect(instance.foo).to eq(:bar)
end
+ it 'works for methods added through an extended module' do
+ instance.extend Module.new { def foo; :bar; end }
+ instance.should_receive(:foo).and_call_original
+ expect(instance.foo).to eq(:bar)
+ end
+
+ it "works for method added through an extended module onto a class's ancestor" do
+ sub_sub_klass = Class.new(Class.new(klass))
+ klass.extend Module.new { def foo; :bar; end }
+ sub_sub_klass.should_receive(:foo).and_call_original
+ expect(sub_sub_klass.foo).to eq(:bar)
+ end
+
+ it "finds the method on the most direct ancestor even if the method " +
+ "is available on more distant ancestors" do
+ klass.extend Module.new { def foo; :klass_bar; end }
+ sub_klass = Class.new(klass)
+ sub_klass.extend Module.new { def foo; :sub_klass_bar; end }
+ sub_klass.should_receive(:foo).and_call_original
+ expect(sub_klass.foo).to eq(:sub_klass_bar)
+ end
+
context 'when using any_instance' do
it 'works for instance methods defined on the class' do
klass.any_instance.should_receive(:meth_1).and_call_original
Please sign in to comment.
Something went wrong with that request. Please try again.