rbs 0.20.1 → 1.0.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7d0358484cf9cfd6a58aba4115025628e9af481fbeb11079ba189e387486bd85
4
- data.tar.gz: 01fa1f2883a0faa043d5116118e6d4bbebb33dc3290d32d9404935817e589643
3
+ metadata.gz: fd21602800550be064e741db770aa752eaab018ca894238f88d75d1d1e950edd
4
+ data.tar.gz: 346c39ff339931cf9866e29cd096a0877c620feff86044a2bbb007826276904b
5
5
  SHA512:
6
- metadata.gz: 7a16ce63cf0d28ba0834f7a702767aa5dcb7440a0ef83d00f443e6877977abdb751c6e7816266d45af44cbe21b3eafc7a563edfdf678662a8412f4d8b758d80c
7
- data.tar.gz: 45e237d7de22114e7f6d22f138b2850645067993c9577581842464bec7d06937a7427d13d9821d93088008f0ea838b6e475b43725d3b16b60c0e3c821b7fef93
6
+ metadata.gz: 94651715eeed037f3d899fdae1cc49dc5134f5d3df7da03d06b7ebc7a053d43139adf29680de4a0036446afb16ef824862fae4ad5a6870861ae48bd589799ac6
7
+ data.tar.gz: ec967eef1ab035d4da2fe66f8a4661523c672eb1bc13f7033ac73ac8593810fd73e52d2d52173f8284abc47273b4442f9a95f4a5325c0e265cdb6a6d6b0321e1
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 1.0.0 (Pre released)
6
+
7
+ * Signature updates for `URI`, `IO`, and `Time` ([#529](https://github.com/ruby/rbs/pull/529), [#521](https://github.com/ruby/rbs/pull/521), [#520](https://github.com/ruby/rbs/pull/520), [#511](https://github.com/ruby/rbs/pull/511), [#517](https://github.com/ruby/rbs/pull/517))
8
+ * `rbs prototype runtime` generates `extend`s ([#535](https://github.com/ruby/rbs/pull/535))
9
+ * `rbs prototype runtime` stability improvements ([#533](https://github.com/ruby/rbs/pull/533), [#526](https://github.com/ruby/rbs/pull/526))
10
+ * Improve runtime type checker compatibility ([#532](https://github.com/ruby/rbs/pull/532), [#528](https://github.com/ruby/rbs/pull/528), )
11
+ * Better compatibility for record type attribute names ([#525](https://github.com/ruby/rbs/pull/525), [#524](https://github.com/ruby/rbs/pull/524))
12
+ * Let module-self-types be classes ([#523](https://github.com/ruby/rbs/pull/523))
13
+ * Method resolution improvements about `alias` and `.new` ([#522](https://github.com/ruby/rbs/pull/522), [#519](https://github.com/ruby/rbs/pull/519), [#516](https://github.com/ruby/rbs/pull/516))
14
+ * Fix `ruby2_keywords` for `Proc` in Ruby <2.7 ([#513](https://github.com/ruby/rbs/pull/513))
15
+
5
16
  ## 0.20.1 (2020-12-06)
6
17
 
7
18
  * Make the order of RBS load reproducible ([#508](https://github.com/ruby/rbs/pull/508))
data/Rakefile CHANGED
@@ -41,6 +41,10 @@ task :validate => :parser do
41
41
  lib << "pstore"
42
42
  end
43
43
 
44
+ if lib == ["logger"]
45
+ lib << "monitor"
46
+ end
47
+
44
48
  sh "#{ruby} #{rbs} #{lib.map {|l| "-r #{l}"}.join(" ")} validate --silent"
45
49
  end
46
50
  end
@@ -34,6 +34,10 @@ interface _Reader
34
34
  def read: (?int length, ?string outbuf) -> String?
35
35
  end
36
36
 
37
+ interface _ReaderPartial
38
+ def readpartial: (int maxlen, ?string outbuf) -> String
39
+ end
40
+
37
41
  interface _Writer
38
42
  # Writes the +data+ string. Returns the number of bytes written
39
43
  def write: (*_ToS data) -> Integer
@@ -405,7 +405,63 @@ class IO < Object
405
405
 
406
406
  def puts: (*untyped arg0) -> NilClass
407
407
 
408
- def read: (?Integer length, ?String outbuf) -> String?
408
+ # Reads *length* bytes from the I/O stream.
409
+ #
410
+ # *length* must be a non-negative integer or `nil`.
411
+ #
412
+ # If *length* is a positive integer, `read` tries to read *length* bytes without
413
+ # any conversion (binary mode). It returns `nil` if an EOF is encountered before
414
+ # anything can be read. Fewer than *length* bytes are returned if an EOF is
415
+ # encountered during the read. In the case of an integer *length*, the resulting
416
+ # string is always in ASCII-8BIT encoding.
417
+ #
418
+ # If *length* is omitted or is `nil`, it reads until EOF and the encoding
419
+ # conversion is applied, if applicable. A string is returned even if EOF is
420
+ # encountered before any data is read.
421
+ #
422
+ # If *length* is zero, it returns an empty string (`""`).
423
+ #
424
+ # If the optional *outbuf* argument is present, it must reference a String,
425
+ # which will receive the data. The *outbuf* will contain only the received data
426
+ # after the method call even if it is not empty at the beginning.
427
+ #
428
+ # When this method is called at end of file, it returns `nil` or `""`, depending
429
+ # on *length*: `read`, `read(nil)`, and `read(0)` return `""`,
430
+ # `read(*positive_integer*)` returns `nil`.
431
+ #
432
+ # f = File.new("testfile")
433
+ # f.read(16) #=> "This is line one"
434
+ #
435
+ # # read whole file
436
+ # open("file") do |f|
437
+ # data = f.read # This returns a string even if the file is empty.
438
+ # # ...
439
+ # end
440
+ #
441
+ # # iterate over fixed length records
442
+ # open("fixed-record-file") do |f|
443
+ # while record = f.read(256)
444
+ # # ...
445
+ # end
446
+ # end
447
+ #
448
+ # # iterate over variable length records,
449
+ # # each record is prefixed by its 32-bit length
450
+ # open("variable-record-file") do |f|
451
+ # while len = f.read(4)
452
+ # len = len.unpack("N")[0] # 32-bit length
453
+ # record = f.read(len) # This returns a string even if len is 0.
454
+ # end
455
+ # end
456
+ #
457
+ # Note that this method behaves like the fread() function in C. This means it
458
+ # retries to invoke read(2) system calls to read data with the specified length
459
+ # (or until EOF). This behavior is preserved even if *ios* is in non-blocking
460
+ # mode. (This method is non-blocking flag insensitive as other methods.) If you
461
+ # need the behavior like a single read(2) system call, consider #readpartial,
462
+ # #read_nonblock, and #sysread.
463
+ #
464
+ def read: (?Integer? length, ?String outbuf) -> String?
409
465
 
410
466
  def read_nonblock: (Integer len) -> String
411
467
  | (Integer len, ?String buf) -> String
@@ -428,8 +484,63 @@ class IO < Object
428
484
 
429
485
  def readlines: (?String sep, ?Integer limit) -> ::Array[String]
430
486
 
431
- def readpartial: (Integer maxlen) -> String
432
- | (Integer maxlen, ?String outbuf) -> String
487
+ # Reads at most *maxlen* bytes from the I/O stream. It blocks only if *ios* has
488
+ # no data immediately available. It doesn't block if some data available.
489
+ #
490
+ # If the optional *outbuf* argument is present, it must reference a String,
491
+ # which will receive the data. The *outbuf* will contain only the received data
492
+ # after the method call even if it is not empty at the beginning.
493
+ #
494
+ # It raises EOFError on end of file.
495
+ #
496
+ # readpartial is designed for streams such as pipe, socket, tty, etc. It blocks
497
+ # only when no data immediately available. This means that it blocks only when
498
+ # following all conditions hold.
499
+ # * the byte buffer in the IO object is empty.
500
+ # * the content of the stream is empty.
501
+ # * the stream is not reached to EOF.
502
+ #
503
+ #
504
+ # When readpartial blocks, it waits data or EOF on the stream. If some data is
505
+ # reached, readpartial returns with the data. If EOF is reached, readpartial
506
+ # raises EOFError.
507
+ #
508
+ # When readpartial doesn't blocks, it returns or raises immediately. If the byte
509
+ # buffer is not empty, it returns the data in the buffer. Otherwise if the
510
+ # stream has some content, it returns the data in the stream. Otherwise if the
511
+ # stream is reached to EOF, it raises EOFError.
512
+ #
513
+ # r, w = IO.pipe # buffer pipe content
514
+ # w << "abc" # "" "abc".
515
+ # r.readpartial(4096) #=> "abc" "" ""
516
+ # r.readpartial(4096) # blocks because buffer and pipe is empty.
517
+ #
518
+ # r, w = IO.pipe # buffer pipe content
519
+ # w << "abc" # "" "abc"
520
+ # w.close # "" "abc" EOF
521
+ # r.readpartial(4096) #=> "abc" "" EOF
522
+ # r.readpartial(4096) # raises EOFError
523
+ #
524
+ # r, w = IO.pipe # buffer pipe content
525
+ # w << "abc\ndef\n" # "" "abc\ndef\n"
526
+ # r.gets #=> "abc\n" "def\n" ""
527
+ # w << "ghi\n" # "def\n" "ghi\n"
528
+ # r.readpartial(4096) #=> "def\n" "" "ghi\n"
529
+ # r.readpartial(4096) #=> "ghi\n" "" ""
530
+ #
531
+ # Note that readpartial behaves similar to sysread. The differences are:
532
+ # * If the byte buffer is not empty, read from the byte buffer instead of
533
+ # "sysread for buffered IO (IOError)".
534
+ # * It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When readpartial
535
+ # meets EWOULDBLOCK and EINTR by read system call, readpartial retry the
536
+ # system call.
537
+ #
538
+ #
539
+ # The latter means that readpartial is nonblocking-flag insensitive. It blocks
540
+ # on the situation IO#sysread causes Errno::EWOULDBLOCK as if the fd is blocking
541
+ # mode.
542
+ #
543
+ def readpartial: (Integer maxlen, ?String outbuf) -> String
433
544
 
434
545
  def reopen: (IO other_IO_or_path) -> IO
435
546
  | (String other_IO_or_path, ?String mode_str) -> IO
@@ -508,13 +619,55 @@ class IO < Object
508
619
 
509
620
  def ungetc: (String arg0) -> NilClass
510
621
 
511
- def write: (*_ToS arg0) -> Integer
622
+ # Writes the given strings to *ios*. The stream must be opened for writing.
623
+ # Arguments that are not a string will be converted to a string using `to_s`.
624
+ # Returns the number of bytes written in total.
625
+ #
626
+ # count = $stdout.write("This is", " a test\n")
627
+ # puts "That was #{count} bytes of data"
628
+ #
629
+ # *produces:*
630
+ #
631
+ # This is a test
632
+ # That was 15 bytes of data
633
+ #
634
+ def write: (*_ToS string) -> Integer
512
635
 
636
+ # Opens the file, optionally seeks to the given *offset*, then returns *length*
637
+ # bytes (defaulting to the rest of the file). #binread ensures the file is
638
+ # closed before returning. The open mode would be `"rb:ASCII-8BIT"`.
639
+ #
640
+ # IO.binread("testfile") #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
641
+ # IO.binread("testfile", 20) #=> "This is line one\nThi"
642
+ # IO.binread("testfile", 20, 10) #=> "ne one\nThis is line "
643
+ #
513
644
  def self.binread: (String name, ?Integer length, ?Integer offset) -> String
514
645
 
515
- def self.binwrite: (String name, _ToS arg0, ?Integer offset, ?external_encoding: String external_encoding, ?internal_encoding: String internal_encoding, ?encoding: String encoding, ?textmode: untyped textmode, ?binmode: untyped binmode, ?autoclose: untyped autoclose, ?mode: String mode) -> Integer
646
+ # Same as IO.write except opening the file in binary mode and ASCII-8BIT
647
+ # encoding (`"wb:ASCII-8BIT"`).
648
+ #
649
+ def self.binwrite: (String name, _ToS string, ?Integer offset, ?mode: String mode) -> Integer
516
650
 
517
- def self.copy_stream: (_Reader src, _Writer dst, ?Integer copy_length, ?Integer src_offset) -> Integer
651
+ # IO.copy_stream copies *src* to *dst*. *src* and *dst* is either a filename or
652
+ # an IO-like object. IO-like object for *src* should have #readpartial or #read
653
+ # method. IO-like object for *dst* should have #write method. (Specialized
654
+ # mechanisms, such as sendfile system call, may be used on appropriate
655
+ # situation.)
656
+ #
657
+ # This method returns the number of bytes copied.
658
+ #
659
+ # If optional arguments are not given, the start position of the copy is the
660
+ # beginning of the filename or the current file offset of the IO. The end
661
+ # position of the copy is the end of file.
662
+ #
663
+ # If *copy_length* is given, No more than *copy_length* bytes are copied.
664
+ #
665
+ # If *src_offset* is given, it specifies the start position of the copy.
666
+ #
667
+ # When *src_offset* is specified and *src* is an IO, IO.copy_stream doesn't move
668
+ # the current file offset.
669
+ #
670
+ def self.copy_stream: ((String | _Reader | _ReaderPartial) src, (String | _Writer) dst, ?Integer copy_length, ?Integer src_offset) -> Integer
518
671
 
519
672
  def self.popen: (*untyped args) -> untyped
520
673
 
@@ -10,7 +10,7 @@
10
10
  # ```ruby
11
11
  # sprintf "%.1f", 1.234 #=> "1.2"
12
12
  # ```
13
- module Kernel
13
+ module Kernel : BasicObject
14
14
  private
15
15
 
16
16
  def caller: (?Integer start_or_range, ?Integer length) -> ::Array[String]?
@@ -28,6 +28,26 @@ rules:
28
28
  pass:
29
29
  - "def `send`: (String | Symbol, *untyped) -> untyped"
30
30
 
31
+ - id: rbs.prefer_boolish
32
+ pattern:
33
+ - regexp: '\([^(]*\bbool\b[^\n]*\)'
34
+ - token: "-> bool }"
35
+ message: |
36
+ Prefer `boolish` over `bool` for method arguments and block return values
37
+
38
+ See the doc below:
39
+ https://github.com/ruby/rbs/blob/78d04a2db0f1c4925d2b13c2939868edf9465d6c/docs/syntax.md#bool-or-boolish
40
+ glob:
41
+ - "**/*.rbs"
42
+ justification:
43
+ - When you strictly want `true | false`.
44
+ pass:
45
+ - "(arg: boolish)"
46
+ - "{ () -> boolish }"
47
+ fail:
48
+ - "(arg: bool)"
49
+ - "{ () -> bool }"
50
+
31
51
  - id: deprecate_stdlib_test
32
52
  pattern:
33
53
  token: < StdlibTest
data/lib/rbs.rb CHANGED
@@ -23,6 +23,8 @@ require "rbs/environment_loader"
23
23
  require "rbs/builtin_names"
24
24
  require "rbs/definition"
25
25
  require "rbs/definition_builder"
26
+ require "rbs/definition_builder/ancestor_builder"
27
+ require "rbs/definition_builder/method_builder"
26
28
  require "rbs/variance_calculator"
27
29
  require "rbs/substitution"
28
30
  require "rbs/constant"
@@ -136,10 +136,12 @@ module RBS
136
136
  class Super
137
137
  attr_reader :name
138
138
  attr_reader :args
139
+ attr_reader :location
139
140
 
140
- def initialize(name:, args:)
141
+ def initialize(name:, args:, location:)
141
142
  @name = name
142
143
  @args = args
144
+ @location = location
143
145
  end
144
146
 
145
147
  def ==(other)
@@ -155,7 +157,8 @@ module RBS
155
157
  def to_json(*a)
156
158
  {
157
159
  name: name,
158
- args: args
160
+ args: args,
161
+ location: location
159
162
  }.to_json(*a)
160
163
  end
161
164
  end
@@ -352,6 +355,8 @@ module RBS
352
355
  attr_reader :location
353
356
  attr_reader :comment
354
357
 
358
+ include MixinHelper
359
+
355
360
  def initialize(name:, type_params:, members:, annotations:, location:, comment:)
356
361
  @name = name
357
362
  @type_params = type_params
@@ -20,7 +20,7 @@ module RBS
20
20
  @annotations = annotations
21
21
  @location = location
22
22
  @comment = comment
23
- @overload = overload
23
+ @overload = overload ? true : false
24
24
  end
25
25
 
26
26
  def ==(other)
@@ -25,7 +25,7 @@ module RBS
25
25
  end
26
26
 
27
27
  loader = EnvironmentLoader.new(core_root: core_root, repository: repository)
28
-
28
+
29
29
  dirs.each do |dir|
30
30
  loader.add(path: Pathname(dir))
31
31
  end
@@ -43,21 +43,21 @@ module RBS
43
43
  opts.on("-r LIBRARY", "Load RBS files of the library") do |lib|
44
44
  libs << lib
45
45
  end
46
-
46
+
47
47
  opts.on("-I DIR", "Load RBS files from the directory") do |dir|
48
48
  dirs << dir
49
49
  end
50
-
50
+
51
51
  opts.on("--no-stdlib", "Skip loading standard library signatures") do
52
52
  self.core_root = nil
53
53
  end
54
-
54
+
55
55
  opts.on("--repo DIR", "Add RBS repository") do |dir|
56
56
  repos << dir
57
57
  end
58
-
58
+
59
59
  opts
60
- end
60
+ end
61
61
  end
62
62
 
63
63
  attr_reader :stdout
@@ -242,7 +242,7 @@ EOU
242
242
 
243
243
  env = Environment.from_loader(loader).resolve_type_names
244
244
 
245
- builder = DefinitionBuilder.new(env: env)
245
+ builder = DefinitionBuilder::AncestorBuilder.new(env: env)
246
246
  type_name = TypeName(args[0]).absolute!
247
247
 
248
248
  if env.class_decls.key?(type_name)
@@ -626,7 +626,7 @@ EOU
626
626
 
627
627
  opts = OptionParser.new
628
628
  opts.banner = <<EOU
629
- Usage: rbs prototype #{format} [options...] [files...]
629
+ Usage: rbs prototype #{format} [files...]
630
630
  #{availability}
631
631
  Generate RBS prototype from source code.
632
632
  It parses specified Ruby code and and generates RBS prototypes.
@@ -735,7 +735,7 @@ Examples:
735
735
  syntax_error = false
736
736
  args.each do |path|
737
737
  path = Pathname(path)
738
- loader.each_file(path, skip_hidden: false, immediate: true) do |file_path|
738
+ loader.each_file(path, skip_hidden: false, immediate: true) do |file_path|
739
739
  Parser.parse_signature(file_path.read)
740
740
  rescue RBS::Parser::SyntaxError => ex
741
741
  loc = ex.error_value.location
@@ -757,7 +757,7 @@ Examples:
757
757
  opts.push(*options.repos.map {|dir| "--repo #{Shellwords.escape(dir)}"})
758
758
  opts.push(*options.dirs.map {|dir| "-I #{Shellwords.escape(dir)}"})
759
759
  opts.push(*options.libs.map {|lib| "-r#{Shellwords.escape(lib)}"})
760
-
760
+
761
761
  opts.empty? ? nil : opts.join(" ")
762
762
  end
763
763
 
@@ -34,6 +34,20 @@ module RBS
34
34
  @implemented_in = implemented_in
35
35
  end
36
36
 
37
+ def ==(other)
38
+ other.is_a?(TypeDef) &&
39
+ other.type == type &&
40
+ other.member == member &&
41
+ other.defined_in == defined_in &&
42
+ other.implemented_in == implemented_in
43
+ end
44
+
45
+ alias eql? ==
46
+
47
+ def hash
48
+ self.class.hash ^ type.hash ^ member.hash ^ defined_in.hash ^ implemented_in.hash
49
+ end
50
+
37
51
  def comment
38
52
  member.comment
39
53
  end
@@ -70,6 +84,21 @@ module RBS
70
84
  @alias_of = alias_of
71
85
  end
72
86
 
87
+ def ==(other)
88
+ other.is_a?(Method) &&
89
+ other.super_method == super_method &&
90
+ other.defs == defs &&
91
+ other.accessibility == accessibility &&
92
+ other.annotations == annotations &&
93
+ other.alias_of == alias_of
94
+ end
95
+
96
+ alias eql? ==
97
+
98
+ def hash
99
+ self.class.hash ^ super_method.hash ^ defs.hash ^ accessibility.hash ^ annotations.hash ^ alias_of.hash
100
+ end
101
+
73
102
  def defined_in
74
103
  @defined_in ||= begin
75
104
  last_def = defs.last or raise
@@ -137,8 +166,43 @@ module RBS
137
166
  end
138
167
 
139
168
  module Ancestor
140
- Instance = _ = Struct.new(:name, :args, keyword_init: true)
141
- Singleton = _ = Struct.new(:name, keyword_init: true)
169
+ class Instance
170
+ attr_reader :name, :args, :source
171
+
172
+ def initialize(name:, args:, source:)
173
+ @name = name
174
+ @args = args
175
+ @source = source
176
+ end
177
+
178
+ def ==(other)
179
+ other.is_a?(Instance) && other.name == name && other.args == args
180
+ end
181
+
182
+ alias eql? ==
183
+
184
+ def hash
185
+ self.class.hash ^ name.hash ^ args.hash
186
+ end
187
+ end
188
+
189
+ class Singleton
190
+ attr_reader :name
191
+
192
+ def initialize(name:)
193
+ @name = name
194
+ end
195
+
196
+ def ==(other)
197
+ other.is_a?(Singleton) && other.name == name
198
+ end
199
+
200
+ alias eql? ==
201
+
202
+ def hash
203
+ self.class.hash ^ name.hash
204
+ end
205
+ end
142
206
  end
143
207
 
144
208
  class InstanceAncestors
@@ -170,7 +234,8 @@ module RBS
170
234
  else
171
235
  Ancestor::Instance.new(
172
236
  name: ancestor.name,
173
- args: ancestor.args.map {|type| type.sub(subst) }
237
+ args: ancestor.args.map {|type| type.sub(subst) },
238
+ source: ancestor.source
174
239
  )
175
240
  end
176
241
  when Ancestor::Singleton
@@ -233,6 +298,8 @@ module RBS
233
298
  case en = entry
234
299
  when Environment::SingleEntry
235
300
  en.decl.is_a?(AST::Declarations::Interface)
301
+ else
302
+ false
236
303
  end
237
304
  end
238
305