rbs 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +7 -1
  3. data/.gitignore +1 -1
  4. data/CHANGELOG.md +7 -0
  5. data/Gemfile +12 -0
  6. data/README.md +86 -47
  7. data/Rakefile +54 -21
  8. data/bin/rbs-prof +9 -0
  9. data/bin/run_in_md.rb +49 -0
  10. data/lib/rbs.rb +2 -0
  11. data/lib/rbs/ast/declarations.rb +62 -7
  12. data/lib/rbs/ast/members.rb +41 -17
  13. data/lib/rbs/cli.rb +299 -121
  14. data/lib/rbs/constant.rb +4 -4
  15. data/lib/rbs/constant_table.rb +50 -44
  16. data/lib/rbs/definition.rb +175 -59
  17. data/lib/rbs/definition_builder.rb +647 -603
  18. data/lib/rbs/environment.rb +338 -209
  19. data/lib/rbs/environment_walker.rb +14 -23
  20. data/lib/rbs/errors.rb +141 -3
  21. data/lib/rbs/parser.y +14 -9
  22. data/lib/rbs/prototype/rb.rb +100 -112
  23. data/lib/rbs/prototype/rbi.rb +4 -2
  24. data/lib/rbs/prototype/runtime.rb +10 -6
  25. data/lib/rbs/substitution.rb +8 -1
  26. data/lib/rbs/test/hook.rb +2 -2
  27. data/lib/rbs/test/setup.rb +3 -1
  28. data/lib/rbs/test/test_helper.rb +2 -5
  29. data/lib/rbs/test/type_check.rb +1 -2
  30. data/lib/rbs/type_name_resolver.rb +58 -0
  31. data/lib/rbs/types.rb +94 -2
  32. data/lib/rbs/validator.rb +51 -0
  33. data/lib/rbs/variance_calculator.rb +12 -2
  34. data/lib/rbs/version.rb +1 -1
  35. data/lib/rbs/writer.rb +125 -89
  36. data/rbs.gemspec +0 -10
  37. data/schema/decls.json +15 -0
  38. data/schema/members.json +3 -0
  39. data/stdlib/benchmark/benchmark.rbs +151 -151
  40. data/stdlib/builtin/enumerable.rbs +1 -1
  41. data/stdlib/builtin/file.rbs +0 -3
  42. data/stdlib/builtin/io.rbs +4 -4
  43. data/stdlib/builtin/thread.rbs +2 -2
  44. data/stdlib/csv/csv.rbs +4 -6
  45. data/stdlib/fiber/fiber.rbs +1 -1
  46. data/stdlib/json/json.rbs +1 -1
  47. data/stdlib/mutex_m/mutex_m.rbs +77 -0
  48. data/stdlib/pathname/pathname.rbs +6 -6
  49. data/stdlib/prime/integer-extension.rbs +1 -1
  50. data/stdlib/prime/prime.rbs +44 -44
  51. data/stdlib/tmpdir/tmpdir.rbs +1 -1
  52. metadata +8 -129
@@ -1,7 +1,10 @@
1
1
  module RBS
2
2
  module AST
3
3
  module Members
4
- class MethodDefinition
4
+ class Base
5
+ end
6
+
7
+ class MethodDefinition < Base
5
8
  attr_reader :name
6
9
  attr_reader :kind
7
10
  attr_reader :types
@@ -9,8 +12,9 @@ module RBS
9
12
  attr_reader :location
10
13
  attr_reader :comment
11
14
  attr_reader :attributes
15
+ attr_reader :overload
12
16
 
13
- def initialize(name:, kind:, types:, annotations:, location:, comment:, attributes:)
17
+ def initialize(name:, kind:, types:, annotations:, location:, comment:, attributes:, overload:)
14
18
  @name = name
15
19
  @kind = kind
16
20
  @types = types
@@ -18,6 +22,7 @@ module RBS
18
22
  @location = location
19
23
  @comment = comment
20
24
  @attributes = attributes
25
+ @overload = overload
21
26
  end
22
27
 
23
28
  def ==(other)
@@ -25,13 +30,14 @@ module RBS
25
30
  other.name == name &&
26
31
  other.kind == kind &&
27
32
  other.types == types &&
28
- other.attributes == attributes
33
+ other.attributes == attributes &&
34
+ other.overload == overload
29
35
  end
30
36
 
31
37
  alias eql? ==
32
38
 
33
39
  def hash
34
- self.class.hash ^ name.hash ^ kind.hash ^ types.hash ^ attributes.hash
40
+ self.class.hash ^ name.hash ^ kind.hash ^ types.hash ^ attributes.hash ^ overload.hash
35
41
  end
36
42
 
37
43
  def instance?
@@ -42,6 +48,23 @@ module RBS
42
48
  kind == :singleton || kind == :singleton_instance
43
49
  end
44
50
 
51
+ def overload?
52
+ overload
53
+ end
54
+
55
+ def update(name: self.name, kind: self.kind, types: self.types, annotations: self.annotations, location: self.location, comment: self.comment, attributes: self.attributes, overload: self.overload)
56
+ self.class.new(
57
+ name: name,
58
+ kind: kind,
59
+ types: types,
60
+ annotations: annotations,
61
+ location: location,
62
+ comment: comment,
63
+ attributes: attributes,
64
+ overload: overload
65
+ )
66
+ end
67
+
45
68
  def to_json(*a)
46
69
  {
47
70
  member: :method_definition,
@@ -50,7 +73,8 @@ module RBS
50
73
  annotations: annotations,
51
74
  location: location,
52
75
  comment: comment,
53
- attributes: attributes
76
+ attributes: attributes,
77
+ overload: overload
54
78
  }.to_json(*a)
55
79
  end
56
80
  end
@@ -79,7 +103,7 @@ module RBS
79
103
  end
80
104
  end
81
105
 
82
- class InstanceVariable
106
+ class InstanceVariable < Base
83
107
  include Var
84
108
 
85
109
  def to_json(*a)
@@ -93,7 +117,7 @@ module RBS
93
117
  end
94
118
  end
95
119
 
96
- class ClassInstanceVariable
120
+ class ClassInstanceVariable < Base
97
121
  include Var
98
122
 
99
123
  def to_json(*a)
@@ -107,7 +131,7 @@ module RBS
107
131
  end
108
132
  end
109
133
 
110
- class ClassVariable
134
+ class ClassVariable < Base
111
135
  include Var
112
136
 
113
137
  def to_json(*a)
@@ -149,7 +173,7 @@ module RBS
149
173
  end
150
174
  end
151
175
 
152
- class Include
176
+ class Include < Base
153
177
  include Mixin
154
178
 
155
179
  def to_json(*a)
@@ -164,7 +188,7 @@ module RBS
164
188
  end
165
189
  end
166
190
 
167
- class Extend
191
+ class Extend < Base
168
192
  include Mixin
169
193
 
170
194
  def to_json(*a)
@@ -179,7 +203,7 @@ module RBS
179
203
  end
180
204
  end
181
205
 
182
- class Prepend
206
+ class Prepend < Base
183
207
  include Mixin
184
208
 
185
209
  def to_json(*a)
@@ -225,7 +249,7 @@ module RBS
225
249
  end
226
250
  end
227
251
 
228
- class AttrReader
252
+ class AttrReader < Base
229
253
  include Attribute
230
254
 
231
255
  def to_json(*a)
@@ -241,7 +265,7 @@ module RBS
241
265
  end
242
266
  end
243
267
 
244
- class AttrAccessor
268
+ class AttrAccessor < Base
245
269
  include Attribute
246
270
 
247
271
  def to_json(*a)
@@ -257,7 +281,7 @@ module RBS
257
281
  end
258
282
  end
259
283
 
260
- class AttrWriter
284
+ class AttrWriter < Base
261
285
  include Attribute
262
286
 
263
287
  def to_json(*a)
@@ -291,7 +315,7 @@ module RBS
291
315
  end
292
316
  end
293
317
 
294
- class Public
318
+ class Public < Base
295
319
  include LocationOnly
296
320
 
297
321
  def to_json(*a)
@@ -299,7 +323,7 @@ module RBS
299
323
  end
300
324
  end
301
325
 
302
- class Private
326
+ class Private < Base
303
327
  include LocationOnly
304
328
 
305
329
  def to_json(*a)
@@ -307,7 +331,7 @@ module RBS
307
331
  end
308
332
  end
309
333
 
310
- class Alias
334
+ class Alias < Base
311
335
  attr_reader :new_name
312
336
  attr_reader :old_name
313
337
  attr_reader :kind
@@ -36,18 +36,18 @@ module RBS
36
36
  @stderr = stderr
37
37
  end
38
38
 
39
- COMMANDS = [:ast, :list, :ancestors, :methods, :method, :validate, :constant, :paths, :prototype, :vendor, :version, :parse]
39
+ COMMANDS = [:ast, :list, :ancestors, :methods, :method, :validate, :constant, :paths, :prototype, :vendor, :parse]
40
40
 
41
41
  def library_parse(opts, options:)
42
- opts.on("-r LIBRARY") do |lib|
42
+ opts.on("-r LIBRARY", "Load RBS files of the library") do |lib|
43
43
  options.libs << lib
44
44
  end
45
45
 
46
- opts.on("-I DIR") do |dir|
46
+ opts.on("-I DIR", "Load RBS files from the directory") do |dir|
47
47
  options.dirs << dir
48
48
  end
49
49
 
50
- opts.on("--no-stdlib") do
50
+ opts.on("--no-stdlib", "Skip loading standard library signatures") do
51
51
  options.no_stdlib = true
52
52
  end
53
53
 
@@ -55,11 +55,11 @@ module RBS
55
55
  end
56
56
 
57
57
  def parse_logging_options(opts)
58
- opts.on("--log-level=LEVEL", "Specify log level (defaults to `warn`)") do |level|
58
+ opts.on("--log-level LEVEL", "Specify log level (defaults to `warn`)") do |level|
59
59
  RBS.logger_level = level
60
60
  end
61
61
 
62
- opts.on("--log-output=OUTPUT", "Specify the file to output log (defaults to stderr)") do |output|
62
+ opts.on("--log-output OUTPUT", "Specify the file to output log (defaults to stderr)") do |output|
63
63
  RBS.logger_output = File.open(output, "a")
64
64
  end
65
65
 
@@ -71,17 +71,24 @@ module RBS
71
71
 
72
72
  opts = OptionParser.new
73
73
  opts.banner = <<~USAGE
74
- Usage: rbs [options] COMMAND
75
- Available commands: #{COMMANDS.join(", ")}
74
+ Usage: rbs [options...] [command...]
75
+
76
+ Available commands: #{COMMANDS.join(", ")}, version, help.
77
+
78
+ Options:
76
79
  USAGE
77
80
  library_parse(opts, options: options)
78
81
  parse_logging_options(opts)
82
+ opts.version = RBS::VERSION
79
83
 
80
84
  opts.order!(args)
81
85
 
82
86
  command = args.shift&.to_sym
83
87
 
84
- if COMMANDS.include?(command)
88
+ case command
89
+ when :version
90
+ stdout.puts opts.ver
91
+ when *COMMANDS
85
92
  __send__ :"run_#{command}", args, options
86
93
  else
87
94
  stdout.puts opts.help
@@ -89,101 +96,151 @@ module RBS
89
96
  end
90
97
 
91
98
  def run_ast(args, options)
92
- loader = EnvironmentLoader.new()
99
+ OptionParser.new do |opts|
100
+ opts.banner = <<EOB
101
+ Usage: rbs ast [patterns...]
102
+
103
+ Print JSON AST of loaded environment.
104
+ You can specify patterns to filter declarations with the file names.
105
+
106
+ Examples:
107
+
108
+ $ rbs ast
109
+ $ rbs ast 'basic_object.rbs'
110
+ $ rbs -I ./sig ast ./sig
111
+ $ rbs -I ./sig ast '*/models/*.rbs'
112
+ EOB
113
+ end.order!(args)
93
114
 
115
+ patterns = args.map do |arg|
116
+ path = Pathname(arg)
117
+ if path.exist?
118
+ # Pathname means a directory or a file
119
+ path
120
+ else
121
+ # String means a `fnmatch` pattern
122
+ arg
123
+ end
124
+ end
125
+
126
+ loader = EnvironmentLoader.new()
94
127
  options.setup(loader)
95
128
 
96
- env = Environment.new()
97
- loader.load(env: env)
129
+ env = Environment.from_loader(loader).resolve_type_names
130
+
131
+ decls = env.declarations.select do |decl|
132
+ name = decl.location.buffer.name
98
133
 
99
- stdout.print JSON.generate(env.declarations)
134
+ patterns.empty? || patterns.any? do |pat|
135
+ case pat
136
+ when Pathname
137
+ Pathname(name).ascend.any? {|p| p == pat }
138
+ when String
139
+ name.end_with?(pat) || File.fnmatch(pat, name, File::FNM_EXTGLOB)
140
+ end
141
+ end
142
+ end
143
+
144
+ stdout.print JSON.generate(decls)
100
145
  stdout.flush
101
146
  end
102
147
 
103
148
  def run_list(args, options)
104
- list = []
149
+ list = Set[]
105
150
 
106
151
  OptionParser.new do |opts|
107
- opts.on("--class") { list << :class }
108
- opts.on("--module") { list << :module }
109
- opts.on("--interface") { list << :interface }
152
+ opts.banner = <<EOB
153
+ Usage: rbs list [options...]
154
+
155
+ List classes, modules, and interfaces.
156
+
157
+ Examples:
158
+
159
+ $ rbs list
160
+ $ rbs list --class --module --interface
161
+
162
+ Options:
163
+ EOB
164
+ opts.on("--class", "List classes") { list << :class }
165
+ opts.on("--module", "List modules") { list << :module }
166
+ opts.on("--interface", "List interfaces") { list << :interface }
110
167
  end.order!(args)
111
168
 
112
- list.push(:class, :module, :interface) if list.empty?
169
+ list.merge([:class, :module, :interface]) if list.empty?
113
170
 
114
171
  loader = EnvironmentLoader.new()
115
-
116
172
  options.setup(loader)
117
173
 
118
- env = Environment.new()
119
- loader.load(env: env)
174
+ env = Environment.from_loader(loader).resolve_type_names
120
175
 
121
- env.each_decl.sort_by {|name,| name.to_s }.each do |type_name, decl|
122
- case decl
123
- when AST::Declarations::Class
124
- if list.include?(:class)
125
- stdout.puts "#{type_name} (class)"
126
- end
127
- when AST::Declarations::Module
128
- if list.include?(:module)
129
- stdout.puts "#{type_name} (module)"
130
- end
131
- when AST::Declarations::Interface
132
- if list.include?(:interface)
133
- stdout.puts "#{type_name} (interface)"
176
+ if list.include?(:class) || list.include?(:module)
177
+ env.class_decls.each do |name, entry|
178
+ case entry
179
+ when Environment::ModuleEntry
180
+ if list.include?(:module)
181
+ stdout.puts "#{name} (module)"
182
+ end
183
+ when Environment::ClassEntry
184
+ if list.include?(:class)
185
+ stdout.puts "#{name} (class)"
186
+ end
134
187
  end
135
188
  end
136
189
  end
190
+
191
+ if list.include?(:interface)
192
+ env.interface_decls.each do |name, entry|
193
+ stdout.puts "#{name} (interface)"
194
+ end
195
+ end
137
196
  end
138
197
 
139
198
  def run_ancestors(args, options)
140
199
  kind = :instance
141
200
 
142
201
  OptionParser.new do |opts|
143
- opts.on("--instance") { kind = :instance }
144
- opts.on("--singleton") { kind = :singleton }
202
+ opts.banner = <<EOU
203
+ Usage: rbs ancestors [options...] [type_name]
204
+
205
+ Show ancestors of the given class or module.
206
+
207
+ Examples:
208
+
209
+ $ rbs ancestors --instance String
210
+ $ rbs ancestors --singleton Array
211
+
212
+ Options:
213
+ EOU
214
+ opts.on("--instance", "Ancestors of instance of the given type_name (default)") { kind = :instance }
215
+ opts.on("--singleton", "Ancestors of singleton of the given type_name") { kind = :singleton }
145
216
  end.order!(args)
146
217
 
147
218
  loader = EnvironmentLoader.new()
148
-
149
219
  options.setup(loader)
150
220
 
151
- env = Environment.new()
152
- loader.load(env: env)
221
+ env = Environment.from_loader(loader).resolve_type_names
153
222
 
154
223
  builder = DefinitionBuilder.new(env: env)
155
224
  type_name = parse_type_name(args[0]).absolute!
156
225
 
157
- if env.class?(type_name)
158
- ancestor = case kind
159
- when :instance
160
- decl = env.find_class(type_name)
161
- Definition::Ancestor::Instance.new(name: type_name,
162
- args: Types::Variable.build(decl.type_params.each.map(&:name)))
163
- when :singleton
164
- Definition::Ancestor::Singleton.new(name: type_name)
165
- end
166
-
167
- ancestors = builder.build_ancestors(ancestor)
226
+ if env.class_decls.key?(type_name)
227
+ ancestors = case kind
228
+ when :instance
229
+ builder.instance_ancestors(type_name)
230
+ when :singleton
231
+ builder.singleton_ancestors(type_name)
232
+ end
168
233
 
169
- ancestors.each do |ancestor|
234
+ ancestors.ancestors.each do |ancestor|
170
235
  case ancestor
171
236
  when Definition::Ancestor::Singleton
172
237
  stdout.puts "singleton(#{ancestor.name})"
173
- when Definition::Ancestor::ExtensionSingleton
174
- stdout.puts "singleton(#{ancestor.name} (#{ancestor.extension_name}))"
175
238
  when Definition::Ancestor::Instance
176
239
  if ancestor.args.empty?
177
240
  stdout.puts ancestor.name.to_s
178
241
  else
179
242
  stdout.puts "#{ancestor.name}[#{ancestor.args.join(", ")}]"
180
243
  end
181
- when Definition::Ancestor::ExtensionInstance
182
- if ancestor.args.empty?
183
- stdout.puts "#{ancestor.name} (#{ancestor.extension_name})"
184
- else
185
- stdout.puts "#{ancestor.name}[#{ancestor.args.join(", ")}] (#{ancestor.extension_name})"
186
- end
187
244
  end
188
245
  end
189
246
  else
@@ -196,10 +253,21 @@ module RBS
196
253
  inherit = true
197
254
 
198
255
  OptionParser.new do |opts|
199
- opts.on("--instance") { kind = :instance }
200
- opts.on("--singleton") { kind = :singleton }
201
- opts.on("--inherit") { inherit = true }
202
- opts.on("--no-inherit") { inherit = false }
256
+ opts.banner = <<EOU
257
+ Usage: rbs methods [options...] [type_name]
258
+
259
+ Show methods defined in the class or module.
260
+
261
+ Examples:
262
+
263
+ $ rbs methods --instance Kernel
264
+ $ rbs methods --singleton --no-inherit String
265
+
266
+ Options:
267
+ EOU
268
+ opts.on("--instance", "Show instance methods (default)") { kind = :instance }
269
+ opts.on("--singleton", "Show singleton methods") { kind = :singleton }
270
+ opts.on("--[no-]inherit", "Show methods defined in super class and mixed modules too") {|v| inherit = v }
203
271
  end.order!(args)
204
272
 
205
273
  unless args.size == 1
@@ -208,16 +276,14 @@ module RBS
208
276
  end
209
277
 
210
278
  loader = EnvironmentLoader.new()
211
-
212
279
  options.setup(loader)
213
280
 
214
- env = Environment.new()
215
- loader.load(env: env)
281
+ env = Environment.from_loader(loader).resolve_type_names
216
282
 
217
283
  builder = DefinitionBuilder.new(env: env)
218
284
  type_name = parse_type_name(args[0]).absolute!
219
285
 
220
- if env.class?(type_name)
286
+ if env.class_decls.key?(type_name)
221
287
  definition = case kind
222
288
  when :instance
223
289
  builder.build_instance(type_name)
@@ -227,7 +293,7 @@ module RBS
227
293
 
228
294
  definition.methods.keys.sort.each do |name|
229
295
  method = definition.methods[name]
230
- if inherit || method.implemented_in == definition.declaration
296
+ if inherit || method.implemented_in == type_name
231
297
  stdout.puts "#{name} (#{method.accessibility})"
232
298
  end
233
299
  end
@@ -240,8 +306,20 @@ module RBS
240
306
  kind = :instance
241
307
 
242
308
  OptionParser.new do |opts|
243
- opts.on("--instance") { kind = :instance }
244
- opts.on("--singleton") { kind = :singleton }
309
+ opts.banner = <<EOU
310
+ Usage: rbs method [options...] [type_name] [method_name]
311
+
312
+ Show the information of the method specified by type_name and method_name.
313
+
314
+ Examples:
315
+
316
+ $ rbs method --instance Kernel puts
317
+ $ rbs method --singleton String try_convert
318
+
319
+ Options:
320
+ EOU
321
+ opts.on("--instance", "Show an instance method (default)") { kind = :instance }
322
+ opts.on("--singleton", "Show a singleton method") { kind = :singleton }
245
323
  end.order!(args)
246
324
 
247
325
  unless args.size == 2
@@ -250,17 +328,15 @@ module RBS
250
328
  end
251
329
 
252
330
  loader = EnvironmentLoader.new()
253
-
254
331
  options.setup(loader)
255
332
 
256
- env = Environment.new()
257
- loader.load(env: env)
333
+ env = Environment.from_loader(loader).resolve_type_names
258
334
 
259
335
  builder = DefinitionBuilder.new(env: env)
260
336
  type_name = parse_type_name(args[0]).absolute!
261
337
  method_name = args[1].to_sym
262
338
 
263
- unless env.class?(type_name)
339
+ unless env.class_decls.key?(type_name)
264
340
  stdout.puts "Cannot find class: #{type_name}"
265
341
  return
266
342
  end
@@ -280,8 +356,8 @@ module RBS
280
356
  end
281
357
 
282
358
  stdout.puts "#{type_name}#{kind == :instance ? "#" : "."}#{method_name}"
283
- stdout.puts " defined_in: #{method.defined_in&.name&.absolute!}"
284
- stdout.puts " implementation: #{method.implemented_in.name.absolute!}"
359
+ stdout.puts " defined_in: #{method.defined_in}"
360
+ stdout.puts " implementation: #{method.implemented_in}"
285
361
  stdout.puts " accessibility: #{method.accessibility}"
286
362
  stdout.puts " types:"
287
363
  separator = " "
@@ -292,46 +368,57 @@ module RBS
292
368
  end
293
369
 
294
370
  def run_validate(args, options)
371
+ OptionParser.new do |opts|
372
+ opts.banner = <<EOU
373
+ Usage: rbs validate
374
+
375
+ Validate RBS files. It ensures the type names in RBS files are present and the type applications have correct arity.
376
+
377
+ Examples:
378
+
379
+ $ rbs validate
380
+ EOU
381
+ end.parse!(args)
382
+
295
383
  loader = EnvironmentLoader.new()
296
384
 
297
385
  options.setup(loader)
298
386
 
299
- env = Environment.new()
300
- loader.load(env: env)
387
+ env = Environment.from_loader(loader).resolve_type_names
301
388
 
302
389
  builder = DefinitionBuilder.new(env: env)
390
+ validator = Validator.new(env: env, resolver: TypeNameResolver.from_env(env))
303
391
 
304
- env.each_decl do |name, decl|
305
- case decl
306
- when AST::Declarations::Class, AST::Declarations::Module
307
- stdout.puts "#{Location.to_string decl.location}:\tValidating class/module definition: `#{name}`..."
308
- builder.build_instance(decl.name.absolute!).each_type do |type|
309
- env.validate type, namespace: Namespace.root
310
- end
311
- builder.build_singleton(decl.name.absolute!).each_type do |type|
312
- env.validate type, namespace: Namespace.root
313
- end
314
- when AST::Declarations::Interface
315
- stdout.puts "#{Location.to_string decl.location}:\tValidating interface: `#{name}`..."
316
- builder.build_interface(decl.name.absolute!, decl).each_type do |type|
317
- env.validate type, namespace: Namespace.root
318
- end
392
+ env.class_decls.each_key do |name|
393
+ stdout.puts "Validating class/module definition: `#{name}`..."
394
+ builder.build_instance(name).each_type do |type|
395
+ validator.validate_type type, context: [Namespace.root]
396
+ end
397
+ builder.build_singleton(name).each_type do |type|
398
+ validator.validate_type type, context: [Namespace.root]
319
399
  end
320
400
  end
321
401
 
322
- env.each_constant do |name, const|
323
- stdout.puts "#{Location.to_string const.location}:\tValidating constant: `#{name}`..."
324
- env.validate const.type, namespace: name.namespace
402
+ env.interface_decls.each_key do |name|
403
+ stdout.puts "Validating interface: `#{name}`..."
404
+ builder.build_interface(name).each_type do |type|
405
+ validator.validate_type type, context: [Namespace.root]
406
+ end
325
407
  end
326
408
 
327
- env.each_global do |name, global|
328
- stdout.puts "#{Location.to_string global.location}:\tValidating global: `#{name}`..."
329
- env.validate global.type, namespace: Namespace.root
409
+ env.constant_decls.each do |name, const|
410
+ stdout.puts "Validating constant: `#{name}`..."
411
+ validator.validate_type const.decl.type, context: const.context
330
412
  end
331
413
 
332
- env.each_alias do |name, decl|
333
- stdout.puts "#{Location.to_string decl.location}:\tValidating alias: `#{name}`..."
334
- env.validate decl.type, namespace: name.namespace
414
+ env.global_decls.each do |name, global|
415
+ stdout.puts "Validating global: `#{name}`..."
416
+ validator.validate_type global.decl.type, context: [Namespace.root]
417
+ end
418
+
419
+ env.alias_decls.each do |name, decl|
420
+ stdout.puts "Validating alias: `#{name}`..."
421
+ validator.validate_type decl.decl.type, context: decl.context
335
422
  end
336
423
  end
337
424
 
@@ -339,7 +426,20 @@ module RBS
339
426
  context = nil
340
427
 
341
428
  OptionParser.new do |opts|
342
- opts.on("--context CONTEXT") {|c| context = c }
429
+ opts.banner = <<EOU
430
+ Usage: rbs constant [options...] [name]
431
+
432
+ Resolve constant based on RBS.
433
+
434
+ Examples:
435
+
436
+ $ rbs constant ::Object
437
+ $ rbs constant UTF_8
438
+ $ rbs constant --context=::Encoding UTF_8
439
+
440
+ Options:
441
+ EOU
442
+ opts.on("--context CONTEXT", "Name of the module where the constant resolution starts") {|c| context = c }
343
443
  end.order!(args)
344
444
 
345
445
  unless args.size == 1
@@ -351,8 +451,7 @@ module RBS
351
451
 
352
452
  options.setup(loader)
353
453
 
354
- env = Environment.new()
355
- loader.load(env: env)
454
+ env = Environment.from_loader(loader).resolve_type_names
356
455
 
357
456
  builder = DefinitionBuilder.new(env: env)
358
457
  table = ConstantTable.new(builder: builder)
@@ -371,11 +470,20 @@ module RBS
371
470
  end
372
471
  end
373
472
 
374
- def run_version(args, options)
375
- stdout.puts "rbs #{VERSION}"
376
- end
377
-
378
473
  def run_paths(args, options)
474
+ OptionParser.new do |opts|
475
+ opts.banner = <<EOU
476
+ Usage: rbs paths
477
+
478
+ Show paths to directories where the RBS files are loaded from.
479
+
480
+ Examples:
481
+
482
+ $ rbs paths
483
+ $ tbs -r set paths
484
+ EOU
485
+ end.parse!(args)
486
+
379
487
  loader = EnvironmentLoader.new()
380
488
 
381
489
  options.setup(loader)
@@ -423,16 +531,30 @@ module RBS
423
531
  owners_included = []
424
532
 
425
533
  OptionParser.new do |opts|
426
- opts.on("--require LIB") do |lib|
534
+ opts.banner = <<EOU
535
+ Usage: rbs prototype runtime [options...] [pattern...]
536
+
537
+ Generate RBS prototype based on runtime introspection.
538
+ It loads Ruby code specified in [options] and generates RBS prototypes for classes matches to [pattern].
539
+
540
+ Examples:
541
+
542
+ $ rbs prototype runtime String
543
+ $ rbs prototype runtime --require set Set
544
+ $ rbs prototype runtime -R lib/rbs RBS::*
545
+
546
+ Options:
547
+ EOU
548
+ opts.on("-r", "--require LIB", "Load library using `require`") do |lib|
427
549
  require_libs << lib
428
550
  end
429
- opts.on("--require-relative LIB") do |lib|
551
+ opts.on("-R", "--require-relative LIB", "Load library using `require_relative`") do |lib|
430
552
  relative_libs << lib
431
553
  end
432
- opts.on("--merge") do
554
+ opts.on("--merge", "Merge generated prototype RBS with existing RBS") do
433
555
  merge = true
434
556
  end
435
- opts.on("--method-owner CLASS") do |klass|
557
+ opts.on("--method-owner CLASS", "Generate method prototypes if the owner of the method is [CLASS]") do |klass|
436
558
  owners_included << klass
437
559
  end
438
560
  end.parse!(args)
@@ -441,8 +563,7 @@ module RBS
441
563
 
442
564
  options.setup(loader)
443
565
 
444
- env = Environment.new()
445
- loader.load(env: env)
566
+ env = Environment.from_loader(loader).resolve_type_names
446
567
 
447
568
  require_libs.each do |lib|
448
569
  require(lib)
@@ -454,15 +575,49 @@ module RBS
454
575
 
455
576
  decls = Prototype::Runtime.new(patterns: args, env: env, merge: merge, owners_included: owners_included).decls
456
577
  else
457
- stdout.puts "Supported formats: rbi, rb, runtime"
578
+ stdout.puts <<EOU
579
+ Usage: rbs prototype [generator...] [args...]
580
+
581
+ Generate prototype of RBS files.
582
+ Supported generators are rb, rbi, runtime.
583
+
584
+ Examples:
585
+
586
+ $ rbs prototype rb foo.rb
587
+ $ rbs prototype rbi foo.rbi
588
+ $ rbs prototype runtime String
589
+ EOU
458
590
  exit 1
459
591
  end
460
592
 
461
- writer = Writer.new(out: stdout)
462
- writer.write decls
593
+ if decls
594
+ writer = Writer.new(out: stdout)
595
+ writer.write decls
596
+ else
597
+ exit 1
598
+ end
463
599
  end
464
600
 
465
601
  def run_prototype_file(format, args)
602
+ opts = OptionParser.new
603
+ opts.banner = <<EOU
604
+ Usage: rbs prototype #{format} [options...] [files...]
605
+
606
+ Generate RBS prototype from source code.
607
+ It parses specified Ruby code and and generates RBS prototypes.
608
+
609
+ Examples:
610
+
611
+ $ rbs prototype rb lib/foo.rb
612
+ $ rbs prototype rbi sorbet/rbi/foo.rbi
613
+ EOU
614
+ opts.parse!(args)
615
+
616
+ if args.empty?
617
+ stdout.puts opts
618
+ return nil
619
+ end
620
+
466
621
  parser = case format
467
622
  when "rbi"
468
623
  Prototype::RBI.new()
@@ -483,9 +638,19 @@ module RBS
483
638
  vendor_dir = Pathname("vendor/sigs")
484
639
 
485
640
  OptionParser.new do |opts|
486
- opts.banner = <<~EOB
487
- Usage: rbs vendor [options] GEMS...
488
- Vendor signatures in the project directory.
641
+ opts.banner = <<-EOB
642
+ Usage: rbs vendor [options...] [gems...]
643
+
644
+ Vendor signatures in the project directory.
645
+ This command ignores the RBS loading global options, `-r` and `-I`.
646
+
647
+ Examples:
648
+
649
+ $ rbs vendor
650
+ $ rbs vendor --vendor-dir=sig
651
+ $ rbs vendor --no-stdlib
652
+
653
+ Options:
489
654
  EOB
490
655
 
491
656
  opts.on("--[no-]clean", "Clean vendor directory (default: no)") do |v|
@@ -528,6 +693,18 @@ module RBS
528
693
  end
529
694
 
530
695
  def run_parse(args, options)
696
+ OptionParser.new do |opts|
697
+ opts.banner = <<-EOB
698
+ Usage: rbs parse [files...]
699
+
700
+ Parse given RBS files and print syntax errors.
701
+
702
+ Examples:
703
+
704
+ $ rbs parse sig/app/models.rbs sig/app/controllers.rbs
705
+ EOB
706
+ end.parse!(args)
707
+
531
708
  loader = EnvironmentLoader.new()
532
709
 
533
710
  syntax_error = false
@@ -545,6 +722,7 @@ module RBS
545
722
  syntax_error = true
546
723
  end
547
724
  end
725
+
548
726
  exit 1 if syntax_error
549
727
  end
550
728