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
Handle keyword arguments separately for and_call_original in supported rubies #1324
Conversation
I'm still getting a warning running this: class Foo
def initialize(bar: nil); end
end
RSpec.describe Foo do
it 'works' do
expect(Foo).to receive(:new).with(bar: :qux).and_call_original
Foo.new(bar: :qux)
end
end |
Ah thats a slightly difference scenario, I think we need more tests around this. |
That's from #1306 🤷♂ |
Yeah I had written a similar spec assuming it was |
Does #1324 (comment) will be handle in this PR too? |
Yep I'll be continuing some work over in rspec support later, and then using that with more scenarios to fix this. |
Any update on this? |
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.
Looks good.
Do you mind for another CI run just in case?
Shame on me. There's still this receive(:new)
case left to fix.
@pirj rspec/rspec-support#419 should solve the case you mentioned, although it's a bit hacky so I'm not sure if it will get accepted. |
Pushed a spec to cover the original request. |
@JonRowe It seems we either have to merge rspec/rspec-support#419, or to close it and pull the |
Quick win while waiting for the patch. Bump to Ruby 2.7.2 released this week. No more warnings. |
That would be just perfect if we didn't have to do anything tricky with RSpec to be kwargs-compliant and no warnings were issued! Wondering if this means there's a performance impact in Ruby 3. I'm more inclined to let postpone those fixes if the performance gain is marginal rather than maintain this burden up to the point when we drop support for Ruby 2.x (for three more years to come or so). |
The warnings just become opt-in in 2.7.2, they don't change the fact we need to change these things before Ruby 3.0 is released. |
Yes of course. :) |
I spend already 5 hours trying to implement rspec/rspec-support#419 (comment) but I'm stuck. I am not able to fix the failing spec here. @pirj or @JonRowe will you be available to tackle this in pairing with me ? I understand we need to find the right signature for the |
@benoittgt I'm available tomorrow in the afternoon. Lost track of what's going on, so you lead, me |
Oops 🙃
I am providing two more failures for diff --git a/spec/rspec/mocks/and_call_original_spec.rb b/spec/rspec/mocks/and_call_original_spec.rb
index 25c5a85c..4459142a 100644
--- a/spec/rspec/mocks/and_call_original_spec.rb
+++ b/spec/rspec/mocks/and_call_original_spec.rb
@@ -88,6 +88,18 @@ RSpec.describe "and_call_original" do
expect(instance.initialize_arg).to eq :initialize_arg
CODE
end
+
+ it 'works with keyword arguments for and_wrap_original' do
+ expect(instance).to receive(:meth_3).and_wrap_original { |m, keyword_arg:| m.call(keyword_arg: keyword_arg.to_s) }
+
+ expect(instance.meth_3(keyword_arg: :original_arg)).to eq 'original_arg'
+ end
+
+ it 'works with keyword arguments for block implementation' do
+ expect(instance).to receive(:meth_4) { |keyword_arg:| keyword_arg }
+
+ expect(instance.meth_4(keyword_arg: :original_arg)).to eq :original_arg
+ end
end
it 'errors when you pass through the wrong number of args' do Or in Ruby: it 'works with keyword arguments for and_wrap_original' do
expect(instance).to receive(:meth_3).and_wrap_original { |m, keyword_arg:| m.call(keyword_arg: keyword_arg.to_s) }
expect(instance.meth_3(keyword_arg: :original_arg)).to eq 'original_arg'
end
it 'works with keyword arguments for block implementation' do
expect(instance).to receive(:meth_4) { |keyword_arg:| keyword_arg }
expect(instance.meth_4(keyword_arg: :original_arg)).to eq :original_arg
end |
This fixed diff --git a/lib/rspec/mocks/message_expectation.rb b/lib/rspec/mocks/message_expectation.rb
index d999dc0f..643b7ca5 100644
--- a/lib/rspec/mocks/message_expectation.rb
+++ b/lib/rspec/mocks/message_expectation.rb
@@ -115,7 +115,9 @@ module RSpec
# original_method.call(*args, &block).first(10)
# end
def and_wrap_original(&block)
- wrap_original(__method__, &block)
+ wrap_original(__method__) do |original, *args, &supplied_block|
+ __call_original(block, original, *args, &supplied_block)
+ end
end
# @overload and_raise |
@JonRowe What's the status on getting this finished up and merged? |
@bryanp According to the plan, quite a lot of method have to be marked with I took a stab at a similar You can certainly help. There is this #1306 (comment) that you can turn into a failing spec like this https://github.com/rspec/rspec-mocks/pull/1383/files#diff-ee4bec83cefa8d926951324b0059b58f31c016628981f29a0c391cd9b8a51315R15. After that, apply the approach described here rspec/rspec-expectations#1221 (comment) and (in brief) here rspec/rspec-expectations#1241 (comment). If you decide to do so, please open a draft PR so we can avoid double work and intervene early in the process. |
✅ Locally, for Ruby <= 2.7.2 specs are all passing ❌ For Ruby 3.0 some specs are failing. All errors seem to be related to the changed behavior for kwargs -> **update**: see comments below! ``` Finished in 19.31 seconds (files took 0.67243 seconds to load) 123 examples, 7 failures Failed examples: rspec ./spec/zip_tricks/block_deflate_spec.rb:46 # ZipTricks::BlockDeflate deflate_in_blocks_and_terminate uses deflate_in_blocks rspec ./spec/zip_tricks/block_deflate_spec.rb:58 # ZipTricks::BlockDeflate deflate_in_blocks_and_terminate passes a custom compression level rspec ./spec/zip_tricks/block_deflate_spec.rb:87 # ZipTricks::BlockDeflate.deflate_in_blocks honors the block size rspec ./spec/zip_tricks/rails_streaming_spec.rb:4 # ZipTricks::RailsStreaming calls the requisite controller methods rspec ./spec/zip_tricks/streamer_spec.rb:276 # ZipTricks::Streamer writes the correct archive elements when using data descriptors rspec ./spec/zip_tricks/streamer_spec.rb:420 # ZipTricks::Streamer prevents duplicates in the stored files rspec ./spec/zip_tricks/streamer_spec.rb:525 # ZipTricks::Streamer writes the specified modification time ``` -> I've added a new issue to address the actual fixes for Ruby 3 in a separated PR: #104 **update** the actual problem (for the first spec at least) is `rspec-mocks`, in particular this line: https://github.com/rspec/rspec-mocks/blob/6ab343ca479c606e892c82ce0245e7410e3f0eac/lib/rspec/mocks/message_expectation.rb#L101 ```ruby def and_call_original wrap_original(__method__) do |original, *args, &block| original.call(*args, &block) end end ``` which will receive the following `args`: ```ruby [#<StringIO:0x00007ff8d713bfc8>, #<StringIO:0x00007ff8d713be88>, {:level=>-1, :block_size=>65536}] ``` hence this is expanded to 3 params, 2x a string, and a hash, which is then not splatted into kwargs. Further research shows, there is already an Issue: rspec/rspec-mocks#1306 with a fixing PR: rspec/rspec-mocks#1324
✅ Locally, for Ruby <= 2.7.2 specs are all passing ❌ For Ruby 3.0 some specs are failing. All errors seem to be related to the changed behavior for kwargs -> **update**: see comments below! ``` Finished in 19.31 seconds (files took 0.67243 seconds to load) 123 examples, 7 failures Failed examples: rspec ./spec/zip_tricks/block_deflate_spec.rb:46 # ZipTricks::BlockDeflate deflate_in_blocks_and_terminate uses deflate_in_blocks rspec ./spec/zip_tricks/block_deflate_spec.rb:58 # ZipTricks::BlockDeflate deflate_in_blocks_and_terminate passes a custom compression level rspec ./spec/zip_tricks/block_deflate_spec.rb:87 # ZipTricks::BlockDeflate.deflate_in_blocks honors the block size rspec ./spec/zip_tricks/rails_streaming_spec.rb:4 # ZipTricks::RailsStreaming calls the requisite controller methods rspec ./spec/zip_tricks/streamer_spec.rb:276 # ZipTricks::Streamer writes the correct archive elements when using data descriptors rspec ./spec/zip_tricks/streamer_spec.rb:420 # ZipTricks::Streamer prevents duplicates in the stored files rspec ./spec/zip_tricks/streamer_spec.rb:525 # ZipTricks::Streamer writes the specified modification time ``` -> I've added a new issue to address the actual fixes for Ruby 3 in a separated PR: WeTransfer#104 **update** the actual problem (for the first spec at least) is `rspec-mocks`, in particular this line: https://github.com/rspec/rspec-mocks/blob/6ab343ca479c606e892c82ce0245e7410e3f0eac/lib/rspec/mocks/message_expectation.rb#L101 ```ruby def and_call_original wrap_original(__method__) do |original, *args, &block| original.call(*args, &block) end end ``` which will receive the following `args`: ```ruby [#<StringIO:0x00007ff8d713bfc8>, #<StringIO:0x00007ff8d713be88>, {:level=>-1, :block_size=>65536}] ``` hence this is expanded to 3 params, 2x a string, and a hash, which is then not splatted into kwargs. Further research shows, there is already an Issue: rspec/rspec-mocks#1306 with a fixing PR: rspec/rspec-mocks#1324
Fixes #1306