-
Notifications
You must be signed in to change notification settings - Fork 984
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
Fix infinite recursion and NameError on load when running with -rdebug
#1203
Conversation
When running with `ruby -rdebug` with a breakpoint set, `self.to_str` (which is not defined) is called repeatedly during module load, including the time after the `class << self` block is loaded but before further blocks that add more bits to `self` are. As such, the dynamic method resolution machinery has to not break in this partially initialized state.
lib/faraday.rb
Outdated
# including the time before the default_connection getter below is loaded | ||
if name == :default_connection | ||
return nil | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style opinion: These guards would look easier to read as a "suffix if", like
return nil if name == :default_connection
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I don't really have a preference here. I first tried name == :default_connection && return nil
but that turned out to be invalid syntax
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @native-api for trying to solve this, and apologies if I never came back to it since you initially raised the issue.
I'm still not entirely sure of what's is going on, but this solution of introducing guards looks more like a patch to me and it's not really elegant.
I don't think filling your code with guards due to some sort of loading race-condition is a good solution and I'd much rather consider others.
It might be worth investigating the issue a little more: you mentioned to_str
is being called, but why is it going to method_missing? Can we do any change to our code to avoid it breaking? Maybe we're not following a convention or something? Can you share your findings so far so we can brainstorm together?
Last time I had a look (here), I did some progress by moving all the self.*
methods into the class << self
block. Although that didn't fix the problem entirely, it shows the kind of solution I would prefer. I feel like we're missing something 🤔
This happens because we initialize the nonexistent member resolution mechanism in parts rather than all at once: first override As such, an alternative solution is to initialize the entire mechanism all at once: define all the overriding methods inside the |
Here's a trace of calls to the missing method resolution machinery during module load:
|
If I got it correctly, moving the all the methods into the Should that not work, then looking at your last comment it seems like we might get away just with changing the implementation of |
No. You also need to
Yes. But I don't want to rely on the knowledge that it's specifically |
Not to mention that we might want |
Go ahead, knock yourself out 🙂 : #1204 As I suspected, some submodules expect the main module to already be initialized and break on load. |
Fixed in #1205 🎉 |
Description
Fixes #1107
When running with
ruby -rdebug
with a breakpoint set,self.to_str
(which is not defined) is called repeatedly during module load, including the time after theclass << self
block is loaded but before further blocks that add more bits toself
are.As such, the dynamic method resolution machinery has to not break in this partially initialized state.
Todos
List any remaining work that needs to be done, i.e:
If this needs to be autotested, some pointers would be welcome: I've no idea how to load the module under test in a separate Ruby invocation from within RSpec.