rubocop-rbs_inline
rubocop-rbs_inline is a RuboCop extension that checks for RBS::Inline annotation comments in Ruby code.
Installation
Install the gem and add to the application's Gemfile by executing:
bundle add rubocop-rbs_inline
If bundler is not being used to manage dependencies, install the gem by executing:
gem install rubocop-rbs_inline
Add the following to your .rubocop.yml:
plugins:
- rubocop-rbs_inline
Available Cops
rubocop-rbs_inline provides the following cops to validate RBS::Inline annotations:
Style/RbsInline/DataClassCommentAlignment
Checks that #: inline type annotations in a multiline Data.define call are aligned to the same column. The expected column is determined by the longest attribute name (plus its trailing comma). Folded Data.define calls (where multiple attributes share a line) are excluded.
Supports autocorrect.
Examples:
# bad
MethodEntry = Data.define(
:name, #: Symbol
:node, #: Parser::AST::Node
:visibility #: Symbol
)
# good
MethodEntry = Data.define(
:name, #: Symbol
:node, #: Parser::AST::Node
:visibility #: Symbol
)
Style/RbsInline/DataDefineWithBlock
Checks for Data.define calls with a block. RBS::Inline does not parse block contents, so any methods defined inside the block will not be recognized for type checking. Instead, call Data.define without a block and reopen the class separately to add methods.
Examples:
# bad
User = Data.define(:name, :role) do
def admin?
role == :admin
end
end
# good
User = Data.define(:name, :role)
class User
def admin? #: bool
role == :admin
end
end
Style/RbsInline/EmbeddedRbsSpacing
Checks that @rbs! comments (embedded RBS) are followed by a blank line.
RBS::Inline requires @rbs! comments to be standalone comments, meaning they should not have any code immediately following them. A blank line after the @rbs! block ensures proper separation.
Examples:
# bad
# @rbs! type foo = Integer
def method
end
# good
# @rbs! type foo = Integer
def method
end
Style/RbsInline/InvalidComment
Checks that annotation comments start with #: or # @rbs (not # : or # rbs).
Examples:
# bad
# () -> void
# : () -> void
# rbs param: String
# good
#: () -> void
# @rbs param: String
Style/RbsInline/InvalidTypes
Validates that RBS type syntax in annotations is correct and complete.
Examples:
# bad
# @rbs arg: Hash[Symbol,
# @rbs &block: String
# good
# @rbs arg: Hash[Symbol, String]
# @rbs &block: () -> void
Style/RbsInline/KeywordSeparator
Ensures RBS keywords (module-self, inherits, override, etc.) are not followed by :.
Examples:
# bad
# @rbs module-self: String
# good
# @rbs module-self String
Style/RbsInline/MethodCommentSpacing
Checks that method-related @rbs annotations are placed immediately before their method definition, with no blank lines in between. Also flags method-related annotations that are not followed by a method definition at all.
Method-related annotations include # @rbs param:, # @rbs return:, # @rbs &block:, # @rbs override, # @rbs skip, # @rbs %a{...}, # @rbs (...) -> Type, and #: (...) -> Type.
Supports autocorrect (removes blank lines between the annotation and the method definition).
Examples:
# bad - blank line between annotation and method
# @rbs x: Integer
# @rbs return: String
def method(x)
end
# bad - annotation comment not followed by a method definition
# @rbs x: Integer
puts "something"
# good
# @rbs x: Integer
# @rbs return: String
def method(x)
end
# good
#: (Integer) -> String
def method(x)
end
Style/RbsInline/MissingDataClassAnnotation
Checks that each attribute passed to Data.define has a trailing #: inline type annotation on the same line.
For folded Data.define calls (where multiple attributes share a line), the cop will suggest rewriting as a multiline call so each attribute can be annotated individually.
Supports autocorrect.
Examples:
# bad
MethodEntry = Data.define(:name, :node, :visibility)
# bad - missing annotation for :node
MethodEntry = Data.define(
:name, #: Symbol
:node,
:visibility #: Symbol
)
# good
MethodEntry = Data.define(
:name, #: Symbol
:node, #: Parser::AST::Node
:visibility #: Symbol
)
Style/RbsInline/MissingTypeAnnotation
Enforces that method definitions and attr_* declarations have RBS inline type annotations.
Configuration:
EnforcedStyle(default:doc_style)doc_style: Requires# @rbsannotationsdoc_style_and_return_annotation: Requires# @rbsparameters and inline#:return typemethod_type_signature: Requires#:annotation commentsmethod_type_signature_or_return_annotation: Requires#:annotation for methods with arguments; accepts either#:annotation or trailing#:return type for methods without arguments
Visibility(default:all)all: Checks all methods regardless of visibilitypublic: Only checks public methods andattr_*declarations
Methods annotated with # @rbs skip are always excluded.
Examples (EnforcedStyle: doc_style):
# bad - no annotation
def greet(name)
"Hello, #{name}"
end
# good
# @rbs name: String
# @rbs return: String
def greet(name)
"Hello, #{name}"
end
Examples (EnforcedStyle: doc_style_and_return_annotation):
# bad - no annotation
def greet(name)
"Hello, #{name}"
end
# good
# @rbs name: String
def greet(name) #: String
"Hello, #{name}"
end
Examples (EnforcedStyle: method_type_signature):
# bad - no annotation
def greet(name)
"Hello, #{name}"
end
# good
#: (String) -> String
def greet(name)
"Hello, #{name}"
end
Examples (EnforcedStyle: method_type_signature_or_return_annotation):
# bad - method with arguments requires method_type_signature
def greet(name)
"Hello, #{name}"
end
# bad - trailing return annotation is not accepted for methods with arguments
def greet(name) #: String
"Hello, #{name}"
end
# good - method_type_signature for methods with arguments
#: (String) -> String
def greet(name)
"Hello, #{name}"
end
# good - method_type_signature for methods without arguments
#: -> String
def greet
"Hello"
end
# good - trailing return annotation for methods without arguments
def greet #: String
"Hello"
end
Style/RbsInline/ParametersSeparator
Checks that parameter annotations use : as a separator between parameter name and type.
Examples:
# bad
# @rbs param String
# @rbs :param String
# good
# @rbs param: String
# @rbs %a{pure}
Style/RbsInline/RedundantAnnotationWithSkip
Warns when type annotations are present alongside # @rbs skip or # @rbs override. These directives instruct RBS::Inline to skip or inherit RBS generation for the method, making any additional type annotations redundant.
Detected redundant annotations include #: method type signatures, # @rbs (Type) -> Type method types, # @rbs param: parameter annotations, # @rbs return: return type annotations, and trailing #: inline types.
Supports unsafe autocorrect (removes the redundant annotations).
Examples:
# bad - redundant method type signature with @rbs skip
# @rbs skip
#: (Integer) -> void
def method(a)
end
# bad - redundant doc-style method type with @rbs skip
# @rbs skip
# @rbs (Integer) -> void
def method(a)
end
# bad - redundant param annotation with @rbs override
# @rbs override
# @rbs a: Integer
def method(a)
end
# bad - redundant trailing return type with @rbs skip
# @rbs skip
def method(a) #: void
end
# good
# @rbs skip
def method(a)
end
# good
# @rbs override
def method(a)
end
Style/RbsInline/RedundantInstanceVariableAnnotation
Warns when a # @rbs @ivar: Type instance variable type annotation is redundant because an attr_* with an inline type annotation already exists for the same attribute.
Supports autocorrect (removes the redundant instance variable type annotation).
Examples:
# bad
# @rbs @foo: Integer
attr_reader :foo #: Integer
# good
attr_reader :foo #: Integer
# good - no inline annotation, so ivar annotation is not redundant
# @rbs @foo: Integer
attr_reader :foo
Style/RbsInline/RedundantTypeAnnotation
Detects redundant type annotations when multiple type specifications exist for the same method. This covers both redundant argument type annotations (when both #: and # @rbs param specify the same parameter) and redundant return type annotations (when multiple of #:, trailing #:, and # @rbs return specify the return type).
Supports unsafe autocorrect.
Configuration: EnforcedStyle (default: doc_style)
method_type_signature: Prefers#:annotation comments with the full method signature;# @rbs param:and# @rbs return:annotations alongside a#:signature are redundantdoc_style: Prefers# @rbsannotations;#:method type signatures alongside# @rbsannotations are redundantdoc_style_and_return_annotation: Prefers# @rbs param:annotations with a trailing inline#:return type; full#:signatures and# @rbs return:annotations are redundant
Examples (EnforcedStyle: method_type_signature):
# bad - redundant @rbs parameter annotation
# @rbs a: Integer
#: (Integer) -> void
def method(a)
end
# bad - redundant trailing return type
#: () -> String
def method(arg) #: String
end
# good
#: (Integer) -> String
def method(a)
end
Examples (EnforcedStyle: doc_style):
# bad - redundant #: method type signature
# @rbs a: Integer
#: (Integer) -> void
def method(a)
end
# bad - redundant trailing return type
# @rbs return: String
def method(arg) #: String
end
# good
# @rbs a: Integer
# @rbs return: String
def method(a)
end
Examples (EnforcedStyle: doc_style_and_return_annotation):
# bad - redundant #: method type signature
# @rbs a: Integer
#: (Integer) -> String
def method(a)
end
# bad - redundant @rbs return annotation
# @rbs a: Integer
# @rbs return: String
def method(a) #: String
end
# good
# @rbs a: Integer
def method(a) #: String
end
Style/RbsInline/RequireRbsInlineComment
Enforces presence or absence of # rbs_inline: magic comment for consistency.
Configuration: EnforcedStyle (default: always)
always: Requires# rbs_inline: enabledor# rbs_inline: disablednever: Forbids# rbs_inline: enabled(allows# rbs_inline: disabled)
Examples (EnforcedStyle: always):
# bad
class Foo
end
# good
# rbs_inline: enabled
class Foo
end
Style/RbsInline/UnmatchedAnnotations
Verifies that annotation parameters match the actual method parameters.
Examples:
# bad
# @rbs unknown: String
def method(arg); end
# good
# @rbs arg: String
def method(arg); end
Style/RbsInline/UntypedInstanceVariable
Warns when an instance variable used in a class or module does not have an RBS type annotation. An instance variable is considered typed when a # @rbs @ivar: Type annotation exists in the class body, or when it is covered by an attr_reader, attr_writer, or attr_accessor declaration with an inline #: Type comment.
Examples:
# bad
class Foo
def
@baz
end
end
# good
class Foo
# @rbs @baz: Integer
def
@baz
end
end
# good
class Foo
attr_reader :baz #: Integer
def
@baz
end
end
Style/RbsInline/VariableCommentSpacing
Checks that @rbs variable comments for instance variables (@ivar), class variables (@@cvar), and class instance variables (self.@civar) are followed by a blank line. RBS::Inline requires these comments to be standalone, so code must not immediately follow them.
Supports autocorrect.
Examples:
# bad
# @rbs @ivar: Integer
# @rbs @@cvar: Float
# @rbs self.@civar: String
def method
end
# good
# @rbs @ivar: Integer
# @rbs @@cvar: Float
# @rbs self.@civar: String
def method
end
Configuration
You can customize cop behavior in your .rubocop.yml. For example:
# Prefer method type signatures over doc-style annotations
Style/RbsInline/RedundantTypeAnnotation:
EnforcedStyle: method_type_signature
# Only require annotations on public methods
Style/RbsInline/MissingTypeAnnotation:
Visibility: public
See config/default.yml for all available configuration options.
Development
After checking out the repo, run bin/setup to install dependencies. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and add Git tag named vX.Y.Z and push it to the GitHub. Then GitHub Actions will be release the package to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/tk0miya/rubocop-rbs_inline. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the rubocop-rbs_inline project's codebases and issue trackers is expected to follow the code of conduct.