lib/rspec/matchers/built_in/yield.rb in rspec-expectations-3.6.0.beta2 vs lib/rspec/matchers/built_in/yield.rb in rspec-expectations-3.6.0
- old
+ new
@@ -6,39 +6,46 @@
# @private
# Object that is yielded to `expect` when one of the
# yield matchers is used. Provides information about
# the yield behavior of the object-under-test.
class YieldProbe
- def self.probe(block)
- probe = new(block)
+ def self.probe(block, &callback)
+ probe = new(block, &callback)
return probe unless probe.has_block?
- probe.assert_valid_expect_block!
- block.call(probe)
- probe.assert_used!
- probe
+ probe.probe
end
attr_accessor :num_yields, :yielded_args
- def initialize(block)
+ def initialize(block, &callback)
@block = block
+ @callback = callback || Proc.new {}
@used = false
self.num_yields = 0
self.yielded_args = []
end
def has_block?
Proc === @block
end
+ def probe
+ assert_valid_expect_block!
+ @block.call(self)
+ assert_used!
+ self
+ end
+
def to_proc
@used = true
probe = self
+ callback = @callback
Proc.new do |*args|
probe.num_yields += 1
probe.yielded_args << args
+ callback.call(*args)
nil # to indicate the block does not return a meaningful value
end
end
def single_yield_args
@@ -54,16 +61,10 @@
'method that yields multiple times. Use the yield_successive_args ' \
'matcher for that case.'
end
end
- def successive_yield_args
- yielded_args.map do |arg_array|
- arg_array.size == 1 ? arg_array.first : arg_array
- end
- end
-
def assert_used!
return if @used
raise 'You must pass the argument yielded to your expect block on ' \
'to the method-under-test as a block. It acts as a probe that ' \
'allows the matcher to detect whether or not the method-under-test ' \
@@ -267,14 +268,19 @@
@expected = args
end
# @private
def matches?(block)
- @probe = YieldProbe.probe(block)
+ @args_matched_when_yielded = true
+ @probe = YieldProbe.new(block) do
+ @actual = @probe.single_yield_args
+ @actual_formatted = actual_formatted
+ @args_matched_when_yielded &&= args_currently_match?
+ end
return false unless @probe.has_block?
- @actual = @probe.single_yield_args
- @probe.yielded_once?(:yield_with_args) && args_match?
+ @probe.probe
+ @probe.yielded_once?(:yield_with_args) && @args_matched_when_yielded
end
# @private
def does_not_match?(block)
!matches?(block) && @probe.has_block?
@@ -315,29 +321,29 @@
end
def negative_failure_reason
if !@probe.has_block?
'was not a block'
- elsif all_args_match?
+ elsif @args_matched_when_yielded && !@expected.empty?
'yielded with expected arguments' \
"\nexpected not: #{surface_descriptions_in(@expected).inspect}" \
- "\n got: #{actual_formatted}"
+ "\n got: #{@actual_formatted}"
else
'did'
end
end
- def args_match?
+ def args_currently_match?
if @expected.empty? # expect {...}.to yield_with_args
@positive_args_failure = 'yielded with no arguments' if @actual.empty?
return !@actual.empty?
end
unless (match = all_args_match?)
@positive_args_failure = 'yielded with unexpected arguments' \
"\nexpected: #{surface_descriptions_in(@expected).inspect}" \
- "\n got: #{actual_formatted}"
+ "\n got: #{@actual_formatted}"
end
match
end
@@ -354,14 +360,25 @@
@expected = args
end
# @private
def matches?(block)
- @probe = YieldProbe.probe(block)
+ @actual_formatted = []
+ @actual = []
+ args_matched_when_yielded = true
+ yield_count = 0
+
+ @probe = YieldProbe.probe(block) do |*arg_array|
+ arg_or_args = arg_array.size == 1 ? arg_array.first : arg_array
+ @actual_formatted << RSpec::Support::ObjectFormatter.format(arg_or_args)
+ @actual << arg_or_args
+ args_matched_when_yielded &&= values_match?(@expected[yield_count], arg_or_args)
+ yield_count += 1
+ end
+
return false unless @probe.has_block?
- @actual = @probe.successive_yield_args
- args_match?
+ args_matched_when_yielded && yield_count == @expected.length
end
def does_not_match?(block)
!matches?(block) && @probe.has_block?
end
@@ -388,31 +405,27 @@
true
end
private
- def args_match?
- values_match?(@expected, @actual)
- end
-
def expected_arg_description
@expected.map { |e| description_of e }.join(', ')
end
def positive_failure_reason
return 'was not a block' unless @probe.has_block?
'yielded with unexpected arguments' \
"\nexpected: #{surface_descriptions_in(@expected).inspect}" \
- "\n got: #{actual_formatted}"
+ "\n got: [#{@actual_formatted.join(", ")}]"
end
def negative_failure_reason
return 'was not a block' unless @probe.has_block?
'yielded with expected arguments' \
"\nexpected not: #{surface_descriptions_in(@expected).inspect}" \
- "\n got: #{actual_formatted}"
+ "\n got: [#{@actual_formatted.join(", ")}]"
end
end
end
end
end