rbs 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +5 -1
- data/.gitignore +2 -0
- data/CHANGELOG.md +32 -0
- data/README.md +1 -1
- data/Rakefile +9 -0
- data/Steepfile +1 -0
- data/core/array.rbs +1 -1
- data/core/basic_object.rbs +1 -1
- data/core/io.rbs +1 -1
- data/core/kernel.rbs +2 -2
- data/core/marshal.rbs +4 -3
- data/docs/rbs_by_example.md +328 -0
- data/docs/stdlib.md +1 -1
- data/docs/syntax.md +0 -3
- data/lib/rbs/definition_builder.rb +2 -18
- data/lib/rbs/definition_builder/ancestor_builder.rb +9 -2
- data/lib/rbs/errors.rb +36 -0
- data/lib/rbs/parser.rb +901 -884
- data/lib/rbs/parser.y +9 -4
- data/lib/rbs/prototype/rb.rb +7 -3
- data/lib/rbs/prototype/runtime.rb +118 -42
- data/lib/rbs/version.rb +1 -1
- data/sig/ancestor_builder.rbs +2 -0
- data/sig/errors.rbs +15 -0
- data/sig/namespace.rbs +1 -1
- data/sig/polyfill.rbs +0 -18
- data/stdlib/dbm/0/dbm.rbs +43 -30
- data/stdlib/mutex_m/0/mutex_m.rbs +1 -1
- data/stdlib/net-http/0/net-http.rbs +1846 -0
- data/stdlib/optparse/0/optparse.rbs +1214 -0
- data/stdlib/resolv/0/resolv.rbs +1504 -0
- data/stdlib/socket/0/addrinfo.rbs +469 -0
- data/stdlib/socket/0/basic_socket.rbs +503 -0
- data/stdlib/socket/0/ip_socket.rbs +72 -0
- data/stdlib/socket/0/socket.rbs +2687 -0
- data/stdlib/socket/0/tcp_server.rbs +177 -0
- data/stdlib/socket/0/tcp_socket.rbs +35 -0
- data/stdlib/socket/0/udp_socket.rbs +111 -0
- data/stdlib/socket/0/unix_server.rbs +154 -0
- data/stdlib/socket/0/unix_socket.rbs +132 -0
- data/stdlib/timeout/0/timeout.rbs +5 -0
- metadata +16 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab99593166ee140ca3ffc517eddcd872c6798dcb41a991c1e67c0c16a2a86fc9
|
4
|
+
data.tar.gz: a4e5cdd454fb49ddd499ba3382e118f8789b5413d0607ad9e3652551839c0ca3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d660c0dd7796bad07fac8e2ee85968e91259af0a4c9fed2c8668f0d6e385a517160d5792702181e18923929a3de7ded420c84e2184cb83a852d2133c1f34050
|
7
|
+
data.tar.gz: 4991d9a71cd0bd2bd2832d7764a8d65a73de146fecf76d3ccd67a41599326ca45b091e559acededcd095a44cdef6e32cc01fbb742e04bba945269b4e21a6444c
|
data/.github/workflows/ruby.yml
CHANGED
@@ -18,7 +18,11 @@ jobs:
|
|
18
18
|
job:
|
19
19
|
- test
|
20
20
|
- stdlib_test
|
21
|
-
- rubocop validate test_doc build test_generate_stdlib
|
21
|
+
- rubocop validate test_doc build test_generate_stdlib
|
22
|
+
- confirm_parser
|
23
|
+
exclude:
|
24
|
+
- container_tag: master-nightly-focal
|
25
|
+
job: confirm_parser
|
22
26
|
container:
|
23
27
|
image: rubylang/ruby:${{ matrix.container_tag }}
|
24
28
|
steps:
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,38 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 1.3.0 (2021-07-20)
|
6
|
+
|
7
|
+
### Summary
|
8
|
+
|
9
|
+
RBS 1.3.0 includes bug fixees of the parser and class/module definition validations.
|
10
|
+
|
11
|
+
### Signature updates
|
12
|
+
|
13
|
+
* dbm ([#718](https://github.com/ruby/rbs/pull/718))
|
14
|
+
* net-http ([#686](https://github.com/ruby/rbs/pull/686))
|
15
|
+
* optparse ([#693](https://github.com/ruby/rbs/pull/693))
|
16
|
+
* resolv ([#697](https://github.com/ruby/rbs/pull/697))
|
17
|
+
* socket ([#699](https://github.com/ruby/rbs/pull/699))
|
18
|
+
* `IO` ([#698](https://github.com/ruby/rbs/pull/698))
|
19
|
+
* `Marshal` ([#684](https://github.com/ruby/rbs/pull/684))
|
20
|
+
* `Mutex` ([#683](https://github.com/ruby/rbs/pull/683))
|
21
|
+
* `Array#shift` ([#707](https://github.com/ruby/rbs/pull/707))
|
22
|
+
* `BasicObject#method_missing` ([#707](https://github.com/ruby/rbs/pull/706), [#710](https://github.com/ruby/rbs/pull/710))
|
23
|
+
* `Kernel#caller` ([#705](https://github.com/ruby/rbs/pull/705))
|
24
|
+
|
25
|
+
### Library changes
|
26
|
+
|
27
|
+
* Interface names starting with lower case characters are now syntax error ([#678](https://github.com/ruby/rbs/pull/678), [#720](https://github.com/ruby/rbs/pull/720))
|
28
|
+
* Mixins of classes are rejected ([#681](https://github.com/ruby/rbs/pull/681))
|
29
|
+
* Generate prototype of `initialize` method with return type `void` ([#685](https://github.com/ruby/rbs/pull/685))
|
30
|
+
* Let `prototype runtime` generate class/module declarations in nested syntax ([#700](https://github.com/ruby/rbs/pull/700))
|
31
|
+
* Fix race condition for multi-thread support ([#702](https://github.com/ruby/rbs/pull/702))
|
32
|
+
|
33
|
+
### Miscellaneous
|
34
|
+
|
35
|
+
* Add new doc `docs/rbs_by_example.md` ([#694](https://github.com/ruby/rbs/pull/694))
|
36
|
+
|
5
37
|
## 1.2.1 (2021-05-27)
|
6
38
|
|
7
39
|
This release includes the following minor changes:
|
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -54,6 +54,15 @@ task :validate => :parser do
|
|
54
54
|
lib << "singleton"
|
55
55
|
end
|
56
56
|
|
57
|
+
if lib == ["net-http"]
|
58
|
+
lib << "uri"
|
59
|
+
end
|
60
|
+
|
61
|
+
if lib == ["resolv"]
|
62
|
+
lib << "socket"
|
63
|
+
lib << "timeout"
|
64
|
+
end
|
65
|
+
|
57
66
|
sh "#{ruby} #{rbs} #{lib.map {|l| "-r #{l}"}.join(" ")} validate --silent"
|
58
67
|
end
|
59
68
|
end
|
data/Steepfile
CHANGED
data/core/array.rbs
CHANGED
data/core/basic_object.rbs
CHANGED
@@ -215,7 +215,7 @@ class BasicObject
|
|
215
215
|
# r.xxiii #=> 23
|
216
216
|
# r.mm #=> 2000
|
217
217
|
#
|
218
|
-
def method_missing: (Symbol, *untyped) -> untyped
|
218
|
+
def method_missing: (Symbol, *untyped, **untyped) ?{ (*untyped, **untyped) -> untyped } -> untyped
|
219
219
|
|
220
220
|
# Invoked as a callback whenever a singleton method is added to the receiver.
|
221
221
|
#
|
data/core/io.rbs
CHANGED
@@ -746,7 +746,7 @@ class IO < Object
|
|
746
746
|
|
747
747
|
def self.readlines: (String name, ?String sep, ?Integer limit, ?external_encoding: String external_encoding, ?internal_encoding: String internal_encoding, ?encoding: String encoding, ?textmode: untyped textmode, ?binmode: untyped binmode, ?autoclose: untyped autoclose, ?mode: String mode) -> ::Array[String]
|
748
748
|
|
749
|
-
def self.select: (::Array[io]? read_array, ?::Array[io]? write_array, ?::Array[io]? error_array, ?
|
749
|
+
def self.select: (::Array[io]? read_array, ?::Array[io]? write_array, ?::Array[io]? error_array, ?Numeric? timeout) -> ::Array[::Array[io]]?
|
750
750
|
|
751
751
|
def self.sysopen: (String path, ?String mode, ?String perm) -> Integer
|
752
752
|
|
data/core/kernel.rbs
CHANGED
@@ -13,8 +13,8 @@
|
|
13
13
|
module Kernel : BasicObject
|
14
14
|
private
|
15
15
|
|
16
|
-
def self?.caller: (
|
17
|
-
| (
|
16
|
+
def self?.caller: (Integer start_or_range, ?Integer length) -> ::Array[String]?
|
17
|
+
| (::Range[Integer] start_or_range) -> ::Array[String]?
|
18
18
|
| () -> ::Array[String]
|
19
19
|
|
20
20
|
def self?.caller_locations: (?Integer start_or_range, ?Integer length) -> ::Array[Thread::Backtrace::Location]?
|
data/core/marshal.rbs
CHANGED
@@ -136,8 +136,8 @@ module Marshal
|
|
136
136
|
# ThreadGroup, Continuation
|
137
137
|
# * objects which define singleton methods
|
138
138
|
#
|
139
|
-
def self.dump: (
|
140
|
-
| (
|
139
|
+
def self.dump: (untyped obj, untyped port, ?Integer limit) -> untyped
|
140
|
+
| (untyped obj, ?Integer limit) -> String
|
141
141
|
|
142
142
|
# Returns the result of converting the serialized data in source into a Ruby
|
143
143
|
# object (possibly with associated subordinate objects). source may be either an
|
@@ -147,7 +147,8 @@ module Marshal
|
|
147
147
|
# Never pass untrusted data (including user supplied input) to this method.
|
148
148
|
# Please see the overview for further details.
|
149
149
|
#
|
150
|
-
def self.load: (String
|
150
|
+
def self.load: (String | untyped port) -> untyped
|
151
|
+
| [A] (String | untyped port, ^(untyped) -> A) -> A
|
151
152
|
|
152
153
|
alias self.restore self.load
|
153
154
|
end
|
@@ -0,0 +1,328 @@
|
|
1
|
+
# RBS By Example
|
2
|
+
|
3
|
+
## Goal
|
4
|
+
|
5
|
+
The purpose of this doc is to teach you how to write RBS signatures by using the standard library's methods as a guide.
|
6
|
+
|
7
|
+
## Examples
|
8
|
+
|
9
|
+
### Zero argument methods
|
10
|
+
|
11
|
+
**Example:** `String#empty?`
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
# .rb
|
15
|
+
"".empty?
|
16
|
+
# => true
|
17
|
+
"hello".empty?
|
18
|
+
# => false
|
19
|
+
```
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
# .rbs
|
23
|
+
class String
|
24
|
+
def empty?: () -> bool
|
25
|
+
end
|
26
|
+
```
|
27
|
+
|
28
|
+
`String`'s `#empty` method takes no parameters, and returns a boolean value
|
29
|
+
|
30
|
+
### Single argument methods
|
31
|
+
|
32
|
+
**Example:** `String#include?`
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
# .rb
|
36
|
+
"homeowner".include?("house")
|
37
|
+
# => false
|
38
|
+
"homeowner".include?("meow")
|
39
|
+
# => true
|
40
|
+
```
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
class String
|
44
|
+
def include?: (String) -> bool
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
`String`'s `include?` method takes one argument, a `String`, and returns a
|
49
|
+
boolean value
|
50
|
+
|
51
|
+
### Variable argument methods
|
52
|
+
|
53
|
+
**Example:** `String#end_with?`
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
# .rb
|
57
|
+
"hello?".end_with?("!")
|
58
|
+
# => false
|
59
|
+
"hello?".end_with?("?")
|
60
|
+
# => true
|
61
|
+
"hello?".end_with?("?", "!")
|
62
|
+
# => true
|
63
|
+
"hello?".end_with?(".", "!")
|
64
|
+
# => false
|
65
|
+
```
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
# .rbs
|
69
|
+
class String
|
70
|
+
def end_with?: (*String) -> bool
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
`String`'s `#end_with?` method takes any number of `String` arguments, and
|
75
|
+
returns a boolean value.
|
76
|
+
|
77
|
+
### Optional positional arguments
|
78
|
+
|
79
|
+
**Example:** `String#ljust`
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
# .rb
|
83
|
+
"hello".ljust(4)
|
84
|
+
#=> "hello"
|
85
|
+
"hello".ljust(20)
|
86
|
+
#=> "hello "
|
87
|
+
"hello".ljust(20, '1234')
|
88
|
+
#=> "hello123412341234123"
|
89
|
+
```
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
# .rbs
|
93
|
+
class String
|
94
|
+
def ljust: (Integer, ?String) -> String
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
`String`'s `ljust` takes one `Integer` argument, and an optional `String` argument, indicated by the the `?` prefix marker. It returns a `String`.
|
99
|
+
|
100
|
+
### Multiple signatures for a single method
|
101
|
+
|
102
|
+
**Example:** `Array#*`
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
# .rb
|
106
|
+
[1, 2, 3] * ","
|
107
|
+
# => "1,2,3"
|
108
|
+
[1, 2, 3] * 2
|
109
|
+
# => [1, 2, 3, 1, 2, 3]
|
110
|
+
```
|
111
|
+
|
112
|
+
*Note:* Some of the signatures after this point include type variables (e.g. `Elem`, `T`).
|
113
|
+
For now, it's safe to ignore them, but they're included for completeness.
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
# .rbs
|
117
|
+
class Array[Elem]
|
118
|
+
def *: (String) -> String
|
119
|
+
| (Integer) -> Array[Elem]
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
`Array`'s `*` method, when given a `String` returns a `String`. When given an
|
124
|
+
`Integer`, it returns an `Array` of the same contained type `Elem` (in our example case, `Elem` corresponds to `Integer`).
|
125
|
+
|
126
|
+
### Union types
|
127
|
+
|
128
|
+
**Example:** `String#<<`
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
# .rb
|
132
|
+
a = "hello "
|
133
|
+
a << "world"
|
134
|
+
#=> "hello world"
|
135
|
+
a << 33
|
136
|
+
#=> "hello world!"
|
137
|
+
```
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
# .rbs
|
141
|
+
class String
|
142
|
+
def <<: (String | Integer) -> String
|
143
|
+
end
|
144
|
+
```
|
145
|
+
|
146
|
+
`String`'s `<<` operator takes either a `String` or an `Integer`, and returns a `String`.
|
147
|
+
|
148
|
+
### Nilable types
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
# .rb
|
152
|
+
[1, 2, 3].first
|
153
|
+
# => 1
|
154
|
+
[].first
|
155
|
+
# => nil
|
156
|
+
[1, 2, 3].first(2)
|
157
|
+
# => [1, 2]
|
158
|
+
[].first(2)
|
159
|
+
# => []
|
160
|
+
```
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
# .rbs
|
164
|
+
class Enumerable[Elem]
|
165
|
+
def first: () -> Elem?
|
166
|
+
| (Integer) -> Array[Elem]
|
167
|
+
end
|
168
|
+
```
|
169
|
+
|
170
|
+
`Enumerable`'s `#first` method has two different signatures.
|
171
|
+
|
172
|
+
When called with no arguments, the return value will either be an instance of
|
173
|
+
whatever type is contained in the enumerable, or `nil`. We represent that with
|
174
|
+
the type variable `Elem`, and the `?` suffix nilable marker.
|
175
|
+
|
176
|
+
When called with an `Integer` positional argument, the return value will be an
|
177
|
+
`Array` of whatever type is contained.
|
178
|
+
|
179
|
+
The `?` syntax is a convenient shorthand for a union with nil. An equivalent union type woould be `(Elem | nil)`.
|
180
|
+
|
181
|
+
### Keyword Arguments
|
182
|
+
|
183
|
+
**Example**: `String#lines`
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
# .rb
|
187
|
+
"hello\nworld\n".lines
|
188
|
+
# => ["hello\n", "world\n"]
|
189
|
+
"hello world".lines(' ')
|
190
|
+
# => ["hello ", " ", "world"]
|
191
|
+
"hello\nworld\n".lines(chomp: true)
|
192
|
+
# => ["hello", "world"]
|
193
|
+
```
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
# .rbs
|
197
|
+
class String
|
198
|
+
def lines: (?String, ?chomp: bool) -> Array[String]
|
199
|
+
end
|
200
|
+
```
|
201
|
+
|
202
|
+
`String`'s `#lines` method take two arguments: one optional String argument, and another optional boolean keyword argument. It returns an `Array` of `String`s.
|
203
|
+
|
204
|
+
Keyword arguments are declared similar to in ruby, with the keyword immediately followed by a colon. Keyword arguments that are optional are indicated as optional using the same `?` prefix as positional arguments.
|
205
|
+
|
206
|
+
|
207
|
+
### Class methods
|
208
|
+
|
209
|
+
**Example**: `Time.now`
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
# .rb
|
213
|
+
Time.now
|
214
|
+
# => 2009-06-24 12:39:54 +0900
|
215
|
+
```
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
class Time
|
219
|
+
def self.now: () -> Time
|
220
|
+
end
|
221
|
+
```
|
222
|
+
|
223
|
+
`Time`'s class method `now` takes no arguments, and returns an instance of the
|
224
|
+
`Time` class.
|
225
|
+
|
226
|
+
### Block Arguments
|
227
|
+
|
228
|
+
**Example**: `Array#filter`
|
229
|
+
|
230
|
+
```ruby
|
231
|
+
# .rb
|
232
|
+
[1,2,3,4,5].select {|num| num.even? }
|
233
|
+
# => [2, 4]
|
234
|
+
%w[ a b c d e f ].select {|v| v =~ /[aeiou]/ }
|
235
|
+
# => ["a", "e"]
|
236
|
+
[1,2,3,4,5].filter
|
237
|
+
```
|
238
|
+
|
239
|
+
```ruby
|
240
|
+
# .rbs
|
241
|
+
class Array[Elem]
|
242
|
+
def filter: () { (Elem) -> boolish } -> ::Array[Elem]
|
243
|
+
| () -> ::Enumerator[Elem, ::Array[Elem]]
|
244
|
+
end
|
245
|
+
```
|
246
|
+
|
247
|
+
`Array`'s `#filter` method, when called with no arguments returns an Enumerator.
|
248
|
+
|
249
|
+
When called with a block, the method returns an `Array` of whatever type the original contained. The block will take one argument, of the type of the contained value, and the block will return a truthy or falsy value.
|
250
|
+
|
251
|
+
`boolish` is a special keyword for any type that will be treated as if it were a `bool`.
|
252
|
+
|
253
|
+
### Type Variables
|
254
|
+
|
255
|
+
**Example**: `Hash`, `Hash#keys`
|
256
|
+
|
257
|
+
```ruby
|
258
|
+
h = { "a" => 100, "b" => 200, "c" => 300, "d" => 400 }
|
259
|
+
h.keys
|
260
|
+
# => ["a", "b", "c", "d"]
|
261
|
+
```
|
262
|
+
|
263
|
+
```ruby
|
264
|
+
# .rbs
|
265
|
+
class Hash[K, V]
|
266
|
+
def keys: () -> Array[K]
|
267
|
+
end
|
268
|
+
```
|
269
|
+
|
270
|
+
Generic types in RBS are parameterized at declaration time. These type variables are then available throughout all the methods contained in the `class` block.
|
271
|
+
|
272
|
+
`Hash`'s `#keys` method takes no arguments, and returns an `Array` of the first type parameter. In the above example, `a` is of concrete type `Hash[String, Integer]`, so `#keys` returns an `Array` for `String`.
|
273
|
+
|
274
|
+
|
275
|
+
```ruby
|
276
|
+
# .rb
|
277
|
+
a = [ "a", "b", "c", "d" ]
|
278
|
+
a.collect {|x| x + "!"}
|
279
|
+
# => ["a!", "b!", "c!", "d!"]
|
280
|
+
a.collect.with_index {|x, i| x * i}
|
281
|
+
# => ["", "b", "cc", "ddd"]
|
282
|
+
```
|
283
|
+
|
284
|
+
```ruby
|
285
|
+
# .rbs
|
286
|
+
class Array[Elem]
|
287
|
+
def collect: [U] () { (Elem) -> U } -> Array[U]
|
288
|
+
| () -> Enumerator[Elem, Array[untyped]]
|
289
|
+
end
|
290
|
+
```
|
291
|
+
|
292
|
+
Type variables can also be introduced in methods. Here, in `Array`'s `#collect` method, we introduce a type variable `U`. The block passed to `#collect` will receive a parameter of type `Elem`, and return a value of type `U`. Then `#collect` will return an `Array` of type `U`.
|
293
|
+
|
294
|
+
In this example, the method receives its signature from the inferred return type of the passed block. When then block is absent, as in when the method returns an `Enumerator`, we can't infer the type, and so the return value of the enumerator can only be described as `Array[untyped]`.
|
295
|
+
|
296
|
+
### Tuples
|
297
|
+
|
298
|
+
**Examples**: `Enumerable#partition`, `Enumerable#to_h`
|
299
|
+
|
300
|
+
```ruby
|
301
|
+
(1..6).partition { |v| v.even? }
|
302
|
+
# => [[2, 4, 6], [1, 3, 5]]
|
303
|
+
```
|
304
|
+
|
305
|
+
```ruby
|
306
|
+
class Enumerable[Elem]
|
307
|
+
def partition: () { (Elem) -> boolish } -> [Array[Elem], Array[Elem]]
|
308
|
+
| () -> ::Enumerator[Elem, [Array[Elem], Array[Elem] ]]
|
309
|
+
end
|
310
|
+
```
|
311
|
+
|
312
|
+
`Enumerable`'s `partition` method, when given a block, returns a 2-item tuple of `Array`s containing the original type of the `Enumerable`.
|
313
|
+
|
314
|
+
Tuples can be of any size, and they can have mixed types.
|
315
|
+
|
316
|
+
```ruby
|
317
|
+
(1..5).to_h {|x| [x, x ** 2]}
|
318
|
+
# => {1=>1, 2=>4, 3=>9, 4=>16, 5=>25}
|
319
|
+
```
|
320
|
+
|
321
|
+
```ruby
|
322
|
+
class Enumerable[Elem]
|
323
|
+
def to_h: () -> ::Hash[untyped, untyped]
|
324
|
+
| [T, U] () { (Elem) -> [T, U] } -> ::Hash[T, U]
|
325
|
+
end
|
326
|
+
```
|
327
|
+
|
328
|
+
`Enumerable`'s `to_h` method, when given a block that returns a 2-item tuple, returns a `Hash` with keys the type of the first position in the tuple, and values the type of the second position in the tuple.
|