Hi Nick,
I came up with a hacky solution that might do the trick for your use case.
```
module MyMatchers
class Pass
include RSpec::Matchers::Composable
def initialize(expected_return_value)
@expected_return_value = expected_return_value
end
def description
"pass with #{@expected_return_value} return value"
end
def matches?(block)
if block.source_location.first.end_with?('compound.rb')
fail "You should use this matcher at the top of the chain,
immediately following the `expect { ... }`"
end
@actual_return_value = block.call
values_match?(@expected_return_value, @actual_return_value)
end
def failure_message(*args)
"Expected: #{@expected_return_value}, got: #{@actual_return_value}"
end
def supports_block_expectations?
true
end
end
def pass(expected_return_value)
Pass.new(expected_return_value)
end
end
RSpec.configure do |config|
config.include MyMatchers
end
$foo = 0
```
Now, when you run:
```
RSpec.describe "a custom block matcher" do
specify do
expect { $foo = 2 }
.to pass(2)
.and change { $foo }.by(2)
end
end
```
it will be green.
However, if `pass` is not the first matcher, it will blow up:
```
RSpec.describe "a custom block matcher" do
specify do
expect { $foo = 2 }
.to change { $foo }.by(2)
.and pass(2)
end
end
```
with:
```
a custom block matcher
is expected to change `$foo` by 2 and pass with 2 return value (FAILED -
1)
Failures:
1) a custom block matcher is expected to change `$foo` by 2 and pass with
2 return value
Failure/Error: fail "You should use this matcher at the top of the
chain, immediately following the `expect { ... }`"
RuntimeError:
You should use this matcher at the top of the chain, immediately
following the `expect { ... }`
```
I hope that works.
There's room to make this generic by:
- wrapping the initial expect block into a proc that would save the return
value of a wrapped initial block into a variable
- pass the return value to other matchers along with the block around in
NestedEvaluator if matcher's `matches?` accepts two arguments
This would allow for using `pass` in any position in the chain.
I'm still not entirely convinced it will be widely used, since the `expect
{ expect(action!).to eq(return_value) }.to check_side_effect }` trick works
quite fine for non-DSL cases.
- Phil
--
You received this message because you are subscribed to the Google Groups
"rspec" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/rspec/CAAk5Ok9HOT%3Dp3MNtSV5nmhTsQnLpw7hHq%2Bbu2JEi84rwsF7Fsw%40mail.gmail.com.