Skip to content

Commit dd4985c

Browse files
authored
Merge pull request #2625 from ruby/inline--docs
Add docs
2 parents 711b2e2 + 382c051 commit dd4985c

File tree

1 file changed

+345
-0
lines changed

1 file changed

+345
-0
lines changed

docs/inline.md

Lines changed: 345 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
# Inline RBS Type Declaration
2+
3+
Inline RBS type declarations allow you to write type annotations directly in your Ruby source files using comments. Instead of maintaining separate `.rbs` files, you can keep your type information alongside your Ruby code, making it easier to keep types and implementation in sync.
4+
5+
The following example defines `Calculator` class and `add` instance method. The `@rbs` comment gives the type of the `add` method with the RBS method type syntax.
6+
7+
```ruby
8+
class Calculator
9+
# @rbs (Integer, Integer) -> Integer
10+
def add(a, b)
11+
a + b
12+
end
13+
end
14+
```
15+
16+
## Classes
17+
18+
Inline RBS supports class definitions from your Ruby code. When you define a class in Ruby, the library recognizes it and the corresponding class definition is generated in RBS.
19+
20+
```ruby
21+
class App
22+
end
23+
```
24+
25+
The `::App` class is defined in RBS and you can use it as a type.
26+
27+
### Non-constant class paths
28+
29+
Only classes with constant names are imported. Dynamic or non-constant class definitions are ignored:
30+
31+
```ruby
32+
# This class is imported
33+
class MyClass
34+
end
35+
36+
# This is ignored - dynamic class definition
37+
MyClass = Class.new do
38+
end
39+
40+
# This is also ignored - non-constant class name
41+
object = Object
42+
class object::MyClass
43+
end
44+
```
45+
46+
### Class Nesting
47+
48+
Nested classes work as expected:
49+
50+
```ruby
51+
class Client
52+
class Error
53+
end
54+
end
55+
```
56+
57+
This creates the types `::Client` and `::Client::Error`.
58+
59+
### Current Limitations
60+
61+
- Inheritance is not supported
62+
- Generic class definitions are not supported
63+
64+
## Modules
65+
66+
Inline RBS supports module definitions from your Ruby code. When you define a module in Ruby, the library recognizes it and the corresponding module definition is generated in RBS.
67+
68+
```ruby
69+
module Helper
70+
end
71+
```
72+
73+
The `::Helper` module is defined in RBS and you can use it as a type.
74+
75+
### Non-constant module paths
76+
77+
Only modules with constant names are imported. Dynamic or non-constant module definitions are ignored:
78+
79+
```ruby
80+
# This module is imported
81+
module MyModule
82+
end
83+
84+
# This is ignored - dynamic module definition
85+
MyModule = Module.new do
86+
end
87+
88+
# This is also ignored - non-constant module name
89+
object = Object
90+
module object::MyModule
91+
end
92+
```
93+
94+
### Module Nesting
95+
96+
Nested modules work as expected:
97+
98+
```ruby
99+
module API
100+
module V1
101+
module Resources
102+
end
103+
end
104+
end
105+
```
106+
107+
This creates the types `::API`, `::API::V1`, and `::API::V1::Resources`.
108+
109+
### Current Limitations
110+
111+
- Generic module definitions are not supported
112+
- Module self-type constraints are not supported
113+
114+
## Method Definitions
115+
116+
Inline RBS supports methods defined using the `def` syntax in Ruby.
117+
118+
```ruby
119+
class Calculator
120+
def add(x, y) = x+y
121+
end
122+
```
123+
124+
It detects method definitions and allows you to add annotation comments to describe their types.
125+
126+
### Unannotated method definition
127+
128+
Methods defined with `def` syntax are detected, but they are untyped.
129+
130+
```ruby
131+
class Calculator
132+
def add(x, y) = x+y
133+
end
134+
```
135+
136+
The type of the `Calculator#add` method is `(?) -> untyped` -- it accepts any arguments without type checking and returns an `untyped` object.
137+
138+
### Method type annotation syntax
139+
140+
You can define the type of the method using `@rbs` and `:` syntax.
141+
142+
```ruby
143+
class Calculator
144+
# @rbs (Integer, Integer) -> Integer
145+
def add(x, y) = x + y
146+
147+
#: (Integer, Integer) -> Integer
148+
def subtract(x, y) = x - y
149+
end
150+
```
151+
152+
The type of both methods is `(Integer, Integer) -> Integer` -- they take two `Integer` objects and return an `Integer` object.
153+
154+
Both syntaxes support method overloading:
155+
156+
```ruby
157+
class Calculator
158+
# @rbs (Integer, Integer) -> Integer
159+
# | (Float, Float) -> Float
160+
def add(x, y) = x + y
161+
162+
#: (Integer, Integer) -> Integer
163+
#: (Float, Float) -> Float
164+
def subtract(x, y) = x - y
165+
end
166+
```
167+
168+
The type of both methods is `(Integer, Integer) -> Integer | (Float, Float) -> Float`.
169+
170+
> [!NOTE]
171+
> The `@rbs METHOD-TYPE` syntax allows overloads with the `|` operator, just like in RBS files.
172+
> Multiple `: METHOD-TYPE` declarations are required for overloads.
173+
174+
#### Doc-style syntax
175+
176+
The `@rbs return: T` syntax declares the return type of a method:
177+
178+
```ruby
179+
class Calculator
180+
# @rbs return: String
181+
def to_s
182+
"Calculator"
183+
end
184+
end
185+
```
186+
187+
### Current Limitations
188+
189+
- Class methods and singleton methods are not supported
190+
- Parameter types are not supported with doc-style syntax
191+
- Method visibility declaration is not supported yet
192+
193+
## Attributes
194+
195+
Inline RBS supports Ruby's attribute methods: `attr_reader`, `attr_writer`, and `attr_accessor`.
196+
197+
```ruby
198+
class Person
199+
attr_reader :name #: String
200+
attr_writer :age #: Integer
201+
attr_accessor :email #: String?
202+
end
203+
```
204+
205+
It detects these attribute declarations and generates the corresponding getter and setter methods.
206+
207+
The accessor methods and instance variables are defined.
208+
209+
### Unannotated attributes
210+
211+
Attributes defined without type annotations are treated as `untyped`:
212+
213+
```ruby
214+
class Person
215+
attr_reader :name
216+
attr_writer :age
217+
attr_accessor :email
218+
end
219+
```
220+
221+
### Type annotations for attributes
222+
223+
You can add type annotations to attributes using the `#:` syntax in trailing comments:
224+
225+
```ruby
226+
class Person
227+
attr_reader :name #: String
228+
attr_writer :age #: Integer
229+
attr_accessor :email #: String?
230+
end
231+
```
232+
233+
This generates the following typed methods:
234+
- `name: () -> String`
235+
- `age=: (Integer) -> Integer`
236+
- `email: () -> String?` and `email=: (String?) -> String?`
237+
238+
### Multiple attributes
239+
240+
When declaring multiple attributes in one line, the type annotation applies to all attributes:
241+
242+
```ruby
243+
class Person
244+
attr_reader :first_name, :last_name #: String
245+
attr_accessor :age, :height #: Integer
246+
end
247+
```
248+
249+
All attributes in each declaration share the same type.
250+
251+
### Non-symbol attribute names
252+
253+
Attribute names must be symbol literals.
254+
255+
```ruby
256+
class Person
257+
attr_reader "name" #: String
258+
259+
age = :age
260+
attr_writer age #: Integer
261+
end
262+
```
263+
264+
The attribute definitions are ignored because the names are given by string literals and local variables.
265+
266+
### Current Limitations
267+
268+
- Attribute visibility is not supported yet. All attributes are _public_
269+
270+
## Mixin
271+
272+
Inline RBS supports Ruby's mixin methods: `include`, `extend`, and `prepend`.
273+
274+
```ruby
275+
module Printable
276+
# @rbs () -> String
277+
def to_print
278+
to_s
279+
end
280+
end
281+
282+
class Document
283+
include Printable
284+
extend Enumerable #[String]
285+
prepend Trackable
286+
end
287+
```
288+
289+
It detects these mixin declarations and adds them to the class or module definition.
290+
291+
### Basic mixin usage
292+
293+
Mixins work just like in regular RBS files:
294+
295+
```ruby
296+
module Helper
297+
end
298+
299+
class MyClass
300+
include Helper
301+
extend Helper
302+
prepend Helper
303+
end
304+
```
305+
306+
### Type arguments for generic modules
307+
308+
You can specify type arguments for generic modules using the `#[...]` syntax:
309+
310+
```ruby
311+
class TodoList
312+
include Enumerable #[String]
313+
314+
# @rbs () { (String) -> void } -> void
315+
def each(&block)
316+
@items.each(&block)
317+
end
318+
end
319+
```
320+
321+
### Module name requirements
322+
323+
Only constant module names are supported. Dynamic module references are not allowed:
324+
325+
```ruby
326+
class MyClass
327+
include Helper # ✓ Works - constant name
328+
329+
mod = Helper
330+
include mod # ✗ Ignored - non-constant module reference
331+
332+
include Helper.new # ✗ Ignored - not a simple constant
333+
end
334+
```
335+
336+
### Module name resolution
337+
338+
The module name resolution is based on the nesting of the class/module definitions, unlike Ruby.
339+
340+
Modules accessible through ancestors (super-class/included modules) are not supported.
341+
342+
### Current Limitations
343+
344+
- Only single module arguments are supported (no `include A, B` syntax)
345+
- Module names must be constants

0 commit comments

Comments
 (0)