Home > Blockchain >  Require Elem when using Sorbet RBI
Require Elem when using Sorbet RBI

Time:12-21

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:

  1. 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
  2. You can use T::Sig::WithoutRuntime.sig instead of sig to write your signature, as explained here.
  • Related