Skip to content

Commit

Permalink
Respect Ruby 3's conversion from keywords to a positional last Hash
Browse files Browse the repository at this point in the history
This change allows a Hash argument expectation (`with({ a: 'a' })`) to
accept keyword arguments (`foo(a: 'a')`) both in Ruby 2 and in Ruby 3.

```
allow(foo).to receive(:bar).with({ a: 'a' })

foo.bar(a: 'a')
foo.bar({ a: 'a' })
```

This is because Ruby 3 also allows the automatic conversion from
keywords to a positional Hash. (But the conversion from a positional
last Hash to keywords is not allowed.)

```
def foo(opts = {})
end

foo(a: 'a')
foo({ a: 'a' })
```
  • Loading branch information
mame committed Jan 8, 2021
1 parent 0a1e644 commit 31cbd3c
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 15 deletions.
2 changes: 1 addition & 1 deletion lib/rspec/mocks/argument_list_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def args_match?(*actual_args)
if Hash.respond_to?(:ruby2_keywords_hash?, true)
# if both arguments end with Hashes, and if one is a keyword hash and the other is not, they don't match
if Hash === expected_args.last && Hash === actual_args.last
if Hash.ruby2_keywords_hash?(actual_args.last) != Hash.ruby2_keywords_hash?(expected_args.last)
if !Hash.ruby2_keywords_hash?(actual_args.last) && Hash.ruby2_keywords_hash?(expected_args.last)
return false
end
end
Expand Down
18 changes: 4 additions & 14 deletions spec/rspec/mocks/argument_matchers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -381,20 +381,10 @@ def ==(other)
a_double.random_call(:a => "a", :b => "b")
end

if RSpec::Support::RubyFeatures.required_kw_args_supported?
it "fails to match against a hash submitted by reference and received by value in Ruby 3", :reset => true do
opts = {:a => "a", :b => "b"}
expect(a_double).to receive(:random_call).with(opts)
expect do
a_double.random_call(:a => "a", :b => "b")
end.to fail_with(/expected: \(\{:a=>"a", :b=>"b"|:b=>"b", :a=>"a"\}\)/)
end
else
it "matches against a hash submitted by reference and received by value in Ruby 2" do
opts = {:a => "a", :b => "b"}
expect(a_double).to receive(:random_call).with(opts)
a_double.random_call(:a => "a", :b => "b")
end
it "matches against a hash submitted by reference and received by value (in both Ruby 2 and Ruby 3)" do
opts = {:a => "a", :b => "b"}
expect(a_double).to receive(:random_call).with(opts)
a_double.random_call(:a => "a", :b => "b")
end

if RSpec::Support::RubyFeatures.required_kw_args_supported?
Expand Down

0 comments on commit 31cbd3c

Please sign in to comment.