From 651ec6bbf11bb1a16bbc3697f4c247b70601b1a6 Mon Sep 17 00:00:00 2001 From: Luke Reeves Date: Thu, 11 Aug 2016 14:32:28 -0400 Subject: [PATCH] Test and fix for call_through w/ instance methods --- lib/spy/subroutine.rb | 44 +++++++++++++++++++----- test/integration/test_instance_method.rb | 6 ++++ 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/lib/spy/subroutine.rb b/lib/spy/subroutine.rb index ead3eff..d4903ee 100644 --- a/lib/spy/subroutine.rb +++ b/lib/spy/subroutine.rb @@ -135,13 +135,29 @@ def and_yield(*args) # tells the spy to call the original method # @return [self] def and_call_through - @plan = Proc.new do |*args, &block| - if original_method - original_method.call(*args, &block) - else - base_object.send(:method_missing, method_name, *args, &block) + if @base_object.is_a? Class + @plan = Proc.new do |object, *args, &block| + if original_method + if original_method.is_a? UnboundMethod + bound_method = original_method.bind(object) + bound_method.call(*args, &block) + else + original_method.call(*args, &block) + end + else + base_object.send(:method_missing, method_name, *args, &block) + end + end + else + @plan = Proc.new do |*args, &block| + if original_method + original_method.call(*args, &block) + else + base_object.send(:method_missing, method_name, *args, &block) + end end end + self end @@ -202,10 +218,18 @@ def has_been_called_with?(*args) # method. def invoke(object, args, block, called_from) check_arity!(args.size) - result = if @plan - check_for_too_many_arguments!(@plan) - @plan.call(*args, &block) - end + + if base_object.is_a? Class + result = if @plan + check_for_too_many_arguments!(@plan) + @plan.call(object, *args, &block) + end + else + result = if @plan + check_for_too_many_arguments!(@plan) + @plan.call(*args, &block) + end + end ensure calls << CallLog.new(object, called_from, args, block, result) end @@ -273,6 +297,8 @@ def check_for_too_many_arguments!(block) min_arity = block.arity min_arity = min_arity.abs - 1 if min_arity < 0 + min_arity -=1 if base_object.is_a? Class # Instance-method procs take an extra param for receiving object + if min_arity > arity_range.max raise ArgumentError.new("block requires #{min_arity} arguments while original_method require a maximum of #{arity_range.max}") end diff --git a/test/integration/test_instance_method.rb b/test/integration/test_instance_method.rb index 590833c..8573bf7 100644 --- a/test/integration/test_instance_method.rb +++ b/test/integration/test_instance_method.rb @@ -17,6 +17,12 @@ def teardown Spy::Agency.instance.dissolve! end + def test_call_through_with_instance_method + Spy.on_instance_method(Foo, :bar).and_call_through + assert_equal "foobar", Foo.new.bar + Spy.off_instance_method(Foo, :bar) + end + def test_it_overides_all_methods assert_equal Foo.new.bar, "foobar" spy = Spy.on_instance_method(Foo, bar: "timshel")