I want to extend the standard Array with a new instance method but I keep getting a runtime error about the type_member not being found.
The definition looks like this.
class Array
extend T::Sig
extend T::Generic
sig do
type_parameters(:U)
.params(split_elem: T.type_parameter(:U))
.returns(T::Array[Elem])
end
def split_on(split_elem)
output = []
group = []
each do |elem|
if elem.eql?(split_elem)
output << group unless group.empty?
group = []
else
group << elem
end
end
output << group unless group.empty?
output
end
end
Is there a way to explicitly require the rbi file declaring Elem?
When trying to run the code, I get the following error. I have tried requiring the sorbet-runtime but no success so far.
NameError: uninitialized constant Array::Elem
.returns(T::Array[Elem])
RBI files are purely static artifacts, they are not meant to be required or run in any way. So, the high-level answer to your question is "no, you can't require RBI files".
The problem you are facing is that you are adding a signature that is statically checkable (i.e. Sorbet can understand Elem and type-check your code without running it), but it is not valid at runtime, since there is no actual Elem constant under the Ruby Array class.
There are three ways you can square this circle:
T.self_type as the return type, which will solve your problem with Elem. Docs for T.self_type are here.Array#split_on to an RBI file, which will make the signature checked only statically (based on what I said about RBI files above), orT::Sig::WithoutRuntime.sig instead of sig to write your signature, as explained here.