-
Notifications
You must be signed in to change notification settings - Fork 6
Syntax guide
# rbs_inline: enabled
magic comment is required to generate RBS from Ruby code.
# rbs_inline: enabled
class Foo
end
The class
syntax in Ruby is translated to class definition in RBS. Note that the class names and super class names must be constant syntax in Ruby.
class Foo
end
Generic classes can be defined with # @rbs generic
annotation.
# @rbs generic A -- Type of `a`
# @rbs generic unchecked in B < String -- Type of `b`
class Foo
end
The class definition generates the following RBS definition:
class Foo[A, unchecked in B < String]
end
The constant super class is supported. Generics is also supported by #[
annotation.
class Foo < String
end
class Bar < Array #[String]
end
# @rbs inherits
annotation allows specifying super class with RBS syntax, even if the super class syntax in Ruby is something unsupported.
# @rbs inherits Hash[String, Integer]
class Foo < Hash
end
# @rbs inherits Struct[String | Integer]
class Bar < Struct.new(:size, :name, keyword_init: true)
end
The module
syntax in Ruby is translated to a module definition in RBS. Note that the module name must be constant syntax in Ruby.
module Foo
end
Generics is supported with # @rbs generic
annotation, like class definition.
Module self type constraints can be defined with # @rbs module-self
annotation.
# @rbs module-self BasicObject
module Kernel
end
Mixin method calls with constant syntax -- include
, prepend
, and extend
-- are translated to mixin syntax in RBS.
class Foo
include Foo
extend Enumerable #[Integer, void]
end
The #[
syntax allows mixing generic modules.
We have two syntaxes for type of methods.
This is more primitive syntax. It allows writing RBS method type embedded in Ruby code.
#:: () -> String
def to_s
end
#:: (?Regexp?) -> Enumerator[String, void]
#:: (?Regexp?) { (String) -> void } -> void
def each_person(pattern = nil, &block)
end
Having multiple #::
syntax generates method definition with overloads.
Here is the example of doc style syntax.
# @rbs size: Integer -- The size of the section in px
# @rbs title: String -- Title of the section
# @rbs rest: Array[String] -- Type of rest args must be `Array[T]`
# @rbs kwrest: Hash[Symbol, untyped] -- Type of keyword rest args must be `Hash[K, V]`
# @rbs returns Section? -- Returns the new section or `nil`
def section(size, title: "Hello", *rest, **kwrest)
end
You can write down type of parameters like # @rbs var: TYPE -- some comments
. The @rbs returns
defines the return type.
The block types can be defined with # @rbs yields
annotations.
# @rbs yields -- Block is required, but not clear what will be yielded
def foo
yield 1
yield 2, "true"
end
# @rbs yields [optional] -- Block is optional
def bar
end
# @rbs yields (String) -> void -- It yields String
def baz
end
We also have #::
syntax at method definition which allows defining method return type.
def to_s #:: String
end
Note
Overloaded methods nor generic methods cannot be defined with doc-style syntax.
You can escape local variable names conflicting to keywords, like returns
, yields
, skip
, with !
.
# @rbs !returns: bool
# @rbs !yields: String
# @rbs !skip: untyped
def foo(returns, yields, skip)
end
# @rbs override
annotation tells the method is overriding the super class definition.
# @rbs override
def foo(x, y)
end
This generates def foo: ...
. We need this annotation to avoid having parameters types and the return type untyped
, while we don't want to copy and paste the super method definition.
def self.foo
syntax inside a class/module definition is supported.
Other receivers nor singleton class definition syntax <<self
are not supported.
# @rbs %a{}
syntax allows giving annotations to methods.
# @rbs %a{pure} %a{another:annotation}
def to_s #:: String
end
The standard attribute definition methods are supported -- attr_reader
, attr_writer
, and attr_accessor
.
class Foo
attr_reader :name #:: String
attr_reader :size, :count #:: Integer
end
Attribute names defined with symbol literal are supported. One attribute method call can have several names, but all of them will have the same type.
You can use # @rbs @var: Type
annotation.
class Foo
# @rbs @name: String -- Instance variable
# @rbs self.@all_names: Array[String] -- Instance variable of the class
end
Add #::
syntax to declare constant of a specific type. The gem infers some simple types for literals.
VERSION = "1.2.3"
Foo = [1,2,3].sample #:: Integer
alias
syntax in Ruby code is detected and alias
declaration will be generated in RBS.
class Foo
def ==(other) #:: bool
end
alias eql? ==
end
You may want to # @rbs skip
annotation to skip generating RBS definition.
# @rbs skip
class HiddenClass
end
class Foo
# @rbs skip
def hidden_method
end
end
We have # @rbs!
annotation for something not covered by the annotations.
class Person
include ActiveModel::Model
include ActiveModel::Attributes
attribute :id, :integer, default: 0
attribute :name, :string, default: ''
# @rbs!
# attr_accessor id (): Integer
# attr_accessor name (): String
end