简体   繁体   English

我应该如何管理类型信息必须在 rbi 文件中而不是内联的 gem 中的冰糕错误?

[英]How should I manage sorbet errors in a gem where type info must be in rbi files and not inline?

I maintain the pdf-reader ruby gem and I'm using it to experiment with sorbet.我维护了pdf 阅读器ruby gem,我用它来试验冰糕。 I have no prior experience with sorbet.我以前没有冰糕的经验。

I'd like to use types to improve the development experience, and distribute the type info with the gem so downstream users who use sorbet can benefit.我想使用类型来改善开发体验,并将类型信息与 gem 一起分发,以便使用 sorbet 的下游用户受益。 However, I'd like to avoid adding a runtime sorbet dependency.但是,我想避免添加运行时冰糕依赖项。 Most downstream users do not use sorbet, and they shouldn't gain a new runtime dependency.大多数下游用户不使用 sorbet,他们不应该获得新的运行时依赖项。

I think that means I should distribute the type info as a *.rbi file(s) inside the top level rbi/ directory.我认为这意味着我应该将类型信息作为 *.rbi 文件分发到顶级rbi/目录中。 I'm not able to inline the types into my source ( extend T::Sig , etc).我无法将类型内联到我的源代码中( extend T::Sig等)。

During development (and test/ci) the type info in rbi/*.rbi is useful for static type checking.在开发(和测试/ci)期间, rbi/*.rbi中的类型信息对于 static 类型检查很有用。 However I can't rely on the types being correct at runtime (where downstream users might pass different types), so in some cases I still want to confirm the type like this :但是我不能依赖在运行时正确的类型(下游用户可能会传递不同的类型),所以在某些情况下,我仍然想像这样确认类型

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

...even though my rbi file declares mediabox can never be nil: ...即使我的 rbi 文件声明 mediabox 永远不能为零:

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

.. but then sorbet is unhappy with the code: ..但随后冰糕对代码不满意:

$ 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

I can explicitly ignore that error:我可以明确忽略该错误:

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

Is there any way to keep the runtime type check without sorbet complaining, and without ignoring the error?有什么方法可以保持运行时类型检查而不会抱怨冰糕,也不会忽略错误? Or maybe the "sorbet way" is just to remove the runtime check and live without it at runtime?或者也许“冰糕方式”只是删除运行时检查并在运行时没有它?

Or maybe my assumptions about only using rbi files for the type info are wrong?或者我关于只使用 rbi 文件作为类型信息的假设是错误的?

Add a helper validation method:添加辅助验证方法:

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

Now you can validate types throughout your code without adding a sorbet-runtime dependency.现在,您可以在整个代码中验证类型,而无需添加 sorbet-runtime 依赖项。

You can of course also introduce variations such as validate_not_null (for your specific example above).您当然也可以引入变体,例如validate_not_null (对于您上面的具体示例)。 It does get a bit tricky with sorbet-specific types such as T::Array , depending on how rigorous you want your validations to be.对于特定于冰糕的类型(例如T::Array ),它确实有点棘手,具体取决于您希望验证的严格程度。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM