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
equal matcher broken for Delegator since 309c4f08b59651737ddc8c3c6e0167220b604b12 #148
Comments
Looks like my original workaround only works on master, on 2.10.0 you need to require a different file, and you don't have to call a method. This is the best workaround I can think of currently to handle both 2.10.0 and the master branch:
|
@jeremyevans -- thanks for the detailed bug report, and taking the time to test Sequel against unreleased rspec versions! It's funny that you mention having the problem with delegate; I had some problems with delegate that were the impetus for enabling some syntax changes to rspec-expectations, and these changes fell out of that. The main changes to rspec-expectations are discussed in length in #119. We've realized that the The solution we came up with is a new syntax: c = Class.new(DelegateClass(Array))
o = c.new([1, 2])
expect(o).to equal(o) By default, both the old
Kernel is still modified when rspec-expectations are loaded, but it may happen at a slightly different point now (the file may get required after another file as already required delegator, for example). Currently it happens in rspec/matchers/configuration.rb. As far as workarounds go, I believe this should work: if defined?(RSpec::Expectations::Syntax)
require 'delegate'
RSpec::Expectations::Syntax.enable_should(Delegator)
end
Anyhow, I want to fix this in rspec-expectations so that users don't have to use this kind of hack to have it work with
Sequel's specs work on all rspec versions >= 1.3? That's pretty crazy cool! I've never heard of a project doing that before (plenty of projects work with lots of versions of runtime dependencies, but it's rare for a project to do that with the testing library it uses). What benefit do you get out of maintaining that level of compatibility? |
Myron, Thanks for the quick response. I like the new #expect syntax and how it works around the issue, but I don't want to force everyone testing Sequel to upgrade to the master branch of rspec-expectations. I tried the I think Sequel's specs work on RSpec 1.2.x+ (not sure which point version), but I don't test on RSpec 1.2 any longer. I do test regularly on RSpec 1.3. As to the benefit of working on both RSpec 1 and 2, it's probably small, but it's been fairly easy to keep it working on both, so there hasn't been a reason to stop working on older versions. This issue is the first RSpec-related problem I remember having in years. Thanks for looking into the issue, hopefully there's a simpler fix than the ugly workaround I used. |
OK, so I think I've figured it out. The changes in rspec-expectations that you pointed out looked like the source of the regression, but it turns out it's due to a change in rspec-core: Before that commit, rspec-core loaded the rspec-expecations kernel extension, causing So...before RSpec 2.10, when you had a spec that loaded and used the The way to fix this is to manually load require 'rspec/expectations'
require 'delegate'
describe 'should equal' do
it "should not falsely raise an error when the two things are equal" do
c = Class.new(DelegateClass(Array))
o = c.new([1, 2])
o.should equal(o)
end
end I'm not sure what we should do (if anything) to fix this. Any ideas? |
Thanks, that appears to work and greatly simplifies the workaround I was using. |
Great, I'm glad that fixed it for you. I've been trying to think of a way to fix it, and none of the options I've thought of are very appealing:
Given that we have a proper solution now (use the new |
The workaround works almost everywhere. However, it appears on jruby 1.7.0 preview 1 (and jruby-head), delegate is required by rspec, causing it to fail. Code:
Output:
Some simple checking shows that rspec requires delegator on jruby 1.7.0:
Is there anything that can be done about this inside RSpec? |
Hmm...I'm not seeing the same thing with jruby 1.6.7.2 (the jruby I installed recently with RVM). Maybe there's a jruby regression in there somewhere?
I mentioned the only ways to deal with this I can think of above, but I find both to be distasteful, unfortunately. Got any better ideas? |
I just install |
OK, I think I've figured out what's going on.
I just pushed an attempted fix to rspec-core, to the delay-drb-loading branch. Can you give that a try? It fixed the problem for me. I need to do a bit more testing before pushing it into rspec-core master since drb is tricky to test with unit tests. |
The delay-drb-loading branch appears to fix both the simple test case and Sequel's extension specs on jruby 1.7.0. Thanks! |
This has been merged into rspec-core. |
Commit 309c4f0 changed the should/should_not integration into Kernel in such a way that it breaks the equal matcher on DelegateClass instances.
Consider the following code:
On RSpec 2.9 and previous versions, this example passes. On RSpec 2.10 and later versions, this example fails.
The reason behind this is the implementation of the delegate library in the stdlib, which does this:
Basically, at the time the delegate library is loaded, it checks the Kernel module for methods and defines most of those methods on the Delegate class. So with the previous RSpec code, the Kernel module was modified by default when RSpec was loaded, so when you loaded the delegate library after that, the should/should_not methods were included in the "kernel" module that is included in Delegator.
Commit 309c4f0 changes this so that Kernel is not modified by default when RSpec is loaded, it is not modified till later (unsure exactly when, looks like first example group definition from some brief testing). Unfortunately, this means that the should/should_not methods are not defined on Delegator, so when they are called, method_missing calls the method on the delegated object instead of the Delegator itself. Since equal checks for identity, and the delegated object is not the same as the Delegator instance, this breaks the equal matcher.
The only work around I can see now is enabling the should/should_not Kernel integration before requiring delegate:
This is ugly but appears to work. Unfortunately, I don't know how portable it is to older versions of RSpec.
This isn't a hypothetical error, this causes some of Sequel's specs to break. As Sequel's specs are designed to work on all versions of RSpec (going back to at least RSpec 1.3), I would prefer a direct fix or a workaround that wasn't RSpec version dependent. The only simple way I can think of for doing that now would be to call RSpec::Expectations::Syntax.enable_should at the end of the rspec/expectations/syntax.rb file and requiring the rspec/expectations/syntax.rb file when RSpec is initially loaded. However, that may cause other issues that I cannot foresee.
The text was updated successfully, but these errors were encountered: