rbs 0.2.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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