-
-
Notifications
You must be signed in to change notification settings - Fork 397
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
Ruby 3.0.3 and keyword arguments #1350
Comments
Ruby keyword arguments are tricky, there is no correct way to capture them and maintain compatibility with Ruby 2, the best approach is to add In any case can you provide a snippet of how you encountered this issue (not our code, but your code that triggered it) because in many cases if you're creating a custom matcher or using blocks you can work around this by simply capturing the keywords using **kwargs yourself |
Could this be the cause of rspec/rspec-mocks#1505? |
spec/support/kwargs_chain_matcher.rb RSpec::Matchers.define :work_with_ruby3_kwargs do
match do |actual|
true
end
chain :but do |value, does: true|
true
end
end spec/spec_helper.rb require_relative "support/kwargs_chain_matcher"
# ... spec/kwargs_chain_spec.rb RSpec.describe "ruby 3 kwargs chain matcher" do
it "should work" do
expect("kwargs chain matcher").to work_with_ruby3_kwargs.but("it", does: :not)
end
end bundle exec rspec spec/kwargs_chain_spec.rb
|
capturing chain :also_capturing_but do |value, **kwargs|
true
end context "when capturing kwargs" do
it "should work" do
expect("kwargs chain matcher").to work_with_ruby3_kwargs.also_capturing_but("it", does: :not)
end
end
|
FWIW, I'm encountering this problem as I am trying to migrate a number of apps to Ruby 3 due to the imminent EOL of Ruby 2. In the short term, I'm probably going to monkey-patch around it as follows, but it's not ideal, obviously. module RSpec
module Matchers
module DSL
module Macros
def chain(method_name, *attr_names, &definition)
unless block_given? ^ attr_names.any?
raise ArgumentError, "You must pass either a block or some attribute names (but not both) to `chain`."
end
definition = assign_attributes(attr_names) if attr_names.any?
define_user_override(method_name, definition) do |*args, **kwargs, &block|
super(*args, **kwargs, &block)
@chained_method_clauses.push([method_name, [*args, kwargs]])
self
end
end
end
end
end
end I haven't properly tested the above, so it might break on certain use-cases. |
A quick fix for both examples with define_user_override(method_name, definition) do |*args, &block|
super(*args, &block)
@chained_method_clauses.push([method_name, args])
self
end
+ ruby2_keywords method_name if respond_to?(:ruby2_keywords, true)
end A PR is welcome with this and a spec covering the case with |
it should be able to support it if we drop support for 2.6 and below, keeping 2.7 for another year. I'm not sure those are still all needed. rspec-expectations/.github/workflows/ci.yml Lines 48 to 52 in 8a468ee
Also maybe its time to bump
|
@mathieujobin our plans are to do just that in the next major version of RSpec, but theres a few things to organise to get that onde. |
Subject of the issue
When using ruby 3.0.3 manually defined chained rspec matchers with keyword parameters don't forwards the arguments correctly
Your environment
Description
Checkout the file:
https://github.com/rspec/rspec-expectations/blob/main/lib/rspec/matchers/dsl.rb
Go to row 304 and 305, they currently look like this:
and accordingly to this explanation for ruby 3 they should look like
Am I overseeing something?
Thanks in advance!
Best regards,
Lukas
The text was updated successfully, but these errors were encountered: