Class: RSpec::Matchers::BuiltIn::Compound::NestedEvaluator Private
Relationships & Source Files | |
Inherits: | Object |
Defined in: | rspec-expectations/lib/rspec/matchers/built_in/compound.rb |
Overview
Normally, we evaluate the matching sequentially. For an expression like ‘expect(x).to foo.and bar`, this becomes:
expect(x).to foo
expect(x).to
For block expectations, we need to nest them instead, so that ‘expect { x }.to foo.and bar` becomes:
expect {
expect { x }.to foo
}.to
This is necessary so that the expect
block is only executed once.
Class Method Summary
- .new(actual, matcher_1, matcher_2) ⇒ NestedEvaluator constructor Internal use only
- .matcher_expects_call_stack_jump?(matcher) ⇒ Boolean private Internal use only
Instance Method Summary
- #matcher_matches?(matcher) ⇒ Boolean Internal use only
-
#inner_matcher_block(outer_args)
private
Internal use only
Some block matchers (such as
yield_xyz
) pass args to theexpect
block. -
#order_block_matchers
private
Internal use only
For a matcher like
raise_error
orthrow_symbol
, where the block will jump up the call stack, we need to order things so that it is the inner matcher.
Constructor Details
.new(actual, matcher_1, matcher_2) ⇒ NestedEvaluator
# File 'rspec-expectations/lib/rspec/matchers/built_in/compound.rb', line 160
def initialize(actual, matcher_1, matcher_2) @actual = actual @matcher_1 = matcher_1 @matcher_2 = matcher_2 @match_results = {} inner, outer = order_block_matchers @match_results[outer] = outer.matches?(Proc.new do |*args| @match_results[inner] = inner.matches?(inner_matcher_block(args)) end) end
Class Method Details
.matcher_expects_call_stack_jump?(matcher) ⇒ Boolean
(private)
# File 'rspec-expectations/lib/rspec/matchers/built_in/compound.rb', line 236
def self.matcher_expects_call_stack_jump?(matcher) matcher.expects_call_stack_jump? rescue NoMethodError false end
Instance Method Details
#inner_matcher_block(outer_args) (private)
Some block matchers (such as yield_xyz
) pass args to the expect
block. When such a matcher is used as the outer matcher, we need to forward the the args on to the expect
block.
# File 'rspec-expectations/lib/rspec/matchers/built_in/compound.rb', line 187
def inner_matcher_block(outer_args) return @actual if outer_args.empty? Proc.new do |*inner_args| unless inner_args.empty? raise ArgumentError, "(#{@matcher_1.description}) and " \ "(#{@matcher_2.description}) cannot be combined in a compound expectation " \ "since both matchers pass arguments to the block." end @actual.call(*outer_args) end end
#matcher_matches?(matcher) ⇒ Boolean
# File 'rspec-expectations/lib/rspec/matchers/built_in/compound.rb', line 173
def matcher_matches?(matcher) @match_results.fetch(matcher) do raise ArgumentError, "Your #{matcher.description} has no match " \ "results, this can occur when an unexpected call stack or " \ "local jump occurs. Perhaps one of your matchers needs to " \ "declare `expects_call_stack_jump?` as `true`?" end end
#order_block_matchers (private)
For a matcher like raise_error
or throw_symbol
, where the block will jump up the call stack, we need to order things so that it is the inner matcher. For example, we need it to be this:
expect {
expect {
x += 1
raise "boom"
}.to raise_error("boom")
}.to change { x }.by(1)
…rather than:
expect {
expect {
x += 1
raise "boom"
}.to change { x }.by(1)
}.to raise_error("boom")
In the latter case, the after-block logic in the change
matcher would never get executed because the ‘raise “boom”` line would jump to the rescue
in the raise_error
logic, so only the former case will work properly.
This method figures out which matcher should be the inner matcher and which should be the outer matcher.
# File 'rspec-expectations/lib/rspec/matchers/built_in/compound.rb', line 227
def order_block_matchers return @matcher_1, @matcher_2 unless self.class.matcher_expects_call_stack_jump?(@matcher_2) return @matcher_2, @matcher_1 unless self.class.matcher_expects_call_stack_jump?(@matcher_1) raise ArgumentError, "(#{@matcher_1.description}) and " \ "(#{@matcher_2.description}) cannot be combined in a compound expectation " \ "because they both expect a call stack jump." end