{"action":"created","issue":{"url":"https://api.github.com/repos/rspec/rspec-mocks/issues/973","labels_url":"https://api.github.com/repos/rspec/rspec-mocks/issues/973/labels{/name}","comments_url":"https://api.github.com/repos/rspec/rspec-mocks/issues/973/comments","events_url":"https://api.github.com/repos/rspec/rspec-mocks/issues/973/events","html_url":"https://github.com/rspec/rspec-mocks/pull/973","id":87954641,"number":973,"title":"Add failing spec for #972.","user":{"login":"myronmarston","id":49391,"avatar_url":"https://avatars.githubusercontent.com/u/49391?v=3","gravatar_id":"","url":"https://api.github.com/users/myronmarston","html_url":"https://github.com/myronmarston","followers_url":"https://api.github.com/users/myronmarston/followers","following_url":"https://api.github.com/users/myronmarston/following{/other_user}","gists_url":"https://api.github.com/users/myronmarston/gists{/gist_id}","starred_url":"https://api.github.com/users/myronmarston/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/myronmarston/subscriptions","organizations_url":"https://api.github.com/users/myronmarston/orgs","repos_url":"https://api.github.com/users/myronmarston/repos","events_url":"https://api.github.com/users/myronmarston/events{/privacy}","received_events_url":"https://api.github.com/users/myronmarston/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2015-06-13T07:34:57Z","updated_at":"2015-06-14T05:23:57Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/rspec/rspec-mocks/pulls/973","html_url":"https://github.com/rspec/rspec-mocks/pull/973","diff_url":"https://github.com/rspec/rspec-mocks/pull/973.diff","patch_url":"https://github.com/rspec/rspec-mocks/pull/973.patch"},"body":"Not sure how to fix it yet.  Figured I'd open this, though."},"comment":{"url":"https://api.github.com/repos/rspec/rspec-mocks/issues/comments/111784559","html_url":"https://github.com/rspec/rspec-mocks/pull/973#issuecomment-111784559","issue_url":"https://api.github.com/repos/rspec/rspec-mocks/issues/973","id":111784559,"user":{"login":"myronmarston","id":49391,"avatar_url":"https://avatars.githubusercontent.com/u/49391?v=3","gravatar_id":"","url":"https://api.github.com/users/myronmarston","html_url":"https://github.com/myronmarston","followers_url":"https://api.github.com/users/myronmarston/followers","following_url":"https://api.github.com/users/myronmarston/following{/other_user}","gists_url":"https://api.github.com/users/myronmarston/gists{/gist_id}","starred_url":"https://api.github.com/users/myronmarston/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/myronmarston/subscriptions","organizations_url":"https://api.github.com/users/myronmarston/orgs","repos_url":"https://api.github.com/users/myronmarston/repos","events_url":"https://api.github.com/users/myronmarston/events{/privacy}","received_events_url":"https://api.github.com/users/myronmarston/received_events","type":"User","site_admin":false},"created_at":"2015-06-14T05:23:57Z","updated_at":"2015-06-14T05:23:57Z","body":"> I think I narrowed this all down to here: `PartialClassDoubleProxyMethods#original_method_handle_for`\r\n\r\n> This method seems to always build the entire proxy chain.\r\n\r\nYep.  You've correctly identified the source of the issue.\r\n\r\n> It would always have been possible for someone to attempt to stub `ActiveRecord::Base` causing the issue.\r\n\r\nI came to the same conclusion, which is why I forged ahead with the rspec-rails fix.  Users generally don't stub `ActiveRecord::Base` directly, but if they did, the error would have occurred even if rspec-mocks didn't invoke the callback for every ancestor.\r\n\r\n> I do not know enough about this process to understand if building the entire proxy chain is a :bug:, preferable, or simply \"The Right Thing\"™.\r\n\r\nI'd say that building the entire proxy chain is an implementation detail that specifically allows stubbing a class and its superclass (or a subclass) to work.  That said, I think that invoking the verifying double callbacks with each ancestor is a bug.  It's purely accidental due to internal implementation details of the proxies, and not something a user of the callback API would ever expect.  (Consider, for example, that when you do `instance_double(SomeModelClass)`, we do not call the callback with each ancestor of `SomeModelClass`).\r\n\r\n> All I can guess at is, we could attempt to short circuit the proxy chain creation as soon as we found the first un-stubbed method definition in the ancestor chain. However, that will not prevent the entire chain being generated for the case of stubbing new.\r\n\r\nIMO, having the callback invoked for _some_ of the ancestors but not all, would be the worst result, because then it's unpredictable from the user point of view which ancestors the callback will be invoked with.\r\n\r\nHere's what I'm thinking we want to do (although I haven't figured out the details of how to do it, and I'm glad @samphippen has volunteered to step up to the plate!): refactor the internals to no-longer instantiate proxies for each ancestor while maintaining the same external behavior enabled by the logic @cupakromer linked to.\r\n\r\nA good starting point would be to comment out all of the methods of `RSpec::Mocks::PartialClassDoubleProxyMethods` except `initialize`, then see what fails, then try to come up with an alternate implementation that makes them pass.  Maybe that logic could be pulled into some kind of a helper module that would allow you to recurse up the ancestor chain w/o instantiating proxies for each?  Apart from fixing this issue, avoiding instantiating unnecessary/unused proxies sounds like a win for fewer object allocations, anyway :)."}}