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

Commit 074a363

Browse files
committed
Workaround buggy Method#arity in JRuby
JRuby apparently didn't even properly support #arity for Java proxy methods before 9.0.3.0 (see jruby/jruby@013e288), so this implements a workaround for these versions. The workaround essentially makes use of Java's introspection to figure out matching methods (which could be more than one partly because Java supports multiple overloads, and partly because JRuby introduces aliases to make method names look more Rubyesque). If there is only a single match, we can use that methods arity directly instead of the default -1 arity. One could in theory do better than -1 for various overload sets with multiple methods in them as well, but we have to draw a line somewhere. Given that this issue also impacts JRuby 1.7.x in 1.8-mode, it would require guards around all the #parameters calls to integrate it into the existing workaround, and thus it is implemented as a separate workaround.
1 parent 7820eb2 commit 074a363

File tree

2 files changed

+55
-16
lines changed

2 files changed

+55
-16
lines changed

lib/rspec/support/method_signature_verifier.rb

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -154,25 +154,56 @@ def classify_parameters
154154
INFINITY = 1 / 0.0
155155
end
156156

157-
# JRuby has only partial support for UnboundMethod#parameters, so we fall back on using #arity
158-
# https://github.com/jruby/jruby/issues/2816 and https://github.com/jruby/jruby/issues/2817
159-
if RSpec::Support::Ruby.jruby? &&
160-
RubyFeatures.optional_and_splat_args_supported? &&
161-
Java::JavaLang::String.instance_method(:char_at).parameters == []
157+
if RSpec::Support::Ruby.jruby?
158+
# JRuby has only partial support for UnboundMethod#parameters, so we fall back on using #arity
159+
# https://github.com/jruby/jruby/issues/2816 and https://github.com/jruby/jruby/issues/2817
160+
if RubyFeatures.optional_and_splat_args_supported? &&
161+
Java::JavaLang::String.instance_method(:char_at).parameters == []
162+
163+
class MethodSignature < remove_const(:MethodSignature)
164+
private
165+
166+
def classify_parameters
167+
super
168+
if (arity = @method.arity) != 0 && @method.parameters.empty?
169+
if arity < 0
170+
@min_non_kw_args = ~arity
171+
@max_non_kw_args = INFINITY
172+
else
173+
@min_non_kw_args = arity
174+
@max_non_kw_args = arity
175+
end
176+
end
177+
end
178+
end
179+
end
162180

163-
class MethodSignature < remove_const(:MethodSignature)
164-
private
181+
# JRuby used to always report -1 arity for Java proxy methods
182+
if Java::JavaLang::String.instance_method(:char_at).arity == -1
183+
class MethodSignature < remove_const(:MethodSignature)
184+
private
185+
186+
def classify_parameters
187+
super
188+
if @method.arity == -1
189+
arity = java_single_overload_arity
190+
if arity < 0
191+
@min_non_kw_args = ~arity
192+
@max_non_kw_args = INFINITY
193+
else
194+
@min_non_kw_args = arity
195+
@max_non_kw_args = arity
196+
end
197+
end
198+
end
165199

166-
def classify_parameters
167-
super
168-
if (arity = @method.arity) != 0 && @method.parameters.empty?
169-
if arity < 0
170-
@min_non_kw_args = ~arity
171-
@max_non_kw_args = INFINITY
172-
else
173-
@min_non_kw_args = arity
174-
@max_non_kw_args = arity
200+
def java_single_overload_arity
201+
return @method.arity unless @method.owner.respond_to?(:java_class)
202+
java_instance_methods = @method.owner.java_class.java_instance_methods
203+
compatible_overloads = java_instance_methods.select do |java_method|
204+
@method == @method.owner.instance_method(java_method.name)
175205
end
206+
(compatible_overloads.size == 1) ? compatible_overloads.first.arity : @method.arity
176207
end
177208
end
178209
end

spec/rspec/support/method_signature_verifier_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,14 @@ def arity_block(_, &block); end
727727
it 'validates against a single argument' do
728728
expect(valid_non_kw_args?(1)).to eq true
729729
end
730+
731+
it 'fails validation against 0 arguments' do
732+
expect(valid_non_kw_args?(0)).to eq false
733+
end
734+
735+
it 'fails validation against 2 arguments' do
736+
expect(valid_non_kw_args?(2)).to eq false
737+
end
730738
end
731739
end
732740
end

0 commit comments

Comments
 (0)