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

Commit 4e607c0

Browse files
authored
Merge pull request #1407 from jhottenstein/jess/add-kwarg-support-for-any-instance
Add tests and fix for ruby 3 keyword arguments issues
2 parents 9ed1fdb + e6e0ef0 commit 4e607c0

File tree

3 files changed

+104
-4
lines changed

3 files changed

+104
-4
lines changed

lib/rspec/mocks/any_instance/recorder.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ def observe!(method_name)
261261
recorder.playback!(self, method_name)
262262
__send__(method_name, *args, &blk)
263263
end
264+
@klass.__send__(:ruby2_keywords, method_name) if @klass.respond_to?(:ruby2_keywords, true)
264265
end
265266

266267
def mark_invoked!(method_name)

spec/rspec/mocks/and_call_original_spec.rb

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,26 @@ def meth_2(x)
1212
yield x, :additional_yielded_arg
1313
end
1414

15+
if RSpec::Support::RubyFeatures.kw_args_supported?
16+
binding.eval(<<-RUBY, __FILE__, __LINE__)
17+
def meth_3(**kwargs)
18+
kwargs
19+
end
20+
21+
def meth_4(x: 1)
22+
x
23+
end
24+
RUBY
25+
end
26+
27+
if RSpec::Support::RubyFeatures.required_kw_args_supported?
28+
binding.eval(<<-RUBY, __FILE__, __LINE__)
29+
def meth_5(x:)
30+
x
31+
end
32+
RUBY
33+
end
34+
1535
def self.new_instance
1636
new
1737
end
@@ -125,6 +145,34 @@ def inst.foo; :bar; end
125145
expect(klass.new.meth_1).to eq(:original)
126146
end
127147

148+
if RSpec::Support::RubyFeatures.kw_args_supported?
149+
binding.eval(<<-RUBY, __FILE__, __LINE__)
150+
it 'works for instance methods that use double splat' do
151+
expect_any_instance_of(klass).to receive(:meth_3).and_call_original
152+
expect(klass.new.meth_3(x: :kwarg)).to eq({x: :kwarg})
153+
end
154+
155+
it 'works for instance methods that use optional keyword arguments' do
156+
expect_any_instance_of(klass).to receive(:meth_4).and_call_original
157+
expect(klass.new.meth_4).to eq(1)
158+
end
159+
160+
it 'works for instance methods that use optional keyword arguments with an argument supplied' do
161+
expect_any_instance_of(klass).to receive(:meth_4).and_call_original
162+
expect(klass.new.meth_4(x: :kwarg)).to eq(:kwarg)
163+
end
164+
RUBY
165+
end
166+
167+
if RSpec::Support::RubyFeatures.required_kw_args_supported?
168+
binding.eval(<<-RUBY, __FILE__, __LINE__)
169+
it 'works for instance methods that use required keyword arguments' do
170+
expect_any_instance_of(klass).to receive(:meth_5).and_call_original
171+
expect(klass.new.meth_5(x: :kwarg)).to eq(:kwarg)
172+
end
173+
RUBY
174+
end
175+
128176
it 'works for instance methods defined on the superclass of the class' do
129177
subclass = Class.new(klass)
130178
expect_any_instance_of(subclass).to receive(:meth_1).and_call_original

spec/rspec/mocks/matchers/receive_spec.rb

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,63 @@ module Mocks
5454
receiver.foo(1.1)
5555
end
5656

57-
it 'allows a `do...end` block implementation to be provided' do
58-
wrapped.to receive(:foo) do
59-
4
57+
context 'without yielding receiver' do
58+
# when `yield_receiver_to_any_instance_implementation_blocks` is `true`
59+
# the block arguments are different for `expect` and `expect_any_instance_of`
60+
around do |example|
61+
previous_value = RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks?
62+
RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks = false
63+
example.run
64+
RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks = previous_value
65+
end
66+
67+
it 'allows a `do...end` block implementation to be provided' do
68+
wrapped.to receive(:foo) do
69+
4
70+
end
71+
72+
expect(receiver.foo).to eq(4)
6073
end
6174

62-
expect(receiver.foo).to eq(4)
75+
if RSpec::Support::RubyFeatures.kw_args_supported?
76+
binding.eval(<<-RUBY, __FILE__, __LINE__)
77+
it 'allows a `do...end` block implementation with keyword args to be provided' do
78+
wrapped.to receive(:foo) do |**kwargs|
79+
kwargs[:kw]
80+
end
81+
82+
expect(receiver.foo(kw: :arg)).to eq(:arg)
83+
end
84+
85+
it 'allows a `do...end` block implementation with optional keyword args to be provided' do
86+
wrapped.to receive(:foo) do |kw: :arg|
87+
kw
88+
end
89+
90+
expect(receiver.foo(kw: 1)).to eq(1)
91+
end
92+
93+
it 'allows a `do...end` block implementation with optional keyword args to be provided' do
94+
wrapped.to receive(:foo) do |kw: :arg|
95+
kw
96+
end
97+
98+
expect(receiver.foo).to eq(:arg)
99+
end
100+
RUBY
101+
end
102+
103+
if RSpec::Support::RubyFeatures.required_kw_args_supported?
104+
binding.eval(<<-RUBY, __FILE__, __LINE__)
105+
it 'allows a `do...end` block implementation with required keyword args' do
106+
wrapped.to receive(:foo) do |kw:|
107+
kw
108+
end
109+
110+
expect(receiver.foo(kw: :arg)).to eq(:arg)
111+
end
112+
RUBY
113+
end
63114
end
64115

65116
it 'allows chaining off a `do...end` block implementation to be provided' do

0 commit comments

Comments
 (0)