rbs 0.7.0 → 0.11.0
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/CHANGELOG.md +34 -0
- data/Gemfile +1 -0
- data/README.md +1 -1
- data/docs/syntax.md +14 -1
- data/lib/rbs/ast/comment.rb +6 -0
- data/lib/rbs/ast/members.rb +3 -8
- data/lib/rbs/cli.rb +83 -4
- data/lib/rbs/definition.rb +15 -5
- data/lib/rbs/definition_builder.rb +32 -13
- data/lib/rbs/environment.rb +0 -1
- data/lib/rbs/environment_loader.rb +55 -35
- data/lib/rbs/location.rb +15 -0
- data/lib/rbs/parser.y +30 -20
- data/lib/rbs/prototype/rb.rb +0 -1
- data/lib/rbs/prototype/rbi.rb +0 -2
- data/lib/rbs/prototype/runtime.rb +0 -4
- data/lib/rbs/test.rb +1 -0
- data/lib/rbs/test/errors.rb +5 -1
- data/lib/rbs/test/hook.rb +1 -0
- data/lib/rbs/test/setup.rb +37 -15
- data/lib/rbs/test/setup_helper.rb +44 -0
- data/lib/rbs/test/tester.rb +61 -15
- data/lib/rbs/test/type_check.rb +45 -17
- data/lib/rbs/validator.rb +4 -0
- data/lib/rbs/version.rb +1 -1
- data/lib/rbs/writer.rb +7 -3
- data/stdlib/builtin/array.rbs +2 -1
- data/stdlib/builtin/enumerable.rbs +2 -2
- data/stdlib/builtin/hash.rbs +1 -1
- data/stdlib/date/date.rbs +1056 -0
- data/stdlib/date/date_time.rbs +582 -0
- data/stdlib/json/json.rbs +6 -0
- data/stdlib/pty/pty.rbs +159 -0
- data/stdlib/zlib/zlib.rbs +392 -0
- metadata +7 -2
data/lib/rbs/environment.rb
CHANGED
@@ -75,29 +75,16 @@ module RBS
|
|
75
75
|
self.class.gem_sig_path(name, version)
|
76
76
|
end
|
77
77
|
|
78
|
-
def each_signature(path
|
78
|
+
def each_signature(path, immediate: true, &block)
|
79
79
|
if block_given?
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
yield path
|
85
|
-
end
|
86
|
-
when path.directory?
|
87
|
-
path.children.each do |child|
|
88
|
-
each_signature child, immediate: false, &block
|
89
|
-
end
|
80
|
+
case
|
81
|
+
when path.file?
|
82
|
+
if path.extname == ".rbs" || immediate
|
83
|
+
yield path
|
90
84
|
end
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
when Pathname
|
95
|
-
each_signature path, immediate: immediate, &block
|
96
|
-
when LibraryPath
|
97
|
-
each_signature path.path, immediate: immediate, &block
|
98
|
-
when GemPath
|
99
|
-
each_signature path.path, immediate: immediate, &block
|
100
|
-
end
|
85
|
+
when path.directory?
|
86
|
+
path.children.each do |child|
|
87
|
+
each_signature child, immediate: false, &block
|
101
88
|
end
|
102
89
|
end
|
103
90
|
else
|
@@ -105,32 +92,65 @@ module RBS
|
|
105
92
|
end
|
106
93
|
end
|
107
94
|
|
108
|
-
def
|
109
|
-
|
95
|
+
def each_library_path
|
96
|
+
paths.each do |path|
|
97
|
+
case path
|
98
|
+
when Pathname
|
99
|
+
yield path, path
|
100
|
+
when LibraryPath
|
101
|
+
yield path, path.path
|
102
|
+
when GemPath
|
103
|
+
yield path, path.path
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def no_builtin!(skip = true)
|
109
|
+
@no_builtin = skip
|
110
|
+
self
|
110
111
|
end
|
111
112
|
|
112
113
|
def no_builtin?
|
113
114
|
@no_builtin
|
114
115
|
end
|
115
116
|
|
116
|
-
def
|
117
|
-
|
117
|
+
def each_decl
|
118
|
+
if block_given?
|
119
|
+
signature_files = []
|
118
120
|
|
119
|
-
|
120
|
-
|
121
|
-
|
121
|
+
unless no_builtin?
|
122
|
+
each_signature(stdlib_root + "builtin") do |path|
|
123
|
+
signature_files << [:stdlib, path]
|
124
|
+
end
|
125
|
+
end
|
122
126
|
|
123
|
-
|
124
|
-
|
127
|
+
each_library_path do |library_path, pathname|
|
128
|
+
each_signature(pathname) do |path|
|
129
|
+
signature_files << [library_path, path]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
signature_files.each do |lib_path, file_path|
|
134
|
+
buffer = Buffer.new(name: file_path.to_s, content: file_path.read)
|
135
|
+
Parser.parse_signature(buffer).each do |decl|
|
136
|
+
yield decl, buffer, file_path, lib_path
|
137
|
+
end
|
138
|
+
end
|
139
|
+
else
|
140
|
+
enum_for :each_decl
|
125
141
|
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def load(env:)
|
145
|
+
loadeds = []
|
126
146
|
|
127
|
-
|
128
|
-
buffer = Buffer.new(name: file.to_s, content: file.read)
|
147
|
+
each_decl do |decl, buffer, file_path, lib_path|
|
129
148
|
env.buffers.push(buffer)
|
130
|
-
|
131
|
-
|
132
|
-
end
|
149
|
+
env << decl
|
150
|
+
loadeds << [decl, file_path, lib_path]
|
133
151
|
end
|
152
|
+
|
153
|
+
loadeds
|
134
154
|
end
|
135
155
|
end
|
136
156
|
end
|
data/lib/rbs/location.rb
CHANGED
@@ -77,6 +77,21 @@ module RBS
|
|
77
77
|
locations.inject {|l1, l2| l1 + l2 }
|
78
78
|
end
|
79
79
|
|
80
|
+
def concat(*others)
|
81
|
+
others.each { |other| self << other }
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
def <<(other)
|
86
|
+
if other
|
87
|
+
raise "Invalid concat: buffer=#{buffer.name}, other.buffer=#{other.buffer.name}" unless other.buffer == buffer
|
88
|
+
@end_pos = other.end_pos
|
89
|
+
@source = nil
|
90
|
+
@end_loc = nil
|
91
|
+
end
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
80
95
|
def pred?(loc)
|
81
96
|
loc.is_a?(Location) &&
|
82
97
|
loc.name == name &&
|
data/lib/rbs/parser.y
CHANGED
@@ -4,9 +4,9 @@ class RBS::Parser
|
|
4
4
|
tANNOTATION
|
5
5
|
tSTRING tSYMBOL tINTEGER tWRITE_ATTR
|
6
6
|
kLPAREN kRPAREN kLBRACKET kRBRACKET kLBRACE kRBRACE
|
7
|
-
kVOID kNIL kTRUE kFALSE kANY kUNTYPED kTOP kBOT kSELF kSELFQ kINSTANCE kCLASS kBOOL kSINGLETON kTYPE kDEF kMODULE
|
7
|
+
kVOID kNIL kTRUE kFALSE kANY kUNTYPED kTOP kBOT kSELF kSELFQ kINSTANCE kCLASS kBOOL kSINGLETON kTYPE kDEF kMODULE
|
8
8
|
kPRIVATE kPUBLIC kALIAS
|
9
|
-
kCOLON kCOLON2 kCOMMA kBAR kAMP kHAT kARROW kQUESTION kEXCLAMATION kSTAR kSTAR2 kFATARROW kEQ kDOT kLT
|
9
|
+
kCOLON kCOLON2 kCOMMA kBAR kAMP kHAT kARROW kQUESTION kEXCLAMATION kSTAR kSTAR2 kFATARROW kEQ kDOT kDOT3 kLT
|
10
10
|
kINTERFACE kEND kINCLUDE kEXTEND kATTRREADER kATTRWRITER kATTRACCESSOR tOPERATOR tQUOTEDMETHOD tQUOTEDIDENT
|
11
11
|
kPREPEND kEXTENSION kINCOMPATIBLE
|
12
12
|
type_TYPE type_SIGNATURE type_METHODTYPE tEOF
|
@@ -425,7 +425,12 @@ rule
|
|
425
425
|
comment: leading_comment(val[0].first&.location || location))
|
426
426
|
}
|
427
427
|
|
428
|
-
overload:
|
428
|
+
overload:
|
429
|
+
{ result = nil }
|
430
|
+
| kOVERLOAD {
|
431
|
+
RBS.logger.warn "`overload def` syntax is deprecated. Use `...` syntax instead."
|
432
|
+
result = val[0]
|
433
|
+
}
|
429
434
|
|
430
435
|
method_member:
|
431
436
|
annotations attributes overload kDEF method_kind def_name method_types {
|
@@ -438,22 +443,29 @@ rule
|
|
438
443
|
type
|
439
444
|
end
|
440
445
|
end
|
446
|
+
|
447
|
+
last_type = val[6].last
|
448
|
+
if last_type.is_a?(LocatedValue) && last_type.value == :dot3
|
449
|
+
overload = true
|
450
|
+
val[6].pop
|
451
|
+
else
|
452
|
+
overload = false
|
453
|
+
end
|
454
|
+
|
441
455
|
result = Members::MethodDefinition.new(
|
442
456
|
name: val[5].value,
|
443
457
|
kind: val[4],
|
444
|
-
types:
|
458
|
+
types: val[6],
|
445
459
|
annotations: val[0],
|
446
460
|
location: location,
|
447
|
-
comment: leading_comment(val[0].first&.location || val[
|
448
|
-
|
449
|
-
overload: !!val[2]
|
461
|
+
comment: leading_comment(val[0].first&.location || val[2]&.location || val[3].location),
|
462
|
+
overload: overload || !!val[2]
|
450
463
|
)
|
451
464
|
}
|
452
465
|
|
453
466
|
attributes:
|
454
|
-
{ result = [] }
|
455
467
|
| attributes kINCOMPATIBLE {
|
456
|
-
|
468
|
+
RBS.logger.warn "`incompatible` method attribute is deprecated and ignored."
|
457
469
|
}
|
458
470
|
|
459
471
|
method_kind:
|
@@ -463,7 +475,7 @@ rule
|
|
463
475
|
|
464
476
|
method_types:
|
465
477
|
method_type { result = [val[0]] }
|
466
|
-
|
|
478
|
+
| kDOT3 { result = [LocatedValue.new(value: :dot3, location: val[0].location)] }
|
467
479
|
| method_type kBAR method_types {
|
468
480
|
result = val[2].unshift(val[0])
|
469
481
|
}
|
@@ -548,7 +560,7 @@ rule
|
|
548
560
|
kCLASS | kVOID | kNIL | kTRUE | kFALSE | kANY | kUNTYPED | kTOP | kBOT | kINSTANCE | kBOOL | kSINGLETON
|
549
561
|
| kTYPE | kMODULE | kPRIVATE | kPUBLIC | kEND | kINCLUDE | kEXTEND | kPREPEND
|
550
562
|
| kATTRREADER | kATTRACCESSOR | kATTRWRITER | kDEF | kEXTENSION | kSELF | kINCOMPATIBLE
|
551
|
-
| kUNCHECKED | kINTERFACE |
|
563
|
+
| kUNCHECKED | kINTERFACE | kALIAS | kOUT | kIN | kOVERLOAD
|
552
564
|
|
553
565
|
module_type_params:
|
554
566
|
{ result = nil }
|
@@ -1150,15 +1162,13 @@ def leading_comment(location)
|
|
1150
1162
|
end
|
1151
1163
|
|
1152
1164
|
def push_comment(string, location)
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
new_comment = AST::Comment.new(string:
|
1158
|
-
|
1165
|
+
if (comment = leading_comment(location)) && comment.location.start_column == location.start_column
|
1166
|
+
comment.concat(string: "#{string}\n", location: location)
|
1167
|
+
@comments[comment.location.end_line] = comment
|
1168
|
+
else
|
1169
|
+
new_comment = AST::Comment.new(string: "#{string}\n", location: location)
|
1170
|
+
@comments[new_comment.location.end_line] = new_comment
|
1159
1171
|
end
|
1160
|
-
|
1161
|
-
@comments[new_comment.location.end_line] = new_comment
|
1162
1172
|
end
|
1163
1173
|
|
1164
1174
|
def new_token(type, value = input.matched)
|
@@ -1218,7 +1228,6 @@ KEYWORDS = {
|
|
1218
1228
|
"attr_reader" => :kATTRREADER,
|
1219
1229
|
"attr_writer" => :kATTRWRITER,
|
1220
1230
|
"attr_accessor" => :kATTRACCESSOR,
|
1221
|
-
"super" => :kSUPER,
|
1222
1231
|
"public" => :kPUBLIC,
|
1223
1232
|
"private" => :kPRIVATE,
|
1224
1233
|
"alias" => :kALIAS,
|
@@ -1267,6 +1276,7 @@ PUNCTS = {
|
|
1267
1276
|
"!" => :kEXCLAMATION,
|
1268
1277
|
"**" => :kSTAR2,
|
1269
1278
|
"*" => :kSTAR,
|
1279
|
+
"..." => :kDOT3,
|
1270
1280
|
"." => :kDOT,
|
1271
1281
|
"<" => :kLT,
|
1272
1282
|
"-@" => :tOPERATOR,
|
data/lib/rbs/prototype/rb.rb
CHANGED
data/lib/rbs/prototype/rbi.rb
CHANGED
@@ -173,7 +173,6 @@ module RBS
|
|
173
173
|
types: types,
|
174
174
|
kind: :singleton,
|
175
175
|
comment: comment,
|
176
|
-
attributes: [],
|
177
176
|
overload: false
|
178
177
|
)
|
179
178
|
end
|
@@ -194,7 +193,6 @@ module RBS
|
|
194
193
|
types: types,
|
195
194
|
kind: :instance,
|
196
195
|
comment: comment,
|
197
|
-
attributes: [],
|
198
196
|
overload: false
|
199
197
|
)
|
200
198
|
end
|
@@ -154,7 +154,6 @@ module RBS
|
|
154
154
|
location: nil,
|
155
155
|
comment: method.comments[0],
|
156
156
|
annotations: method.annotations,
|
157
|
-
attributes: method.attributes,
|
158
157
|
overload: false
|
159
158
|
)
|
160
159
|
return
|
@@ -193,7 +192,6 @@ module RBS
|
|
193
192
|
location: nil,
|
194
193
|
comment: nil,
|
195
194
|
annotations: [],
|
196
|
-
attributes: [],
|
197
195
|
overload: false
|
198
196
|
)
|
199
197
|
end
|
@@ -227,7 +225,6 @@ module RBS
|
|
227
225
|
location: nil,
|
228
226
|
comment: nil,
|
229
227
|
annotations: [],
|
230
|
-
attributes: [],
|
231
228
|
overload: false
|
232
229
|
)
|
233
230
|
end
|
@@ -262,7 +259,6 @@ module RBS
|
|
262
259
|
location: nil,
|
263
260
|
comment: nil,
|
264
261
|
annotations: [],
|
265
|
-
attributes: [],
|
266
262
|
overload: false
|
267
263
|
)
|
268
264
|
end
|
data/lib/rbs/test.rb
CHANGED
data/lib/rbs/test/errors.rb
CHANGED
@@ -28,7 +28,11 @@ module RBS
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def self.inspect_(obj)
|
31
|
-
|
31
|
+
if obj.respond_to?(:inspect)
|
32
|
+
obj.inspect
|
33
|
+
else
|
34
|
+
Test::INSPECT.bind(obj).call # For the case inspect is not defined (like BasicObject)
|
35
|
+
end
|
32
36
|
end
|
33
37
|
|
34
38
|
def self.to_string(error)
|
data/lib/rbs/test/hook.rb
CHANGED
data/lib/rbs/test/setup.rb
CHANGED
@@ -1,24 +1,34 @@
|
|
1
1
|
require "rbs"
|
2
2
|
require "rbs/test"
|
3
|
-
|
4
3
|
require "optparse"
|
5
4
|
require "shellwords"
|
6
5
|
|
6
|
+
include RBS::Test::SetupHelper
|
7
|
+
|
7
8
|
logger = Logger.new(STDERR)
|
8
9
|
|
9
10
|
begin
|
10
11
|
opts = Shellwords.shellsplit(ENV["RBS_TEST_OPT"] || "-I sig")
|
11
|
-
filter = ENV.fetch(
|
12
|
-
skips = (ENV[
|
13
|
-
sampling = !ENV.key?("RBS_TEST_NO_SAMPLE")
|
12
|
+
filter = ENV.fetch('RBS_TEST_TARGET', "").split(',').map! { |e| e.strip }
|
13
|
+
skips = (ENV['RBS_TEST_SKIP'] || '').split(',').map! { |e| e.strip }
|
14
14
|
RBS.logger_level = (ENV["RBS_TEST_LOGLEVEL"] || "info")
|
15
|
-
|
15
|
+
sample_size = get_sample_size(ENV['RBS_TEST_SAMPLE_SIZE'] || '')
|
16
|
+
double_class = to_double_class(ENV['RBS_TEST_DOUBLE_SUITE'])
|
17
|
+
unchecked_classes = (ENV['RBS_TEST_UNCHECKED_CLASSES'] || '').split(',').map! { |unchecked_class| unchecked_class.strip }.push(*double_class)
|
18
|
+
rescue InvalidSampleSizeError => exception
|
19
|
+
RBS.logger.error exception.message
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
|
23
|
+
if filter.empty?
|
16
24
|
STDERR.puts "rbs/test/setup handles the following environment variables:"
|
17
25
|
STDERR.puts " [REQUIRED] RBS_TEST_TARGET: test target class name, `Foo::Bar,Foo::Baz` for each class or `Foo::*` for all classes under `Foo`"
|
18
26
|
STDERR.puts " [OPTIONAL] RBS_TEST_SKIP: skip testing classes"
|
19
27
|
STDERR.puts " [OPTIONAL] RBS_TEST_OPT: options for signatures (`-r` for libraries or `-I` for signatures)"
|
20
28
|
STDERR.puts " [OPTIONAL] RBS_TEST_LOGLEVEL: one of debug|info|warn|error|fatal (defaults to info)"
|
21
|
-
STDERR.puts " [OPTIONAL]
|
29
|
+
STDERR.puts " [OPTIONAL] RBS_TEST_SAMPLE_SIZE: sets the amount of values in a collection to be type-checked (Set to `ALL` to type check all the values)"
|
30
|
+
STDERR.puts " [OPTIONAL] RBS_TEST_DOUBLE_SUITE: sets the double suite in use (currently supported: minitest | rspec)"
|
31
|
+
STDERR.puts " [OPTIONAL] RBS_TEST_UNCHECKED_CLASSES: sets the classes that would not be checked"
|
22
32
|
exit 1
|
23
33
|
end
|
24
34
|
|
@@ -32,26 +42,38 @@ env = RBS::Environment.from_loader(loader).resolve_type_names
|
|
32
42
|
|
33
43
|
def match(filter, name)
|
34
44
|
if filter.end_with?("*")
|
35
|
-
|
45
|
+
size = filter.size
|
46
|
+
name.start_with?(filter[0, size - 1]) || name == filter[0, size-3]
|
36
47
|
else
|
37
48
|
filter == name
|
38
49
|
end
|
39
50
|
end
|
40
51
|
|
41
|
-
|
52
|
+
def to_absolute_typename(type_name)
|
53
|
+
RBS::Factory.new().type_name(type_name).absolute!
|
54
|
+
end
|
55
|
+
|
42
56
|
tester = RBS::Test::Tester.new(env: env)
|
43
57
|
|
58
|
+
module_name = Module.instance_method(:name)
|
59
|
+
|
44
60
|
TracePoint.trace :end do |tp|
|
45
|
-
class_name = tp.self.
|
61
|
+
class_name = module_name.bind(tp.self).call&.yield_self {|name| to_absolute_typename name }
|
46
62
|
|
47
63
|
if class_name
|
48
|
-
if filter.any? {|f| match(f, class_name.to_s) } && skips.none? {|f| match(f, class_name.to_s) }
|
49
|
-
if
|
50
|
-
|
51
|
-
|
52
|
-
tester.install!(tp.self, sampling: sampling)
|
53
|
-
end
|
64
|
+
if filter.any? {|f| match(to_absolute_typename(f).to_s, class_name.to_s) } && skips.none? {|f| match(f, class_name.to_s) }
|
65
|
+
if env.class_decls.key?(class_name)
|
66
|
+
logger.info "Setting up hooks for #{class_name}"
|
67
|
+
tester.install!(tp.self, sample_size: sample_size, unchecked_classes: unchecked_classes)
|
54
68
|
end
|
55
69
|
end
|
56
70
|
end
|
57
71
|
end
|
72
|
+
|
73
|
+
at_exit do
|
74
|
+
if $!.nil? || $!.is_a?(SystemExit) && $!.success?
|
75
|
+
if tester.targets.empty?
|
76
|
+
logger.debug { "No type checker was installed!" }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module RBS
|
2
|
+
module Test
|
3
|
+
module SetupHelper
|
4
|
+
class InvalidSampleSizeError < StandardError
|
5
|
+
attr_reader :string
|
6
|
+
|
7
|
+
def initialize(string)
|
8
|
+
@string = string
|
9
|
+
super("Sample size should be a positive integer: `#{string}`")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
DEFAULT_SAMPLE_SIZE = 100
|
14
|
+
|
15
|
+
def get_sample_size(string)
|
16
|
+
case string
|
17
|
+
when ""
|
18
|
+
DEFAULT_SAMPLE_SIZE
|
19
|
+
when 'ALL'
|
20
|
+
nil
|
21
|
+
else
|
22
|
+
int_size = string.to_i
|
23
|
+
raise InvalidSampleSizeError.new(string) unless int_size.positive?
|
24
|
+
int_size
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_double_class(double_suite)
|
29
|
+
return nil unless double_suite
|
30
|
+
|
31
|
+
case double_suite.downcase.strip
|
32
|
+
when 'rspec'
|
33
|
+
['::RSpec::Mocks::Double']
|
34
|
+
when 'minitest'
|
35
|
+
['::Minitest::Mock']
|
36
|
+
else
|
37
|
+
RBS.logger.warn "Unknown test suite - defaults to nil"
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|