0

我维护pdf-reader ruby​​ gem,并用它来试验冰糕。我以前没有冰糕的经验。

我想使用类型来改善开发体验,并将类型信息与 gem 一起分发,以便使用 sorbet 的下游用户受益。但是,我想避免添加运行时冰糕依赖项。大多数下游用户不使用 sorbet,他们不应该获得新的运行时依赖项。

我认为这意味着我应该将类型信息作为 *.rbi 文件分发到顶级rbi/目录中。我无法将类型内联到我的源(extend T::Sig等)中。

在开发(和测试/ci)期间,类型信息rbi/*.rbi对于静态类型检查很有用。但是我不能依赖在运行时正确的类型(下游用户可能会传递不同的类型),所以在某些情况下,我仍然想像这样确认类型

def initialize(runs, mediabox)
  raise ArgumentError, "a mediabox must be provided" if mediabox.nil?

...即使我的 rbi 文件声明 mediabox 永远不能为零:

sig { params(runs: T::Array[PDF::Reader::TextRun], mediabox: T::Array[Numeric]).void }
def initialize(runs, mediabox); end

..但随后冰糕对代码不满意:

$ srb tc
./lib/pdf/reader/page_layout.rb:20: This code is unreachable https://srb.help/7006
    20 |      raise ArgumentError, "a mediabox must be provided" if mediabox.nil?
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ./lib/pdf/reader/page_layout.rb:20: This condition was always falsy (T::Boolean)
    20 |      raise ArgumentError, "a mediabox must be provided" if mediabox.nil?
                                                                    ^^^^^^^^^^^^^
  Got T::Boolean originating from:
    ./lib/pdf/reader/page_layout.rb:20:
    20 |      raise ArgumentError, "a mediabox must be provided" if mediabox.nil?
                                                                    ^^^^^^^^^^^^^
Errors: 1

我可以明确忽略该错误:

$ srb tc --suppress-error-code 7006
No errors! Great job.

有什么方法可以保持运行时类型检查而不会抱怨冰糕,也不会忽略错误?或者也许“冰糕方式”只是删除运行时检查并在运行时没有它?

或者我关于只使用 rbi 文件作为类型信息的假设是错误的?

4

1 回答 1

0

添加辅助验证方法:

sig { params(obj: Object, cls: Module).void }
def self.validate(obj, cls)
  raise ArgumentError, "#{obj} must be a #{cls}" unless obj.is_a?(cls)
end

现在,您可以在整个代码中验证类型,而无需添加 sorbet-runtime 依赖项。

您当然也可以引入变体,例如validate_not_null(对于您上面的具体示例)。对于特定于冰糕的类型,例如 ,它确实有点棘手,具体T::Array取决于您希望验证的严格程度。

于 2021-11-21T03:26:37.753 回答