rbs 0.2.0 → 0.6.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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +7 -1
  3. data/.gitignore +1 -1
  4. data/CHANGELOG.md +35 -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 +301 -123
  20. data/lib/rbs/constant.rb +4 -4
  21. data/lib/rbs/constant_table.rb +64 -53
  22. data/lib/rbs/definition.rb +175 -59
  23. data/lib/rbs/definition_builder.rb +646 -603
  24. data/lib/rbs/environment.rb +352 -210
  25. data/lib/rbs/environment_walker.rb +14 -23
  26. data/lib/rbs/errors.rb +159 -3
  27. data/lib/rbs/factory.rb +14 -0
  28. data/lib/rbs/namespace.rb +18 -0
  29. data/lib/rbs/parser.y +75 -21
  30. data/lib/rbs/prototype/rb.rb +119 -117
  31. data/lib/rbs/prototype/rbi.rb +5 -3
  32. data/lib/rbs/prototype/runtime.rb +34 -7
  33. data/lib/rbs/substitution.rb +8 -1
  34. data/lib/rbs/test.rb +81 -3
  35. data/lib/rbs/test/errors.rb +1 -1
  36. data/lib/rbs/test/hook.rb +133 -259
  37. data/lib/rbs/test/observer.rb +17 -0
  38. data/lib/rbs/test/setup.rb +13 -14
  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 +44 -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 +2 -2
  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/tmpdir/tmpdir.rbs +1 -1
  80. metadata +26 -116
  81. 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,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
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
166
233
 
167
- ancestors = builder.build_ancestors(ancestor)
168
-
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]
399
+ end
400
+ end
401
+
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]
319
406
  end
320
407
  end
321
408
 
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
409
+ env.constant_decls.each do |name, const|
410
+ stdout.puts "Validating constant: `#{name}`..."
411
+ validator.validate_type const.decl.type, context: const.context
325
412
  end
326
413
 
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
414
+ env.global_decls.each do |name, global|
415
+ stdout.puts "Validating global: `#{name}`..."
416
+ validator.validate_type global.decl.type, context: [Namespace.root]
330
417
  end
331
418
 
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
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)
@@ -362,7 +461,7 @@ module RBS
362
461
  name = Namespace.parse(args[0]).to_type_name
363
462
  stdout.puts "Constant name: #{name}"
364
463
 
365
- constant = table.resolve_constant_reference(name, context: namespace)
464
+ constant = table.resolve_constant_reference(name, context: namespace.ascend.to_a)
366
465
 
367
466
  if constant
368
467
  stdout.puts " => #{constant.name}: #{constant.type}"
@@ -371,11 +470,20 @@ module RBS
371
470
  end
372
471
  end
373
472
 
374
- def run_version(args, options)
375
- stdout.puts "ruby-signature #{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,28 +563,61 @@ 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)
449
570
  end
450
571
 
451
572
  relative_libs.each do |lib|
452
- require(lib)
573
+ eval("require_relative(lib)", binding, "rbs")
453
574
  end
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