rbs 0.3.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +7 -1
  3. data/.gitignore +1 -1
  4. data/CHANGELOG.md +39 -0
  5. data/COPYING +1 -1
  6. data/Gemfile +16 -2
  7. data/README.md +87 -48
  8. data/Rakefile +54 -22
  9. data/bin/rbs-prof +9 -0
  10. data/bin/run_in_md.rb +49 -0
  11. data/bin/test_runner.rb +0 -2
  12. data/docs/sigs.md +6 -6
  13. data/docs/stdlib.md +3 -5
  14. data/docs/syntax.md +6 -3
  15. data/goodcheck.yml +65 -0
  16. data/lib/rbs.rb +3 -0
  17. data/lib/rbs/ast/declarations.rb +115 -14
  18. data/lib/rbs/ast/members.rb +41 -17
  19. data/lib/rbs/cli.rb +315 -122
  20. data/lib/rbs/constant.rb +4 -4
  21. data/lib/rbs/constant_table.rb +51 -45
  22. data/lib/rbs/definition.rb +175 -59
  23. data/lib/rbs/definition_builder.rb +802 -604
  24. data/lib/rbs/environment.rb +352 -210
  25. data/lib/rbs/environment_walker.rb +14 -23
  26. data/lib/rbs/errors.rb +184 -3
  27. data/lib/rbs/factory.rb +14 -0
  28. data/lib/rbs/parser.y +95 -27
  29. data/lib/rbs/prototype/rb.rb +119 -117
  30. data/lib/rbs/prototype/rbi.rb +5 -3
  31. data/lib/rbs/prototype/runtime.rb +34 -7
  32. data/lib/rbs/substitution.rb +12 -1
  33. data/lib/rbs/test.rb +82 -3
  34. data/lib/rbs/test/errors.rb +5 -1
  35. data/lib/rbs/test/hook.rb +133 -259
  36. data/lib/rbs/test/observer.rb +17 -0
  37. data/lib/rbs/test/setup.rb +35 -19
  38. data/lib/rbs/test/setup_helper.rb +29 -0
  39. data/lib/rbs/test/spy.rb +0 -321
  40. data/lib/rbs/test/tester.rb +116 -0
  41. data/lib/rbs/test/type_check.rb +43 -7
  42. data/lib/rbs/type_name_resolver.rb +58 -0
  43. data/lib/rbs/types.rb +94 -2
  44. data/lib/rbs/validator.rb +51 -0
  45. data/lib/rbs/variance_calculator.rb +12 -2
  46. data/lib/rbs/version.rb +1 -1
  47. data/lib/rbs/writer.rb +127 -91
  48. data/rbs.gemspec +0 -9
  49. data/schema/annotation.json +14 -0
  50. data/schema/comment.json +26 -0
  51. data/schema/decls.json +353 -0
  52. data/schema/function.json +87 -0
  53. data/schema/location.json +56 -0
  54. data/schema/members.json +248 -0
  55. data/schema/methodType.json +44 -0
  56. data/schema/types.json +299 -0
  57. data/stdlib/benchmark/benchmark.rbs +151 -151
  58. data/stdlib/builtin/encoding.rbs +2 -0
  59. data/stdlib/builtin/enumerable.rbs +4 -4
  60. data/stdlib/builtin/enumerator.rbs +3 -1
  61. data/stdlib/builtin/fiber.rbs +5 -1
  62. data/stdlib/builtin/file.rbs +0 -3
  63. data/stdlib/builtin/io.rbs +4 -4
  64. data/stdlib/builtin/proc.rbs +1 -2
  65. data/stdlib/builtin/symbol.rbs +1 -1
  66. data/stdlib/builtin/thread.rbs +2 -2
  67. data/stdlib/csv/csv.rbs +4 -6
  68. data/stdlib/fiber/fiber.rbs +117 -0
  69. data/stdlib/json/json.rbs +1 -1
  70. data/stdlib/logger/formatter.rbs +23 -0
  71. data/stdlib/logger/log_device.rbs +39 -0
  72. data/stdlib/logger/logger.rbs +507 -0
  73. data/stdlib/logger/period.rbs +7 -0
  74. data/stdlib/logger/severity.rbs +8 -0
  75. data/stdlib/mutex_m/mutex_m.rbs +77 -0
  76. data/stdlib/pathname/pathname.rbs +6 -6
  77. data/stdlib/prime/integer-extension.rbs +1 -1
  78. data/stdlib/prime/prime.rbs +44 -44
  79. data/stdlib/pty/pty.rbs +159 -0
  80. data/stdlib/tmpdir/tmpdir.rbs +1 -1
  81. metadata +28 -116
  82. data/lib/rbs/test/test_helper.rb +0 -183
@@ -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,33 +55,44 @@ 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
 
66
66
  opts
67
67
  end
68
68
 
69
+ def has_parser?
70
+ defined?(RubyVM::AbstractSyntaxTree)
71
+ end
72
+
69
73
  def run(args)
70
74
  options = LibraryOptions.new
71
75
 
72
76
  opts = OptionParser.new
73
77
  opts.banner = <<~USAGE
74
- Usage: rbs [options] COMMAND
75
- Available commands: #{COMMANDS.join(", ")}
78
+ Usage: rbs [options...] [command...]
79
+
80
+ Available commands: #{COMMANDS.join(", ")}, version, help.
81
+
82
+ Options:
76
83
  USAGE
77
84
  library_parse(opts, options: options)
78
85
  parse_logging_options(opts)
86
+ opts.version = RBS::VERSION
79
87
 
80
88
  opts.order!(args)
81
89
 
82
90
  command = args.shift&.to_sym
83
91
 
84
- if COMMANDS.include?(command)
92
+ case command
93
+ when :version
94
+ stdout.puts opts.ver
95
+ when *COMMANDS
85
96
  __send__ :"run_#{command}", args, options
86
97
  else
87
98
  stdout.puts opts.help
@@ -89,101 +100,151 @@ module RBS
89
100
  end
90
101
 
91
102
  def run_ast(args, options)
92
- loader = EnvironmentLoader.new()
103
+ OptionParser.new do |opts|
104
+ opts.banner = <<EOB
105
+ Usage: rbs ast [patterns...]
106
+
107
+ Print JSON AST of loaded environment.
108
+ You can specify patterns to filter declarations with the file names.
109
+
110
+ Examples:
93
111
 
112
+ $ rbs ast
113
+ $ rbs ast 'basic_object.rbs'
114
+ $ rbs -I ./sig ast ./sig
115
+ $ rbs -I ./sig ast '*/models/*.rbs'
116
+ EOB
117
+ end.order!(args)
118
+
119
+ patterns = args.map do |arg|
120
+ path = Pathname(arg)
121
+ if path.exist?
122
+ # Pathname means a directory or a file
123
+ path
124
+ else
125
+ # String means a `fnmatch` pattern
126
+ arg
127
+ end
128
+ end
129
+
130
+ loader = EnvironmentLoader.new()
94
131
  options.setup(loader)
95
132
 
96
- env = Environment.new()
97
- loader.load(env: env)
133
+ env = Environment.from_loader(loader).resolve_type_names
98
134
 
99
- stdout.print JSON.generate(env.declarations)
135
+ decls = env.declarations.select do |decl|
136
+ name = decl.location.buffer.name
137
+
138
+ patterns.empty? || patterns.any? do |pat|
139
+ case pat
140
+ when Pathname
141
+ Pathname(name).ascend.any? {|p| p == pat }
142
+ when String
143
+ name.end_with?(pat) || File.fnmatch(pat, name, File::FNM_EXTGLOB)
144
+ end
145
+ end
146
+ end
147
+
148
+ stdout.print JSON.generate(decls)
100
149
  stdout.flush
101
150
  end
102
151
 
103
152
  def run_list(args, options)
104
- list = []
153
+ list = Set[]
105
154
 
106
155
  OptionParser.new do |opts|
107
- opts.on("--class") { list << :class }
108
- opts.on("--module") { list << :module }
109
- opts.on("--interface") { list << :interface }
156
+ opts.banner = <<EOB
157
+ Usage: rbs list [options...]
158
+
159
+ List classes, modules, and interfaces.
160
+
161
+ Examples:
162
+
163
+ $ rbs list
164
+ $ rbs list --class --module --interface
165
+
166
+ Options:
167
+ EOB
168
+ opts.on("--class", "List classes") { list << :class }
169
+ opts.on("--module", "List modules") { list << :module }
170
+ opts.on("--interface", "List interfaces") { list << :interface }
110
171
  end.order!(args)
111
172
 
112
- list.push(:class, :module, :interface) if list.empty?
173
+ list.merge([:class, :module, :interface]) if list.empty?
113
174
 
114
175
  loader = EnvironmentLoader.new()
115
-
116
176
  options.setup(loader)
117
177
 
118
- env = Environment.new()
119
- loader.load(env: env)
178
+ env = Environment.from_loader(loader).resolve_type_names
120
179
 
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)"
180
+ if list.include?(:class) || list.include?(:module)
181
+ env.class_decls.each do |name, entry|
182
+ case entry
183
+ when Environment::ModuleEntry
184
+ if list.include?(:module)
185
+ stdout.puts "#{name} (module)"
186
+ end
187
+ when Environment::ClassEntry
188
+ if list.include?(:class)
189
+ stdout.puts "#{name} (class)"
190
+ end
134
191
  end
135
192
  end
136
193
  end
194
+
195
+ if list.include?(:interface)
196
+ env.interface_decls.each do |name, entry|
197
+ stdout.puts "#{name} (interface)"
198
+ end
199
+ end
137
200
  end
138
201
 
139
202
  def run_ancestors(args, options)
140
203
  kind = :instance
141
204
 
142
205
  OptionParser.new do |opts|
143
- opts.on("--instance") { kind = :instance }
144
- opts.on("--singleton") { kind = :singleton }
206
+ opts.banner = <<EOU
207
+ Usage: rbs ancestors [options...] [type_name]
208
+
209
+ Show ancestors of the given class or module.
210
+
211
+ Examples:
212
+
213
+ $ rbs ancestors --instance String
214
+ $ rbs ancestors --singleton Array
215
+
216
+ Options:
217
+ EOU
218
+ opts.on("--instance", "Ancestors of instance of the given type_name (default)") { kind = :instance }
219
+ opts.on("--singleton", "Ancestors of singleton of the given type_name") { kind = :singleton }
145
220
  end.order!(args)
146
221
 
147
222
  loader = EnvironmentLoader.new()
148
-
149
223
  options.setup(loader)
150
224
 
151
- env = Environment.new()
152
- loader.load(env: env)
225
+ env = Environment.from_loader(loader).resolve_type_names
153
226
 
154
227
  builder = DefinitionBuilder.new(env: env)
155
228
  type_name = parse_type_name(args[0]).absolute!
156
229
 
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
230
+ if env.class_decls.key?(type_name)
231
+ ancestors = case kind
232
+ when :instance
233
+ builder.instance_ancestors(type_name)
234
+ when :singleton
235
+ builder.singleton_ancestors(type_name)
236
+ end
166
237
 
167
- ancestors = builder.build_ancestors(ancestor)
168
-
169
- ancestors.each do |ancestor|
238
+ ancestors.ancestors.each do |ancestor|
170
239
  case ancestor
171
240
  when Definition::Ancestor::Singleton
172
241
  stdout.puts "singleton(#{ancestor.name})"
173
- when Definition::Ancestor::ExtensionSingleton
174
- stdout.puts "singleton(#{ancestor.name} (#{ancestor.extension_name}))"
175
242
  when Definition::Ancestor::Instance
176
243
  if ancestor.args.empty?
177
244
  stdout.puts ancestor.name.to_s
178
245
  else
179
246
  stdout.puts "#{ancestor.name}[#{ancestor.args.join(", ")}]"
180
247
  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
248
  end
188
249
  end
189
250
  else
@@ -196,10 +257,21 @@ module RBS
196
257
  inherit = true
197
258
 
198
259
  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 }
260
+ opts.banner = <<EOU
261
+ Usage: rbs methods [options...] [type_name]
262
+
263
+ Show methods defined in the class or module.
264
+
265
+ Examples:
266
+
267
+ $ rbs methods --instance Kernel
268
+ $ rbs methods --singleton --no-inherit String
269
+
270
+ Options:
271
+ EOU
272
+ opts.on("--instance", "Show instance methods (default)") { kind = :instance }
273
+ opts.on("--singleton", "Show singleton methods") { kind = :singleton }
274
+ opts.on("--[no-]inherit", "Show methods defined in super class and mixed modules too") {|v| inherit = v }
203
275
  end.order!(args)
204
276
 
205
277
  unless args.size == 1
@@ -208,16 +280,14 @@ module RBS
208
280
  end
209
281
 
210
282
  loader = EnvironmentLoader.new()
211
-
212
283
  options.setup(loader)
213
284
 
214
- env = Environment.new()
215
- loader.load(env: env)
285
+ env = Environment.from_loader(loader).resolve_type_names
216
286
 
217
287
  builder = DefinitionBuilder.new(env: env)
218
288
  type_name = parse_type_name(args[0]).absolute!
219
289
 
220
- if env.class?(type_name)
290
+ if env.class_decls.key?(type_name)
221
291
  definition = case kind
222
292
  when :instance
223
293
  builder.build_instance(type_name)
@@ -227,7 +297,7 @@ module RBS
227
297
 
228
298
  definition.methods.keys.sort.each do |name|
229
299
  method = definition.methods[name]
230
- if inherit || method.implemented_in == definition.declaration
300
+ if inherit || method.implemented_in == type_name
231
301
  stdout.puts "#{name} (#{method.accessibility})"
232
302
  end
233
303
  end
@@ -240,8 +310,20 @@ module RBS
240
310
  kind = :instance
241
311
 
242
312
  OptionParser.new do |opts|
243
- opts.on("--instance") { kind = :instance }
244
- opts.on("--singleton") { kind = :singleton }
313
+ opts.banner = <<EOU
314
+ Usage: rbs method [options...] [type_name] [method_name]
315
+
316
+ Show the information of the method specified by type_name and method_name.
317
+
318
+ Examples:
319
+
320
+ $ rbs method --instance Kernel puts
321
+ $ rbs method --singleton String try_convert
322
+
323
+ Options:
324
+ EOU
325
+ opts.on("--instance", "Show an instance method (default)") { kind = :instance }
326
+ opts.on("--singleton", "Show a singleton method") { kind = :singleton }
245
327
  end.order!(args)
246
328
 
247
329
  unless args.size == 2
@@ -250,17 +332,15 @@ module RBS
250
332
  end
251
333
 
252
334
  loader = EnvironmentLoader.new()
253
-
254
335
  options.setup(loader)
255
336
 
256
- env = Environment.new()
257
- loader.load(env: env)
337
+ env = Environment.from_loader(loader).resolve_type_names
258
338
 
259
339
  builder = DefinitionBuilder.new(env: env)
260
340
  type_name = parse_type_name(args[0]).absolute!
261
341
  method_name = args[1].to_sym
262
342
 
263
- unless env.class?(type_name)
343
+ unless env.class_decls.key?(type_name)
264
344
  stdout.puts "Cannot find class: #{type_name}"
265
345
  return
266
346
  end
@@ -280,8 +360,8 @@ module RBS
280
360
  end
281
361
 
282
362
  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!}"
363
+ stdout.puts " defined_in: #{method.defined_in}"
364
+ stdout.puts " implementation: #{method.implemented_in}"
285
365
  stdout.puts " accessibility: #{method.accessibility}"
286
366
  stdout.puts " types:"
287
367
  separator = " "
@@ -292,46 +372,57 @@ module RBS
292
372
  end
293
373
 
294
374
  def run_validate(args, options)
375
+ OptionParser.new do |opts|
376
+ opts.banner = <<EOU
377
+ Usage: rbs validate
378
+
379
+ Validate RBS files. It ensures the type names in RBS files are present and the type applications have correct arity.
380
+
381
+ Examples:
382
+
383
+ $ rbs validate
384
+ EOU
385
+ end.parse!(args)
386
+
295
387
  loader = EnvironmentLoader.new()
296
388
 
297
389
  options.setup(loader)
298
390
 
299
- env = Environment.new()
300
- loader.load(env: env)
391
+ env = Environment.from_loader(loader).resolve_type_names
301
392
 
302
393
  builder = DefinitionBuilder.new(env: env)
394
+ validator = Validator.new(env: env, resolver: TypeNameResolver.from_env(env))
303
395
 
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
396
+ env.class_decls.each_key do |name|
397
+ stdout.puts "Validating class/module definition: `#{name}`..."
398
+ builder.build_instance(name).each_type do |type|
399
+ validator.validate_type type, context: [Namespace.root]
400
+ end
401
+ builder.build_singleton(name).each_type do |type|
402
+ validator.validate_type type, context: [Namespace.root]
319
403
  end
320
404
  end
321
405
 
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
406
+ env.interface_decls.each_key do |name|
407
+ stdout.puts "Validating interface: `#{name}`..."
408
+ builder.build_interface(name).each_type do |type|
409
+ validator.validate_type type, context: [Namespace.root]
410
+ end
325
411
  end
326
412
 
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
413
+ env.constant_decls.each do |name, const|
414
+ stdout.puts "Validating constant: `#{name}`..."
415
+ validator.validate_type const.decl.type, context: const.context
330
416
  end
331
417
 
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
418
+ env.global_decls.each do |name, global|
419
+ stdout.puts "Validating global: `#{name}`..."
420
+ validator.validate_type global.decl.type, context: [Namespace.root]
421
+ end
422
+
423
+ env.alias_decls.each do |name, decl|
424
+ stdout.puts "Validating alias: `#{name}`..."
425
+ validator.validate_type decl.decl.type, context: decl.context
335
426
  end
336
427
  end
337
428
 
@@ -339,7 +430,20 @@ module RBS
339
430
  context = nil
340
431
 
341
432
  OptionParser.new do |opts|
342
- opts.on("--context CONTEXT") {|c| context = c }
433
+ opts.banner = <<EOU
434
+ Usage: rbs constant [options...] [name]
435
+
436
+ Resolve constant based on RBS.
437
+
438
+ Examples:
439
+
440
+ $ rbs constant ::Object
441
+ $ rbs constant UTF_8
442
+ $ rbs constant --context=::Encoding UTF_8
443
+
444
+ Options:
445
+ EOU
446
+ opts.on("--context CONTEXT", "Name of the module where the constant resolution starts") {|c| context = c }
343
447
  end.order!(args)
344
448
 
345
449
  unless args.size == 1
@@ -351,8 +455,7 @@ module RBS
351
455
 
352
456
  options.setup(loader)
353
457
 
354
- env = Environment.new()
355
- loader.load(env: env)
458
+ env = Environment.from_loader(loader).resolve_type_names
356
459
 
357
460
  builder = DefinitionBuilder.new(env: env)
358
461
  table = ConstantTable.new(builder: builder)
@@ -371,11 +474,20 @@ module RBS
371
474
  end
372
475
  end
373
476
 
374
- def run_version(args, options)
375
- stdout.puts "ruby-signature #{VERSION}"
376
- end
377
-
378
477
  def run_paths(args, options)
478
+ OptionParser.new do |opts|
479
+ opts.banner = <<EOU
480
+ Usage: rbs paths
481
+
482
+ Show paths to directories where the RBS files are loaded from.
483
+
484
+ Examples:
485
+
486
+ $ rbs paths
487
+ $ tbs -r set paths
488
+ EOU
489
+ end.parse!(args)
490
+
379
491
  loader = EnvironmentLoader.new()
380
492
 
381
493
  options.setup(loader)
@@ -423,16 +535,30 @@ module RBS
423
535
  owners_included = []
424
536
 
425
537
  OptionParser.new do |opts|
426
- opts.on("--require LIB") do |lib|
538
+ opts.banner = <<EOU
539
+ Usage: rbs prototype runtime [options...] [pattern...]
540
+
541
+ Generate RBS prototype based on runtime introspection.
542
+ It loads Ruby code specified in [options] and generates RBS prototypes for classes matches to [pattern].
543
+
544
+ Examples:
545
+
546
+ $ rbs prototype runtime String
547
+ $ rbs prototype runtime --require set Set
548
+ $ rbs prototype runtime -R lib/rbs RBS::*
549
+
550
+ Options:
551
+ EOU
552
+ opts.on("-r", "--require LIB", "Load library using `require`") do |lib|
427
553
  require_libs << lib
428
554
  end
429
- opts.on("--require-relative LIB") do |lib|
555
+ opts.on("-R", "--require-relative LIB", "Load library using `require_relative`") do |lib|
430
556
  relative_libs << lib
431
557
  end
432
- opts.on("--merge") do
558
+ opts.on("--merge", "Merge generated prototype RBS with existing RBS") do
433
559
  merge = true
434
560
  end
435
- opts.on("--method-owner CLASS") do |klass|
561
+ opts.on("--method-owner CLASS", "Generate method prototypes if the owner of the method is [CLASS]") do |klass|
436
562
  owners_included << klass
437
563
  end
438
564
  end.parse!(args)
@@ -441,28 +567,72 @@ module RBS
441
567
 
442
568
  options.setup(loader)
443
569
 
444
- env = Environment.new()
445
- loader.load(env: env)
570
+ env = Environment.from_loader(loader).resolve_type_names
446
571
 
447
572
  require_libs.each do |lib|
448
573
  require(lib)
449
574
  end
450
575
 
451
576
  relative_libs.each do |lib|
452
- require(lib)
577
+ eval("require_relative(lib)", binding, "rbs")
453
578
  end
454
579
 
455
580
  decls = Prototype::Runtime.new(patterns: args, env: env, merge: merge, owners_included: owners_included).decls
456
581
  else
457
- stdout.puts "Supported formats: rbi, rb, runtime"
582
+ stdout.puts <<EOU
583
+ Usage: rbs prototype [generator...] [args...]
584
+
585
+ Generate prototype of RBS files.
586
+ Supported generators are rb, rbi, runtime.
587
+
588
+ Examples:
589
+
590
+ $ rbs prototype rb foo.rb
591
+ $ rbs prototype rbi foo.rbi
592
+ $ rbs prototype runtime String
593
+ EOU
458
594
  exit 1
459
595
  end
460
596
 
461
- writer = Writer.new(out: stdout)
462
- writer.write decls
597
+ if decls
598
+ writer = Writer.new(out: stdout)
599
+ writer.write decls
600
+ else
601
+ exit 1
602
+ end
463
603
  end
464
604
 
465
605
  def run_prototype_file(format, args)
606
+ availability = unless has_parser?
607
+ "\n** This command does not work on this interpreter (#{RUBY_ENGINE}) **\n"
608
+ end
609
+
610
+ opts = OptionParser.new
611
+ opts.banner = <<EOU
612
+ Usage: rbs prototype #{format} [options...] [files...]
613
+ #{availability}
614
+ Generate RBS prototype from source code.
615
+ It parses specified Ruby code and and generates RBS prototypes.
616
+
617
+ It only works on MRI because it parses Ruby code with `RubyVM::AbstractSyntaxTree`.
618
+
619
+ Examples:
620
+
621
+ $ rbs prototype rb lib/foo.rb
622
+ $ rbs prototype rbi sorbet/rbi/foo.rbi
623
+ EOU
624
+ opts.parse!(args)
625
+
626
+ unless has_parser?
627
+ stdout.puts "Not supported on this interpreter (#{RUBY_ENGINE})."
628
+ exit 1
629
+ end
630
+
631
+ if args.empty?
632
+ stdout.puts opts
633
+ return nil
634
+ end
635
+
466
636
  parser = case format
467
637
  when "rbi"
468
638
  Prototype::RBI.new()
@@ -483,9 +653,19 @@ module RBS
483
653
  vendor_dir = Pathname("vendor/sigs")
484
654
 
485
655
  OptionParser.new do |opts|
486
- opts.banner = <<~EOB
487
- Usage: rbs vendor [options] GEMS...
488
- Vendor signatures in the project directory.
656
+ opts.banner = <<-EOB
657
+ Usage: rbs vendor [options...] [gems...]
658
+
659
+ Vendor signatures in the project directory.
660
+ This command ignores the RBS loading global options, `-r` and `-I`.
661
+
662
+ Examples:
663
+
664
+ $ rbs vendor
665
+ $ rbs vendor --vendor-dir=sig
666
+ $ rbs vendor --no-stdlib
667
+
668
+ Options:
489
669
  EOB
490
670
 
491
671
  opts.on("--[no-]clean", "Clean vendor directory (default: no)") do |v|
@@ -528,6 +708,18 @@ module RBS
528
708
  end
529
709
 
530
710
  def run_parse(args, options)
711
+ OptionParser.new do |opts|
712
+ opts.banner = <<-EOB
713
+ Usage: rbs parse [files...]
714
+
715
+ Parse given RBS files and print syntax errors.
716
+
717
+ Examples:
718
+
719
+ $ rbs parse sig/app/models.rbs sig/app/controllers.rbs
720
+ EOB
721
+ end.parse!(args)
722
+
531
723
  loader = EnvironmentLoader.new()
532
724
 
533
725
  syntax_error = false
@@ -545,6 +737,7 @@ module RBS
545
737
  syntax_error = true
546
738
  end
547
739
  end
740
+
548
741
  exit 1 if syntax_error
549
742
  end
550
743