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.