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])
CodePudding user response:
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 two ways you can square this circle:
- You can move the inline signature for
Array#split_on
to an RBI file, which will make the signature checked only statically (based on what I said about RBI files above), or - You can use
T::Sig::WithoutRuntime.sig
instead ofsig
to write your signature, as explained here.