Skip to content
This repository
Browse code

Merge pull request #213 from rspec/issue-212

Fix `and_call_original` so that it looks for the method in all ancestors
  • Loading branch information...
commit 80899f0a84ce23869b3dd07ab449e61342868fea 2 parents 6356c92 + 14ae958
Myron Marston authored January 05, 2013
8  Changelog.md
Source Rendered
... ...
@@ -1,3 +1,11 @@
  1
+### dev
  2
+[full changelog](http://github.com/rspec/rspec-mocks/compare/v2.12.1...master)
  3
+
  4
+Bug fixes
  5
+
  6
+* Fix `and_call_original` to work properly for methods defined
  7
+  on a module extended onto an object instance (Myron Marston).
  8
+
1 9
 ### 2.12.1 / 2012-12-21
2 10
 [full changelog](http://github.com/rspec/rspec-mocks/compare/v2.12.0...v2.12.1)
3 11
 
12  lib/rspec/mocks/method_double.rb
@@ -56,8 +56,8 @@ def original_method
56 56
           meth
57 57
         else
58 58
           begin
59  
-            # Example: an instance method defined on @object's class.
60  
-            @object.class.instance_method(@method_name).bind(@object)
  59
+            # Example: an instance method defined on one of @object's ancestors.
  60
+            original_method_from_ancestor(object_singleton_class.ancestors)
61 61
           rescue NameError
62 62
             raise unless @object.respond_to?(:superclass)
63 63
 
@@ -97,6 +97,14 @@ def any_instance_class_recorder_observing_method?(klass)
97 97
         any_instance_class_recorder_observing_method?(superklass)
98 98
       end
99 99
 
  100
+      def original_method_from_ancestor(ancestors)
  101
+        klass, *rest = ancestors
  102
+        klass.instance_method(@method_name).bind(@object)
  103
+      rescue NameError
  104
+        raise if rest.empty?
  105
+        original_method_from_ancestor(rest)
  106
+      end
  107
+
100 108
       if RUBY_VERSION.to_f > 1.8
101 109
         # @private
102 110
         def original_method_from_superclass
22  spec/rspec/mocks/and_call_original_spec.rb
@@ -37,6 +37,28 @@ def instance.foo; :bar; end
37 37
       expect(instance.foo).to eq(:bar)
38 38
     end
39 39
 
  40
+    it 'works for methods added through an extended module' do
  41
+      instance.extend Module.new { def foo; :bar; end }
  42
+      instance.should_receive(:foo).and_call_original
  43
+      expect(instance.foo).to eq(:bar)
  44
+    end
  45
+
  46
+    it "works for method added through an extended module onto a class's ancestor" do
  47
+      sub_sub_klass = Class.new(Class.new(klass))
  48
+      klass.extend Module.new { def foo; :bar; end }
  49
+      sub_sub_klass.should_receive(:foo).and_call_original
  50
+      expect(sub_sub_klass.foo).to eq(:bar)
  51
+    end
  52
+
  53
+    it "finds the method on the most direct ancestor even if the method " +
  54
+       "is available on more distant ancestors" do
  55
+      klass.extend Module.new { def foo; :klass_bar; end }
  56
+      sub_klass = Class.new(klass)
  57
+      sub_klass.extend Module.new { def foo; :sub_klass_bar; end }
  58
+      sub_klass.should_receive(:foo).and_call_original
  59
+      expect(sub_klass.foo).to eq(:sub_klass_bar)
  60
+    end
  61
+
40 62
     context 'when using any_instance' do
41 63
       it 'works for instance methods defined on the class' do
42 64
         klass.any_instance.should_receive(:meth_1).and_call_original

0 notes on commit 80899f0

Please sign in to comment.
Something went wrong with that request. Please try again.