Skip to content
This repository has been archived by the owner on Nov 30, 2024. It is now read-only.

Be more permissive when detecting frozen objects #1401

Closed
wants to merge 3 commits into from

Conversation

keegangroth
Copy link
Contributor

Rather than rely on an object's #frozen? method, always attempt to
proxy a method when requested. Catch the errors resulting from failed
attempts to proxy and reraise (or log) them with helpful messages.

One notable use case for this is rails' activerecord's Model objects
becoming frozen after be deleted. In reality, only the underlying hash
of attributes is frozen and it should still be possible to write
proxies for these objects.

@JonRowe JonRowe changed the title Be more permissive when proxying frozen/static objects Be more permissive when detecting frozen objects Jan 12, 2021
@tannermares
Copy link

Hey there! Any reason this isn't being merged? I'm hitting this during a Rails update and could really use the fix.

@pirj pirj requested a review from JonRowe February 16, 2022 07:32
lib/rspec/mocks/method_double.rb Outdated Show resolved Hide resolved
lib/rspec/mocks/proxy.rb Show resolved Hide resolved
spec/rspec/mocks/space_spec.rb Outdated Show resolved Hide resolved
spec/rspec/mocks/space_spec.rb Outdated Show resolved Hide resolved
lib/rspec/mocks/method_double.rb Outdated Show resolved Hide resolved
@JonRowe
Copy link
Member

JonRowe commented Feb 16, 2022

As the original source of this bug is Rails not implementing frozen? correctly, it might also be worth raising this with them. Only properly frozen objects should return true for frozen?

@keegangroth
Copy link
Contributor Author

keegangroth commented Feb 16, 2022

Do I need to address the failures in the "legacy" tests? I've having some trouble getting rvm to install ruby-1.8.7...

@JonRowe
Copy link
Member

JonRowe commented Feb 16, 2022

Do I need to address the failures in the "legacy" tests? I've having some trouble getting rvm to install ruby-1.8.7...

If you want this merged to main for a potential bug fix release, yes, if you want it merged to 4-0-dev for when that gets released no, looking at it you have a behaviour difference with frozen objects for those rubies.

@keegangroth keegangroth force-pushed the main branch 2 times, most recently from 39bdbd5 to e446e02 Compare February 20, 2022 17:21
@keegangroth
Copy link
Contributor Author

I think this is ready for another look. I manged to get 1.8.7 running and the tests passing there. Also rearranged and added more tests, the diff for those looks worse than it really is though.

@keegangroth
Copy link
Contributor Author

for real this time, set up the actions on my fork and the only failure was some ffi compilation issue on one windows run...

lib/rspec/mocks/proxy.rb Outdated Show resolved Hide resolved
Copy link
Member

@pirj pirj left a comment

Choose a reason for hiding this comment

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

Looks good, thank you!

@pirj pirj requested a review from JonRowe February 20, 2022 20:01
@keegangroth keegangroth force-pushed the main branch 2 times, most recently from 0076660 to 66b2c58 Compare February 22, 2022 13:40
@pirj
Copy link
Member

pirj commented Feb 24, 2022

manged to get 1.8.7 running

Locally? Thanks for this effort, I know it is not easy.
Please accept my apologies for the delayed response and our CI build gate. I've triggered the build.

@keegangroth
Copy link
Contributor Author

manged to get 1.8.7 running

Locally? Thanks for this effort, I know it is not easy.

yeah, this took me a little while, but doing it with docker ended up not being too bad. Likely not perfect, but here's a gist for it if anyone else needs it. Then you just have to find working docker images, here's what I used:

docker build --build-arg ruby=ruby:2.1.9 -t rspec-mocks .
docker build --build-arg ruby=okyada/ruby:1.8.7 -t rspec-mocks .

spec/rspec/mocks/matchers/receive_spec.rb Show resolved Hide resolved
@@ -35,8 +35,7 @@ def initialize(object, order_group, options={})

# @private
def ensure_can_be_proxied!(object)
return unless object.is_a?(Symbol) || object.frozen?
return if object.nil?
return unless object.is_a?(Symbol) || (object.is_a?(String) && object.frozen?)
Copy link
Member

Choose a reason for hiding this comment

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

This check is wrong, we still need to check other types of objects are frozen. If you want to improve this check to actually check the real object is frozen please do, (prehaps checking that the frozen method is kernels method) but as it is I don't want to only warn for frozen strings.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's actually simply redundant, the new exception handling takes care of all objects regardless of this check. I had mentioned this previously in #1401 (comment) and @pirj advised minimizing the changes, but I would be happy to remove this method entirely to avoid this confusion.

@cknoxrun
Copy link

cknoxrun commented May 2, 2022

This one is biting me too with Rails - happy to help get it across the finish line if I can.

@pirj
Copy link
Member

pirj commented May 2, 2022

@cknoxrun You're welcome to.

@keegangroth
Copy link
Contributor Author

I'm still watching this, was just waiting @JonRowe to say how he wanted it, but I guess I'll just take another shot

Rather than rely on an object's #frozen? method, always attempt to
proxy a method when requested. Catch the errors resulting from failed
attempts to proxy and reraise (or log) them with helpful messages.

One notable use case for this is rails' activerecord's Model objects
becoming frozen after being deleted. In reality, only the underlying
hash of attributes is frozen and it should still be possible to write
proxies for these objects.
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.

@keegangroth Apologies, I thought I made it clear that you still needed to restore some existing behaviour for this to be mergable, as that hadn't happened I didn't re-review. I've highlighted the issues again.

lib/rspec/mocks/proxy.rb Show resolved Hide resolved
spec/rspec/mocks/syntax_agnostic_message_matchers_spec.rb Outdated Show resolved Hide resolved
spec/rspec/mocks/syntax_agnostic_message_matchers_spec.rb Outdated Show resolved Hide resolved
spec/rspec/mocks/space_spec.rb Show resolved Hide resolved
Let the logic in method_double handle this like it does for other
classes.
@simonxmh
Copy link

simonxmh commented Nov 7, 2022

Any updates on this? We are still encountering this as a blocker

JonRowe added a commit that referenced this pull request Nov 10, 2022
@JonRowe JonRowe closed this Nov 10, 2022
@JonRowe
Copy link
Member

JonRowe commented Nov 10, 2022

Merged in 727ba92

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

Successfully merging this pull request may close these issues.

6 participants