rubocop-sorbet 0.9.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.devcontainer/devcontainer.json +25 -0
- data/.github/workflows/ci.yml +6 -6
- data/.github/workflows/dependabot_automerge.yml +2 -2
- data/.github/workflows/stale.yml +1 -1
- data/.rubocop.yml +2 -2
- data/.ruby-version +1 -1
- data/CONTRIBUTING.md +29 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +27 -29
- data/README.md +4 -16
- data/Rakefile +43 -5
- data/VERSION +1 -0
- data/bin/{rspec → rake} +5 -9
- data/config/default.yml +89 -64
- data/config/rbi.yml +0 -3
- data/dev.yml +1 -1
- data/lib/rubocop/cop/sorbet/block_method_definition.rb +83 -0
- data/lib/rubocop/cop/sorbet/forbid_mixes_in_class_methods.rb +49 -0
- data/lib/rubocop/cop/sorbet/select_by_is_a.rb +62 -0
- data/lib/rubocop/cop/sorbet/sigils/enforce_single_sigil.rb +1 -1
- data/lib/rubocop/cop/sorbet/sigils/valid_sigil.rb +20 -2
- data/lib/rubocop/cop/sorbet/signatures/empty_line_after_sig.rb +20 -11
- data/lib/rubocop/cop/sorbet_cops.rb +3 -0
- data/lib/rubocop/sorbet/plugin.rb +5 -3
- data/lib/rubocop/sorbet/version.rb +1 -1
- data/lib/rubocop/sorbet.rb +1 -1
- data/lib/rubocop-sorbet.rb +1 -1
- data/manual/cops.md +3 -0
- data/manual/cops_sorbet.md +108 -8
- data/rubocop-sorbet.gemspec +2 -2
- metadata +15 -10
- data/.travis.yml +0 -12
data/dev.yml
CHANGED
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Sorbet
|
6
|
+
# Disallow defining methods in blocks, to prevent running into issues
|
7
|
+
# caused by https://github.com/sorbet/sorbet/issues/3609.
|
8
|
+
#
|
9
|
+
# As a workaround, use `define_method` instead.
|
10
|
+
#
|
11
|
+
# The one exception is for `Class.new` blocks, as long as the result is
|
12
|
+
# assigned to a constant (i.e. as long as it is not an anonymous class).
|
13
|
+
|
14
|
+
# @example
|
15
|
+
# # bad
|
16
|
+
# yielding_method do
|
17
|
+
# def bad(args)
|
18
|
+
# # ...
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# # bad
|
23
|
+
# Class.new do
|
24
|
+
# def bad(args)
|
25
|
+
# # ...
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# # good
|
30
|
+
# yielding_method do
|
31
|
+
# define_method(:good) do |args|
|
32
|
+
# # ...
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# # good
|
37
|
+
# MyClass = Class.new do
|
38
|
+
# def good(args)
|
39
|
+
# # ...
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
class BlockMethodDefinition < Base
|
44
|
+
include RuboCop::Cop::Alignment
|
45
|
+
extend AutoCorrector
|
46
|
+
|
47
|
+
MSG = "Do not define methods in blocks (use `define_method` as a workaround)."
|
48
|
+
|
49
|
+
def on_block(node)
|
50
|
+
if (parent = node.parent)
|
51
|
+
return if parent.casgn_type?
|
52
|
+
end
|
53
|
+
|
54
|
+
node.each_descendant(:any_def) do |def_node|
|
55
|
+
add_offense(def_node) do |corrector|
|
56
|
+
autocorrect_method_in_block(corrector, def_node)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
alias_method :on_numblock, :on_block
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def autocorrect_method_in_block(corrector, node)
|
65
|
+
indent = offset(node)
|
66
|
+
|
67
|
+
method_name = node.method_name
|
68
|
+
args = node.arguments.map(&:source).join(", ")
|
69
|
+
body = node.body&.source&.prepend("\n#{indent} ")
|
70
|
+
|
71
|
+
if node.def_type?
|
72
|
+
replacement = "define_method(:#{method_name}) do |#{args}|#{body}\n#{indent}end"
|
73
|
+
elsif node.defs_type?
|
74
|
+
receiver = node.receiver.source
|
75
|
+
replacement = "#{receiver}.define_singleton_method(:#{method_name}) do |#{args}|#{body}\n#{indent}end"
|
76
|
+
end
|
77
|
+
|
78
|
+
corrector.replace(node, replacement)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Sorbet
|
6
|
+
# Check that code does not call `mixes_in_class_methods` from Sorbet `T::Helpers`.
|
7
|
+
#
|
8
|
+
# Good:
|
9
|
+
#
|
10
|
+
# ```
|
11
|
+
# module M
|
12
|
+
# extend ActiveSupport::Concern
|
13
|
+
#
|
14
|
+
# class_methods do
|
15
|
+
# ...
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
# ```
|
19
|
+
#
|
20
|
+
# Bad:
|
21
|
+
#
|
22
|
+
# ```
|
23
|
+
# module M
|
24
|
+
# extend T::Helpers
|
25
|
+
#
|
26
|
+
# module ClassMethods
|
27
|
+
# ...
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# mixes_in_class_methods(ClassMethods)
|
31
|
+
# end
|
32
|
+
# ```
|
33
|
+
class ForbidMixesInClassMethods < ::RuboCop::Cop::Base
|
34
|
+
MSG = "Do not use `mixes_in_class_methods`, use `extend ActiveSupport::Concern` instead."
|
35
|
+
RESTRICT_ON_SEND = [:mixes_in_class_methods].freeze
|
36
|
+
|
37
|
+
# @!method mixes_in_class_methods?(node)
|
38
|
+
def_node_matcher(:mixes_in_class_methods?, <<~PATTERN)
|
39
|
+
(send {self | nil? | (const (const {cbase | nil?} :T) :Helpers)} :mixes_in_class_methods ...)
|
40
|
+
PATTERN
|
41
|
+
|
42
|
+
def on_send(node)
|
43
|
+
add_offense(node) if mixes_in_class_methods?(node)
|
44
|
+
end
|
45
|
+
alias_method :on_csend, :on_send
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubocop"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sorbet
|
8
|
+
# Suggests using `grep` over `select` when using it only for type narrowing.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# strings_or_integers.select { |e| e.is_a?(String) }
|
14
|
+
# strings_or_integers.filter { |e| e.is_a?(String) }
|
15
|
+
# strings_or_integers.select { |e| e.kind_of?(String) }
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# strings_or_integers.grep(String)
|
19
|
+
class SelectByIsA < RuboCop::Cop::Base
|
20
|
+
extend AutoCorrector
|
21
|
+
|
22
|
+
MSG = "Use `grep` instead of `select` when using it only for type narrowing."
|
23
|
+
RESTRICT_ON_SEND = [:select, :filter].freeze
|
24
|
+
|
25
|
+
# @!method type_narrowing_select?(node)
|
26
|
+
def_node_matcher :type_narrowing_select?, <<~PATTERN
|
27
|
+
{
|
28
|
+
(block
|
29
|
+
(call _ {:select :filter})
|
30
|
+
(args (arg _))
|
31
|
+
(send (lvar _) { :is_a? :kind_of? } (const nil? _)))
|
32
|
+
(numblock
|
33
|
+
(call _ {:select :filter})
|
34
|
+
_
|
35
|
+
(send (lvar _) { :is_a? :kind_of? } (const nil? _)))
|
36
|
+
(itblock
|
37
|
+
(call _ {:select :filter})
|
38
|
+
_
|
39
|
+
(send (lvar _) { :is_a? :kind_of? } (const nil? _)))
|
40
|
+
}
|
41
|
+
PATTERN
|
42
|
+
|
43
|
+
def on_send(node)
|
44
|
+
block_node = node.block_node
|
45
|
+
|
46
|
+
return unless block_node
|
47
|
+
return unless type_narrowing_select?(block_node)
|
48
|
+
|
49
|
+
add_offense(block_node) do |corrector|
|
50
|
+
receiver = node.receiver
|
51
|
+
type_class = block_node.body.children[2]
|
52
|
+
navigation = node.csend_type? ? "&." : "."
|
53
|
+
replacement = "#{receiver.source}#{navigation}grep(#{type_class.source})"
|
54
|
+
|
55
|
+
corrector.replace(block_node, replacement)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
alias_method :on_csend, :on_send
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -54,7 +54,7 @@ module RuboCop
|
|
54
54
|
# The first sigil encountered represents the "real" strictness so remove any below
|
55
55
|
sigils[1..sigils.size].each do |token|
|
56
56
|
corrector.remove(
|
57
|
-
source_range(processed_source.buffer, token.line,
|
57
|
+
source_range(processed_source.buffer, token.line, 0..token.pos.last_column),
|
58
58
|
)
|
59
59
|
end
|
60
60
|
end
|
@@ -28,6 +28,8 @@ module RuboCop
|
|
28
28
|
return unless check_sigil_present(sigil)
|
29
29
|
|
30
30
|
strictness = extract_strictness(sigil)
|
31
|
+
check_double_commented_sigil(sigil, strictness)
|
32
|
+
|
31
33
|
return unless check_strictness_not_empty(sigil, strictness)
|
32
34
|
return unless check_strictness_valid(sigil, strictness)
|
33
35
|
|
@@ -37,7 +39,8 @@ module RuboCop
|
|
37
39
|
protected
|
38
40
|
|
39
41
|
STRICTNESS_LEVELS = ["ignore", "false", "true", "strict", "strong"]
|
40
|
-
SIGIL_REGEX = /^[[:blank:]]
|
42
|
+
SIGIL_REGEX = /^[[:blank:]]*(?:#[[:blank:]]*)?#[[:blank:]]+typed:(?:[[:blank:]]+([\S]+))?/
|
43
|
+
INVALID_SIGIL_MSG = "Invalid Sorbet sigil `%<sigil>s`."
|
41
44
|
|
42
45
|
# extraction
|
43
46
|
|
@@ -104,12 +107,27 @@ module RuboCop
|
|
104
107
|
false
|
105
108
|
end
|
106
109
|
|
110
|
+
def check_double_commented_sigil(sigil, strictness)
|
111
|
+
return unless sigil.text.start_with?(/[[:blank:]]*#[[:blank:]]*#/)
|
112
|
+
|
113
|
+
add_offense(
|
114
|
+
sigil.pos,
|
115
|
+
message: format(INVALID_SIGIL_MSG, sigil: sigil.text),
|
116
|
+
) do |corrector|
|
117
|
+
# Remove the extra comment and normalize spaces
|
118
|
+
corrector.replace(
|
119
|
+
sigil.pos,
|
120
|
+
"# typed: #{strictness}",
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
107
125
|
def check_strictness_valid(sigil, strictness)
|
108
126
|
return true if STRICTNESS_LEVELS.include?(strictness)
|
109
127
|
|
110
128
|
add_offense(
|
111
129
|
sigil.pos,
|
112
|
-
message:
|
130
|
+
message: format(INVALID_SIGIL_MSG, sigil: strictness),
|
113
131
|
) do |corrector|
|
114
132
|
autocorrect(corrector)
|
115
133
|
end
|
@@ -24,9 +24,8 @@ module RuboCop
|
|
24
24
|
# @!method sig_or_signable_method_definition?(node)
|
25
25
|
def_node_matcher :sig_or_signable_method_definition?, <<~PATTERN
|
26
26
|
${
|
27
|
-
|
28
|
-
|
29
|
-
(send nil? {:attr_reader :attr_writer :attr_accessor} ...)
|
27
|
+
any_def
|
28
|
+
(send nil? {:attr :attr_reader :attr_writer :attr_accessor} ...)
|
30
29
|
#signature?
|
31
30
|
}
|
32
31
|
PATTERN
|
@@ -34,16 +33,22 @@ module RuboCop
|
|
34
33
|
def on_signature(sig)
|
35
34
|
sig_or_signable_method_definition?(next_sibling(sig)) do |definition|
|
36
35
|
range = lines_between(sig, definition)
|
37
|
-
next if range.empty? || range.single_line?
|
36
|
+
next if range.empty? || range.single_line? || contains_only_rubocop_directives?(range)
|
38
37
|
|
39
38
|
add_offense(range) do |corrector|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
lines = range.source.lines
|
40
|
+
rubocop_lines, other_lines = lines.partition { |line| line.strip.start_with?("# rubocop:") }
|
41
|
+
|
42
|
+
unless other_lines.empty?
|
43
|
+
corrector.insert_before(
|
44
|
+
range_by_whole_lines(sig.source_range),
|
45
|
+
other_lines.join
|
46
|
+
.sub(/\A\n+/, "") # remove initial newline(s)
|
47
|
+
.gsub(/\n{2,}/, "\n"), # remove empty line(s)
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
corrector.replace(range, rubocop_lines.empty? ? "" : rubocop_lines.join)
|
47
52
|
end
|
48
53
|
end
|
49
54
|
end
|
@@ -54,6 +59,10 @@ module RuboCop
|
|
54
59
|
node.parent&.children&.at(node.sibling_index + 1)
|
55
60
|
end
|
56
61
|
|
62
|
+
def contains_only_rubocop_directives?(range)
|
63
|
+
range.source.lines.all? { |line| line.strip.start_with?("# rubocop:") }
|
64
|
+
end
|
65
|
+
|
57
66
|
def lines_between(node1, node2, buffer: processed_source.buffer)
|
58
67
|
end_of_node1_pos = node1.source_range.end_pos
|
59
68
|
start_of_node2_pos = node2.source_range.begin_pos
|
@@ -5,9 +5,11 @@ require_relative "sorbet/mixin/t_enum"
|
|
5
5
|
require_relative "sorbet/mixin/signature_help"
|
6
6
|
|
7
7
|
require_relative "sorbet/binding_constant_without_type_alias"
|
8
|
+
require_relative "sorbet/block_method_definition"
|
8
9
|
require_relative "sorbet/constants_from_strings"
|
9
10
|
require_relative "sorbet/forbid_superclass_const_literal"
|
10
11
|
require_relative "sorbet/forbid_include_const_literal"
|
12
|
+
require_relative "sorbet/forbid_mixes_in_class_methods"
|
11
13
|
require_relative "sorbet/forbid_type_aliased_shapes"
|
12
14
|
require_relative "sorbet/forbid_untyped_struct_props"
|
13
15
|
require_relative "sorbet/implicit_conversion_method"
|
@@ -18,6 +20,7 @@ require_relative "sorbet/forbid_t_unsafe"
|
|
18
20
|
require_relative "sorbet/forbid_t_untyped"
|
19
21
|
require_relative "sorbet/redundant_extend_t_sig"
|
20
22
|
require_relative "sorbet/refinement"
|
23
|
+
require_relative "sorbet/select_by_is_a"
|
21
24
|
require_relative "sorbet/type_alias_name"
|
22
25
|
require_relative "sorbet/obsolete_strict_memoization"
|
23
26
|
require_relative "sorbet/buggy_obsolete_strict_memoization"
|
@@ -1,5 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
rubocop_min_version = Gem::Version.create("1.72.1")
|
4
|
+
rubocop_version = Gem::Version.create(RuboCop::Version.version)
|
5
|
+
|
6
|
+
return if rubocop_version < rubocop_min_version
|
7
|
+
|
3
8
|
require "rubocop"
|
4
9
|
require "lint_roller"
|
5
10
|
require "pathname"
|
@@ -8,9 +13,6 @@ module RuboCop
|
|
8
13
|
module Sorbet
|
9
14
|
# A plugin that integrates RuboCop Sorbet with RuboCop's plugin system.
|
10
15
|
class Plugin < LintRoller::Plugin
|
11
|
-
RUBOCOP_MIN_VERSION = "1.72.1"
|
12
|
-
SUPPORTED = Gem::Version.create(RuboCop::Version.version) < RUBOCOP_MIN_VERSION
|
13
|
-
|
14
16
|
def about
|
15
17
|
LintRoller::About.new(
|
16
18
|
name: "rubocop-sorbet",
|
data/lib/rubocop/sorbet.rb
CHANGED
@@ -10,7 +10,7 @@ module RuboCop
|
|
10
10
|
module Sorbet
|
11
11
|
class Error < StandardError; end
|
12
12
|
|
13
|
-
unless Plugin
|
13
|
+
unless defined?(::RuboCop::Sorbet::Plugin)
|
14
14
|
PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
|
15
15
|
CONFIG_DEFAULT = PROJECT_ROOT.join("config", "default.yml").freeze
|
16
16
|
CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
|
data/lib/rubocop-sorbet.rb
CHANGED
@@ -6,7 +6,7 @@ require_relative "rubocop/sorbet"
|
|
6
6
|
require_relative "rubocop/sorbet/version"
|
7
7
|
require_relative "rubocop/sorbet/plugin"
|
8
8
|
|
9
|
-
unless RuboCop::Sorbet::Plugin
|
9
|
+
unless defined?(RuboCop::Sorbet::Plugin)
|
10
10
|
require_relative "rubocop/sorbet/inject"
|
11
11
|
RuboCop::Sorbet::Inject.defaults!
|
12
12
|
end
|
data/manual/cops.md
CHANGED
@@ -7,6 +7,7 @@ In the following section you find all available cops:
|
|
7
7
|
|
8
8
|
* [Sorbet/AllowIncompatibleOverride](cops_sorbet.md#sorbetallowincompatibleoverride)
|
9
9
|
* [Sorbet/BindingConstantWithoutTypeAlias](cops_sorbet.md#sorbetbindingconstantwithouttypealias)
|
10
|
+
* [Sorbet/BlockMethodDefinition](cops_sorbet.md#sorbetblockmethoddefinition)
|
10
11
|
* [Sorbet/BuggyObsoleteStrictMemoization](cops_sorbet.md#sorbetbuggyobsoletestrictmemoization)
|
11
12
|
* [Sorbet/CallbackConditionalsBinding](cops_sorbet.md#sorbetcallbackconditionalsbinding)
|
12
13
|
* [Sorbet/CheckedTrueInSignature](cops_sorbet.md#sorbetcheckedtrueinsignature)
|
@@ -19,6 +20,7 @@ In the following section you find all available cops:
|
|
19
20
|
* [Sorbet/ForbidComparableTEnum](cops_sorbet.md#sorbetforbidcomparabletenum)
|
20
21
|
* [Sorbet/ForbidExtendTSigHelpersInShims](cops_sorbet.md#sorbetforbidextendtsighelpersinshims)
|
21
22
|
* [Sorbet/ForbidIncludeConstLiteral](cops_sorbet.md#sorbetforbidincludeconstliteral)
|
23
|
+
* [Sorbet/ForbidMixesInClassMethods](cops_sorbet.md#sorbetforbidmixesinclassmethods)
|
22
24
|
* [Sorbet/ForbidRBIOutsideOfAllowedPaths](cops_sorbet.md#sorbetforbidrbioutsideofallowedpaths)
|
23
25
|
* [Sorbet/ForbidSig](cops_sorbet.md#sorbetforbidsig)
|
24
26
|
* [Sorbet/ForbidSigWithRuntime](cops_sorbet.md#sorbetforbidsigwithruntime)
|
@@ -38,6 +40,7 @@ In the following section you find all available cops:
|
|
38
40
|
* [Sorbet/ObsoleteStrictMemoization](cops_sorbet.md#sorbetobsoletestrictmemoization)
|
39
41
|
* [Sorbet/RedundantExtendTSig](cops_sorbet.md#sorbetredundantextendtsig)
|
40
42
|
* [Sorbet/Refinement](cops_sorbet.md#sorbetrefinement)
|
43
|
+
* [Sorbet/SelectByIsA](cops_sorbet.md#sorbetselectbyisa)
|
41
44
|
* [Sorbet/SignatureBuildOrder](cops_sorbet.md#sorbetsignaturebuildorder)
|
42
45
|
* [Sorbet/SingleLineRbiClassModuleDefinitions](cops_sorbet.md#sorbetsinglelinerbiclassmoduledefinitions)
|
43
46
|
* [Sorbet/StrictSigil](cops_sorbet.md#sorbetstrictsigil)
|
data/manual/cops_sorbet.md
CHANGED
@@ -41,6 +41,46 @@ FooOrBar = T.any(Foo, Bar)
|
|
41
41
|
FooOrBar = T.type_alias { T.any(Foo, Bar) }
|
42
42
|
```
|
43
43
|
|
44
|
+
## Sorbet/BlockMethodDefinition
|
45
|
+
|
46
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
47
|
+
--- | --- | --- | --- | ---
|
48
|
+
Enabled | Yes | Yes (Unsafe) | 0.10.1 | -
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
### Examples
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
# bad
|
56
|
+
yielding_method do
|
57
|
+
def bad(args)
|
58
|
+
# ...
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# bad
|
63
|
+
Class.new do
|
64
|
+
def bad(args)
|
65
|
+
# ...
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# good
|
70
|
+
yielding_method do
|
71
|
+
define_method(:good) do |args|
|
72
|
+
# ...
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# good
|
77
|
+
MyClass = Class.new do
|
78
|
+
def good(args)
|
79
|
+
# ...
|
80
|
+
end
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
44
84
|
## Sorbet/BuggyObsoleteStrictMemoization
|
45
85
|
|
46
86
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
@@ -180,7 +220,7 @@ end
|
|
180
220
|
|
181
221
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
182
222
|
--- | --- | --- | --- | ---
|
183
|
-
Enabled | Yes | Yes | 0.7.0 |
|
223
|
+
Enabled | Yes | Yes | 0.7.0 | 0.10.1
|
184
224
|
|
185
225
|
Checks for blank lines after signatures.
|
186
226
|
|
@@ -254,6 +294,12 @@ You can configure the placeholders used by changing the following options:
|
|
254
294
|
* `ParameterTypePlaceholder`: placeholders used for parameter types (default: 'T.untyped')
|
255
295
|
* `ReturnTypePlaceholder`: placeholders used for return types (default: 'T.untyped')
|
256
296
|
|
297
|
+
### Configurable attributes
|
298
|
+
|
299
|
+
Name | Default value | Configurable values
|
300
|
+
--- | --- | ---
|
301
|
+
AllowRBS | `false` | Boolean
|
302
|
+
|
257
303
|
## Sorbet/EnforceSingleSigil
|
258
304
|
|
259
305
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
@@ -385,6 +431,40 @@ or
|
|
385
431
|
include Polaris::Engine.helpers
|
386
432
|
```
|
387
433
|
|
434
|
+
## Sorbet/ForbidMixesInClassMethods
|
435
|
+
|
436
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
437
|
+
--- | --- | --- | --- | ---
|
438
|
+
Disabled | Yes | No | 0.10.1 | -
|
439
|
+
|
440
|
+
Check that code does not call `mixes_in_class_methods` from Sorbet `T::Helpers`.
|
441
|
+
|
442
|
+
Good:
|
443
|
+
|
444
|
+
```
|
445
|
+
module M
|
446
|
+
extend ActiveSupport::Concern
|
447
|
+
|
448
|
+
class_methods do
|
449
|
+
...
|
450
|
+
end
|
451
|
+
end
|
452
|
+
```
|
453
|
+
|
454
|
+
Bad:
|
455
|
+
|
456
|
+
```
|
457
|
+
module M
|
458
|
+
extend T::Helpers
|
459
|
+
|
460
|
+
module ClassMethods
|
461
|
+
...
|
462
|
+
end
|
463
|
+
|
464
|
+
mixes_in_class_methods(ClassMethods)
|
465
|
+
end
|
466
|
+
```
|
467
|
+
|
388
468
|
## Sorbet/ForbidRBIOutsideOfAllowedPaths
|
389
469
|
|
390
470
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
@@ -421,7 +501,7 @@ Include | `**/*.rbi` | Array
|
|
421
501
|
|
422
502
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
423
503
|
--- | --- | --- | --- | ---
|
424
|
-
Disabled | Yes | No |
|
504
|
+
Disabled | Yes | No | 0.9.0 | -
|
425
505
|
|
426
506
|
Check that definitions do not use a `sig` block.
|
427
507
|
|
@@ -443,7 +523,7 @@ def foo; end
|
|
443
523
|
|
444
524
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
445
525
|
--- | --- | --- | --- | ---
|
446
|
-
Disabled | Yes | No |
|
526
|
+
Disabled | Yes | No | 0.9.0 | -
|
447
527
|
|
448
528
|
Check that definitions do not use a `sig` block.
|
449
529
|
|
@@ -465,7 +545,7 @@ def foo; end
|
|
465
545
|
|
466
546
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
467
547
|
--- | --- | --- | --- | ---
|
468
|
-
Disabled | Yes | Yes |
|
548
|
+
Disabled | Yes | Yes | 0.9.0 | -
|
469
549
|
|
470
550
|
Check that `sig` is used instead of `T::Sig::WithoutRuntime.sig`.
|
471
551
|
|
@@ -518,7 +598,7 @@ Exclude | `db/migrate/*.rb` | Array
|
|
518
598
|
|
519
599
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
520
600
|
--- | --- | --- | --- | ---
|
521
|
-
Disabled | No | No |
|
601
|
+
Disabled | No | No | 0.8.9 | -
|
522
602
|
|
523
603
|
Disallow using `T::Enum`.
|
524
604
|
|
@@ -545,7 +625,7 @@ end
|
|
545
625
|
|
546
626
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
547
627
|
--- | --- | --- | --- | ---
|
548
|
-
Disabled | No | Yes |
|
628
|
+
Disabled | No | Yes | 0.7.4 | -
|
549
629
|
|
550
630
|
Disallow using `T::Struct` and `T::Props`.
|
551
631
|
|
@@ -714,7 +794,7 @@ Exclude | `bin/**/*`, `db/**/*.rb`, `script/**/*` | Array
|
|
714
794
|
|
715
795
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
716
796
|
--- | --- | --- | --- | ---
|
717
|
-
Disabled | Yes | No |
|
797
|
+
Disabled | Yes | No | 0.7.1 | -
|
718
798
|
|
719
799
|
Disallows declaring implicit conversion methods.
|
720
800
|
Since Sorbet is a nominal (not structural) type system,
|
@@ -857,7 +937,7 @@ end
|
|
857
937
|
|
858
938
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
859
939
|
--- | --- | --- | --- | ---
|
860
|
-
Enabled | Yes | No |
|
940
|
+
Enabled | Yes | No | 0.8.6 | -
|
861
941
|
|
862
942
|
Checks for the use of Ruby Refinements library. Refinements add
|
863
943
|
complexity and incur a performance penalty that can be significant
|
@@ -890,6 +970,26 @@ module Foo
|
|
890
970
|
end
|
891
971
|
```
|
892
972
|
|
973
|
+
## Sorbet/SelectByIsA
|
974
|
+
|
975
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
976
|
+
--- | --- | --- | --- | ---
|
977
|
+
Enabled | Yes | Yes | 0.10.1 | -
|
978
|
+
|
979
|
+
Suggests using `grep` over `select` when using it only for type narrowing.
|
980
|
+
|
981
|
+
### Examples
|
982
|
+
|
983
|
+
```ruby
|
984
|
+
# bad
|
985
|
+
strings_or_integers.select { |e| e.is_a?(String) }
|
986
|
+
strings_or_integers.filter { |e| e.is_a?(String) }
|
987
|
+
strings_or_integers.select { |e| e.kind_of?(String) }
|
988
|
+
|
989
|
+
# good
|
990
|
+
strings_or_integers.grep(String)
|
991
|
+
```
|
992
|
+
|
893
993
|
## Sorbet/SignatureBuildOrder
|
894
994
|
|
895
995
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
data/rubocop-sorbet.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.homepage = "https://github.com/shopify/rubocop-sorbet"
|
13
13
|
spec.license = "MIT"
|
14
14
|
|
15
|
-
spec.required_ruby_version = ">= 3.
|
15
|
+
spec.required_ruby_version = ">= 3.1"
|
16
16
|
|
17
17
|
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
18
18
|
spec.metadata["homepage_uri"] = spec.homepage
|
@@ -28,6 +28,6 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
29
29
|
spec.require_paths = ["lib"]
|
30
30
|
|
31
|
-
spec.add_runtime_dependency("lint_roller"
|
31
|
+
spec.add_runtime_dependency("lint_roller")
|
32
32
|
spec.add_runtime_dependency("rubocop", ">= 1")
|
33
33
|
end
|