Skip to content

Commit

Permalink
always backfill the Spy::MethodCall#result value for callbacks
Browse files Browse the repository at this point in the history
  • Loading branch information
jbodah committed Feb 9, 2016
1 parent 2cb3117 commit ec6768b
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 34 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ gem 'minitest'
gem 'guard'
gem 'guard-minitest'
gem 'minitest-bisect'
gem 'minitest-tagz'

gem 'coveralls', require: false
62 changes: 28 additions & 34 deletions lib/spy/instance/api/internal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,39 +30,37 @@ def call(receiver, *args, &block)
# it isn't just a data struct
is_active = @conditional_filters.all? {|f| f.call(receiver, *args)}

if !is_active
call_original(receiver, *args, &block)
else
if @before_callbacks.any?
mc = build_method_call(receiver, *args, &block)
@before_callbacks.each {|f| f.call(mc)}
end
return call_original(receiver, *args, &block) if !is_active

if @around_procs.any?
# Procify the original call
# Still return the result from it
result = nil
original_proc = Proc.new do
result = call_and_record(receiver, *args, &block)
end
if @before_callbacks.any?
mc = build_method_call(receiver, *args, &block)
@before_callbacks.each {|f| f.call(mc)}
end

mc = build_method_call(receiver, *args, &block)
if @around_procs.any?
mc = build_method_call(receiver, *args, &block)

# Keep wrapping the original proc with each around_proc
@around_procs.reduce(original_proc) do |p, wrapper|
Proc.new { wrapper.call mc, &p }
end.call
else
result = call_and_record(receiver, *args, &block)
# Procify the original call
# Still return the result from it
result = nil
original_proc = Proc.new do
result = call_and_record(receiver, args, { :record => mc }, &block)
end

if @after_callbacks.any?
mc = build_method_call(receiver, *args, &block)
@after_callbacks.each {|f| f.call(mc)}
end
# Keep wrapping the original proc with each around_proc
@around_procs.reduce(original_proc) do |p, wrapper|
Proc.new { wrapper.call(mc, &p) }
end.call
else
result = call_and_record(receiver, args, &block)
end

result
if @after_callbacks.any?
mc = @call_history.last
@after_callbacks.each {|f| f.call(mc)}
end

result
end

private
Expand All @@ -76,18 +74,14 @@ def build_method_call(receiver, *args, &block)
&block)
end

def call_and_record(receiver, *args, &block)
record = track_call(receiver, *args, &block)
def call_and_record(receiver, args, opts = {}, &block)
record = opts[:record] || build_method_call(receiver, *args, &block)
@call_history << record

result = call_original(receiver, *args, &block)
record.result = result
end

def track_call(receiver, *args, &block)
build_method_call(receiver, *args, &block).tap do |mc|
@call_history << mc
end
end

def call_original(receiver, *args, &block)
if original.is_a?(UnboundMethod)
original.bind(receiver).call(*args, &block)
Expand Down
12 changes: 12 additions & 0 deletions test/before_after_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,17 @@ class BeforeAfterTest < Minitest::Spec

assert yielded.is_a? Spy::MethodCall
end

it 'has the Spy::MethodCall result field filled in' do
obj = []
spy = Spy.on(obj, :<<)

yielded = nil
spy.after { |mc| yielded = mc }

obj << "hello"

assert_equal obj, yielded.result
end
end
end
6 changes: 6 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@
require 'minitest/pride'
require 'minitest/autorun'
require 'minitest/spec'
require 'minitest/tagz'

tags = ENV['TAGS'].split(',') if ENV['TAGS']
tags ||= []
tags << 'focus'
Minitest::Tagz.choose_tags(*tags, run_all_if_no_match: true)
12 changes: 12 additions & 0 deletions test/wrap_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,18 @@ def hello

assert yielded.is_a? Spy::MethodCall
end

it 'fills in the Spy::MethodCall result field after yielding execution back to the spied method' do
obj = []
spy = Spy.on(obj, :<<)

yielded = nil
spy.wrap { |mc, &block| block.call; yielded = mc }

obj << "hello"

assert_equal obj, yielded.result
end
end
end
end

0 comments on commit ec6768b

Please sign in to comment.