Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow satisfy to match the block expectation return value #1477

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

pirj
Copy link
Member

@pirj pirj commented Aug 4, 2024

fixes #1466
idea #805 (comment)

ary = [1, 2]
expect { ary.shift }
  .to change { ary }.to([2])
  .and satisfy { |returned_value| returned_value == 1 }

@pirj pirj changed the title Teach satisfy to match on the block expectation return value Allow satisfy to match the block expectation return value Aug 4, 2024
@pirj pirj marked this pull request as ready for review August 4, 2024 17:10
@pirj pirj self-assigned this Aug 4, 2024
@pirj pirj requested a review from JonRowe August 4, 2024 17:11
@pirj
Copy link
Member Author

pirj commented Aug 18, 2024

cc @zverok WDYT?

Copy link
Member

@JonRowe JonRowe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay reviewing this @pirj definietly a good idea and good work but needs some tweaks

@@ -39,3 +53,20 @@ Feature: `satisfy` matcher
| expected 10 to satisfy expression `v > 15` |
| expected 10 not to be greater than 5 |
| expected 10 to be greater than 15 |

@skip-when-ripper-unsupported
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you just copy this tag or check to see if it works without it? I'd expect it to work without it as its not matching source.

Comment on lines +798 to +800
# Passes if the submitted block returns true.
# For value expectations, yields target to the block.
# For block expectations, yields the expectation's returned value to the block.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Passes if the submitted block returns true.
# For value expectations, yields target to the block.
# For block expectations, yields the expectation's returned value to the block.
# Passes if the submitted block returns true. Yields targer to the
# block. This is either the direct value or the result of an `expect` block.

@@ -11,6 +11,7 @@ Enhancements:

* Improve the IO emulation in the output capture matchers (`output(...).to_stdout` et al)
by adding `as_tty` and `as_not_tty` to change the `tty?` flags. (Sergio Gil Pérez de la Manga, #1459)
* Allow `satisfy` to match block expectations return value. (Phil Pirozhkov, #1477)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Allow `satisfy` to match block expectations return value. (Phil Pirozhkov, #1477)
* Improve the `satisfy` matcher to allow assertations on an `expect { ... }` return value.
(Phil Pirozhkov, #1477)

@@ -1,3 +1,19 @@
RSpec.shared_examples "an RSpec value-only matcher" do |options|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this technically makes it more consistent but it causes a lot of churn, I'm leaning towards preferring inverting this so that "an RSpec value matcher" is the "value only" specs and the opposite is named something else, or even make these optional specs part of one group like above.

end
end

pending "allows a matcher as an argument" do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not introduce pending specs unless its for something version specific, what needs to be done to make this work?

end
end

describe "composed usage" do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should follow on from the example group description

Suggested change
describe "composed usage" do
describe "when composed with other matchers" do

@match_results[inner] = inner.matches?(inner_matcher_block(args))
p = Proc.new { |*args2|
returned = inner_matcher_block(args).call(*args2)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to take care of ruby2 keywords (e.g. marked as such, not having keywords itself) so that they get passed through, I'm also a bit nervous about returned why isn't it just implict from the assignment?

@zverok
Copy link

zverok commented Sep 8, 2024

(A bit of a philosophical note, as I was tagged...)

I can’t say that I am fond of this solution. The original idea for return_value matcher, for me, is more in the spirit of RSpec (and I actually have one in saharspec, called just ret, as you are probably aware).

The solution with satisfy { boolean check } seems to go against the RSpec spirit of “every check should be built from combining matchers,” the spirit that allows to produce clear explanations of “what is expected” in --format doc mode, but which requires to write matchers in “RSpec DSL” instead of pure Ruby (e.g., we write expected.to eq 5 not expected.to == 5).

This is a choice that is questioned by some, but it allows to build powerful, combinable checks, which very clearly report “what went wrong” when the specs are red, able to produce nice diffs depending on the context of the check and so on.

Even the original satisfy { any code } looked like an “escape hatch” for me (basically, “when you are in a hurry, or the check is so unique that it is easier then make a new small clear matcher”), and extending its usage for new cases... I am not sure if I see it justified.

May I ask why the original return_value(other_matcher) idea was abandoned?..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

return_value matcher
3 participants