我正在一个实验性开源项目 ( ruby_crystal_codemod ) 中试用 Sorbet 。我无法弄清楚如何让类型检查与嵌套测试项目中的某些 RSpec 测试一起使用。当我运行时srb tc,我看到一些像这样的类型检查错误:
spec/src/example_class_annotated_spec.rb:6: Method it does not exist on T.class_of(<root>) https://srb.help/7003
6 | it 'should add @foo and @bar' do
7 | instance = ExampleClass.new(2, 3, 4)
8 | expect(instance.add).to eq 5
9 | end
spec/src/example_class_annotated_spec.rb:8: Method expect does not exist on T.class_of(<root>) https://srb.help/7003
8 | expect(instance.add).to eq 5
^^^^^^^^^^^^^^^^^^^^
https://github.com/sorbet/sorbet/tree/67cd17f5168252fdec1ad04839b31fdda8bc6155/rbi/core/kernel.rbi#L2662: Did you mean: Kernel#exec?
2662 | def exec(*args); end
^^^^^^^^^^^^^^^
spec/src/example_class_annotated_spec.rb:8: Method eq does not exist on T.class_of(<root>) https://srb.help/7003 …Run Code Online (Sandbox Code Playgroud) Here's example code:
# typed: true
class KeyGetter
sig {params(env_var_name: String).returns(KeyGetter)}
def self.from_env_var(env_var_name)
return Null.new if env_var_name.nil?
return new(env_var_name)
end
def initialize(env_var_name)
@env_var_name = env_var_name
end
def to_key
"key from #{@env_var_name}"
end
def to_s
"str from #{@env_var_name}"
end
class Null
def to_key; end
def to_s; end
end
end
Run Code Online (Sandbox Code Playgroud)
Running srb tc on it fails with
key_getter.rb:7: Returning value that does not conform to method result type https://srb.help/7005
7 | return Null.new if env_var_name.nil?
^^^^^^^^^^^^^^^
Expected KeyGetter
key_getter.rb:6: Method from_env_var has …Run Code Online (Sandbox Code Playgroud) 我正在尝试在 Rails 项目上测试 Sorbet。
gem sorbet-rails# typed: true但实际上并没有发生任何事情,我想我错过了拼图的一部分。有没有人找到让 Sorbet 与 Vs Code 一起工作的解决方案
谢谢
Sorbet正在显示attr_reader的错误,但是请纠正我,如果我错了,则在声明该函数(而不是调用该函数)时需要sig,对吗?
我已经尝试过文档,但我得到的只是这份笔记
注意:许多看起来像局部变量的Ruby构造实际上是没有括号的方法调用!具体来说,请注意attr_reader和零参数方法定义。
app/util/hodor.rb:125: This function does not have a `sig` https://sorbet.org/docs/error-reference#7017
125 | attr_reader(:collection_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud) 我有一个具有冰糕类型签名定义的方法。尝试在使用RSpec的测试中模拟此方法时,出现类型不匹配错误。我试图了解如何解决此问题并添加基于RSpec的测试而不影响冰糕类型检查。
sig {params(login_context: LoginContext, company_id: String).returns(T::Boolean)}
def populate_dummy_data(login_context, company_id)
Run Code Online (Sandbox Code Playgroud)
测试代码:
@login_context = double(LoginContext, :requester => @requester) # Creates an instance of type Rspec::Mocks::double
Run Code Online (Sandbox Code Playgroud)
错误:
expected no Exception, got #<TypeError: Parameter ‘login_context’: Expected type LoginContext, got type RSpec::Mocks::Double wit...a_populator_spec.rb:42
Run Code Online (Sandbox Code Playgroud) 我有一个带有 jsonb 列的模型。此列仅接受 json 对象。Sorbet 正确生成包含以下内容的 .rbi 文件:
module PushedContent::GeneratedAttributeMethods
sig { returns(T.nilable(T.any(T::Array[T.untyped], T::Boolean, Float, T::Hash[T.untyped, T.untyped], Integer, String))) }
def value; end
sig { params(value: T.nilable(T.any(T::Array[T.untyped], T::Boolean, Float, T::Hash[T.untyped, T.untyped], Integer, String))).void }
def value=(value); end
end
Run Code Online (Sandbox Code Playgroud)
jsonb 列将始终存储数组或哈希值。由于这些方法签名不能满足我的需求,我决定在文件夹下的我自己的文件中覆盖它们:sorbet/rbi/types/app/models/model.rbi
module PushedContent::GeneratedAttributeMethods
sig { returns(T.nilable(T::Array[T.untyped], T::Hash[T.untyped, T.untyped])) }
def value; end
sig { params(value: T.nilable(T::Array[T.untyped], T::Hash[T.untyped, T.untyped])).void }
def value=(value); end
end
Run Code Online (Sandbox Code Playgroud)
当我运行时,bundle exec rake rails_rbi:models\[Model\]我期望 sorbet 会看到覆盖的方法,并将它们从自动生成的文件中排除。但不幸的是事实并非如此。两个文件中都存在方法。因此,我收到与自动生成的文件相对应的类型错误,而不是与我编写的文件相对应的类型错误。有趣的是,当我运行时srb tc没有错误。
当我从自动生成的文件中删除方法时,类型错误消失了,但显然这不是处理它的最佳方法。
如何覆盖这些方法以便将它们从自动生成的文件中排除?
我正在尝试将 Devise 添加到使用 Sorbet 的 Rails 项目中。添加 Devise 后,我运行bundle exec tapioca dsl并bundle exec tapioca gem. 现在,在我的控制器上,类型检查抱怨它找不到current_user帮助器方法。
我注意到生成的文件中sorbet/rbi/gems/devise@4.9.2.rbi包含以下描述:
class << self
# Define authentication filters and accessor helpers based on mappings.
# These filters should be used inside the controllers as before_actions,
# so you can control the scope of the user who should be signed in to
# access that specific controller/action.
# Example:
#
# Roles:
# User
# Admin
# …Run Code Online (Sandbox Code Playgroud) 尝试注释此代码时,rose memoization ( @||=) 给了我一个错误Use of undeclared variable @git_sha。
# typed: strict
# frozen_string_literal: true
module Util
extend T::Sig
sig { returns(String) }
def self.git_sha
@git_sha ||= ENV.fetch(
'GIT_REV',
`git rev-parse --verify HEAD 2>&1`
).chomp
end
end
Run Code Online (Sandbox Code Playgroud)
据我发现,我应该声明变量的类型,T.let但还没有弄清楚具体如何。
鉴于:
# typed: true
module X
class Y
end
end
module X
class X
def y
X::Y
end
end
end
Run Code Online (Sandbox Code Playgroud)
冰糕给出错误:
editor.rb:6: Unable to resolve constant Y https://srb.help/5002
6 | X::Y
Run Code Online (Sandbox Code Playgroud)
即使定义了 X::Y,为什么 sorbet 也会给出错误?
如何使用冰糕指定类型参数?
例如,我想用A返回泛型类型的参数来注释一个方法T[A]。
def build_array(value)
[value]
end
Run Code Online (Sandbox Code Playgroud)
输出类型取决于输入类型:
build_array(42) #=> return Array[Integer]
build_array('42') #=> return Array[String]
Run Code Online (Sandbox Code Playgroud) (请注意,这不能在 sorbet.run 上重现,据我所知,它只能用 Sorbet 的本地副本重现)
我希望我可以使用Typed Structs 功能来创建一个方法签名,其中一个参数是options散列,但这不起作用:
# typed: true
require 'sorbet-runtime'
extend T::Sig
class OptionsStruct < T::Struct
prop :x, Integer, default: 1
end
sig { params(options: OptionsStruct).void }
def method(options)
puts options.x
end
# This works
method(OptionsStruct.new({x: 2}))
# This causes the typechecker to throw.
method({x: 2})
Run Code Online (Sandbox Code Playgroud)
本质上,当您键入检查此文件时,它会抱怨在需要 Struct 时传入哈希值。我的问题是:如何为具有特定参数的哈希定义有效签名?结构在这里显然不起作用。虽然我没有尝试过 Shapes,但根据文档,它们非常有限,所以如果可能的话,我宁愿不使用它们。
关于泛型的文档提到了哈希,但似乎表明它们只能在哈希的键和值都是相同类型的情况下Hash<Symbol, String>才能使用(例如,要求所有键都是符号,所有值都是字符串),并且不提供任何方式(据我所知)用特定的键定义一个散列。
谢谢!
我想了解为什么冰糕不抱怨这个例子:例子:
sig {params(x: T::Hash[String, String]).void}
def foo(x)
x.each do |k, v|
puts "key = #{k}, value = #{v}"
end
end
hash = {}
hash[1] = 1
foo(hash) # I'd expect this to fail to type-check
Run Code Online (Sandbox Code Playgroud)
我已声明foo接受 [String, String] 的哈希值,但我传递的是 [Integer, Integer] 的哈希值。我以为冰糕会在这里抱怨......
有没有办法让它在这种情况下出错?
我在 Rails 项目上使用 Sorbet,并且有一个方法可以对 nilable 属性进行计算。
def age
return unless dob && dob.year > 1900
now = Time.now.utc.to_date
now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
end
Run Code Online (Sandbox Code Playgroud)
在该代码上,dob是nilable。如果我对它进行类型检查,我会收到一堆抱怨,要求将其包装dob在里面T.must(dob):
app/models/person.rb:18: Method year does not exist on NilClass component of T.nilable(Date) https://srb.help/7003
18 | return unless dob && dob.year > 1900
^^^^
Got T.nilable(Date) originating from:
app/models/person.rb:18:
18 | return unless dob && dob.year > …Run Code Online (Sandbox Code Playgroud)