Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit 0a852ba

Browse files
committed
Merge pull request #1394 from mame/with-for-ruby3
Make `with` support Ruby 3 keywords
1 parent 8635dda commit 0a852ba

File tree

5 files changed

+43
-12
lines changed

5 files changed

+43
-12
lines changed

lib/rspec/mocks/argument_list_matcher.rb

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,30 @@ def initialize(*expected_args)
4646
@expected_args = expected_args
4747
ensure_expected_args_valid!
4848
end
49+
ruby2_keywords :initialize if Module.private_method_defined?(:ruby2_keywords)
4950

5051
# @api public
51-
# @param [Array] args
52+
# @param [Array] actual_args
5253
#
5354
# Matches each element in the `expected_args` against the element in the same
5455
# position of the arguments passed to `new`.
5556
#
5657
# @see #initialize
57-
def args_match?(*args)
58-
Support::FuzzyMatcher.values_match?(resolve_expected_args_based_on(args), args)
58+
def args_match?(*actual_args)
59+
expected_args = resolve_expected_args_based_on(actual_args)
60+
61+
return false if expected_args.size != actual_args.size
62+
63+
if RUBY_VERSION >= "3"
64+
# if both arguments end with Hashes, and if one is a keyword hash and the other is not, they don't match
65+
if Hash === expected_args.last && Hash === actual_args.last
66+
if !Hash.ruby2_keywords_hash?(actual_args.last) && Hash.ruby2_keywords_hash?(expected_args.last)
67+
return false
68+
end
69+
end
70+
end
71+
72+
Support::FuzzyMatcher.values_match?(expected_args, actual_args)
5973
end
6074

6175
# @private

lib/rspec/mocks/matchers/receive.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def setup_any_instance_allowance(subject, &block)
6262
@recorded_customizations << ExpectationCustomization.new(method, args, block)
6363
self
6464
end
65+
ruby2_keywords(method) if Module.private_method_defined?(:ruby2_keywords)
6566
end
6667

6768
private

lib/rspec/mocks/message_expectation.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ def with(*args, &block)
364364
@argument_list_matcher = ArgumentListMatcher.new(*args)
365365
self
366366
end
367+
ruby2_keywords(:with) if Module.private_method_defined?(:ruby2_keywords)
367368

368369
# Expect messages to be received in a specific order.
369370
#

spec/rspec/mocks/argument_matchers_spec.rb

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -379,16 +379,26 @@ def ==(other)
379379
a_double.random_call(:a => "a", :b => "b")
380380
end
381381

382-
it "matches against a hash submitted by reference and received by value" do
382+
it "matches against a hash submitted as keyword arguments a and received as a positional argument (in both Ruby 2 and Ruby 3)" do
383383
opts = {:a => "a", :b => "b"}
384384
expect(a_double).to receive(:random_call).with(opts)
385385
a_double.random_call(:a => "a", :b => "b")
386386
end
387387

388-
it "matches against a hash submitted by value and received by reference" do
389-
opts = {:a => "a", :b => "b"}
390-
expect(a_double).to receive(:random_call).with(:a => "a", :b => "b")
391-
a_double.random_call(opts)
388+
if RUBY_VERSION >= "3"
389+
it "fails to matches against a hash submitted as a positional argument and received as keyword arguments in Ruby 3.0 or later", :reset => true do
390+
opts = {:a => "a", :b => "b"}
391+
expect(a_double).to receive(:random_call).with(:a => "a", :b => "b")
392+
expect do
393+
a_double.random_call(opts)
394+
end.to fail_with(/expected: \(\{(:a=>\"a\", :b=>\"b\"|:b=>\"b\", :a=>\"a\")\}\)/)
395+
end
396+
else
397+
it "matches against a hash submitted as a positional argument and received as keyword arguments in Ruby 2.7 or before" do
398+
opts = {:a => "a", :b => "b"}
399+
expect(a_double).to receive(:random_call).with(:a => "a", :b => "b")
400+
a_double.random_call(opts)
401+
end
392402
end
393403

394404
it "fails for a hash w/ wrong values", :reset => true do

spec/rspec/mocks/partial_double_spec.rb

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,15 @@ def call(name)
8181
expect(object.foobar(:key => "value")).to equal(1)
8282
end
8383

84-
it "can accept an inner hash as a message argument" do
85-
hash = {:a => {:key => "value"}}
86-
expect(object).to receive(:foobar).with(:key => "value").and_return(1)
87-
expect(object.foobar(hash[:a])).to equal(1)
84+
if RSpec::Support::RubyFeatures.required_kw_args_supported?
85+
# Use eval to avoid syntax error on 1.8 and 1.9
86+
binding.eval(<<-CODE, __FILE__, __LINE__)
87+
it "can accept an inner hash as a message argument" do
88+
hash = {:a => {:key => "value"}}
89+
expect(object).to receive(:foobar).with(:key => "value").and_return(1)
90+
expect(object.foobar(**hash[:a])).to equal(1)
91+
end
92+
CODE
8893
end
8994

9095
it "can create a positive message expectation" do

0 commit comments

Comments
 (0)