rbs 0.15.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +7 -3
  3. data/CHANGELOG.md +7 -1
  4. data/Gemfile +1 -0
  5. data/Rakefile +8 -1
  6. data/Steepfile +0 -1
  7. data/bin/test_runner.rb +15 -1
  8. data/{stdlib/builtin → core}/array.rbs +0 -0
  9. data/{stdlib/builtin → core}/basic_object.rbs +0 -0
  10. data/{stdlib/builtin → core}/binding.rbs +0 -0
  11. data/{stdlib/builtin → core}/builtin.rbs +0 -0
  12. data/{stdlib/builtin → core}/class.rbs +0 -0
  13. data/{stdlib/builtin → core}/comparable.rbs +0 -0
  14. data/{stdlib/builtin → core}/complex.rbs +0 -0
  15. data/{stdlib/builtin → core}/constants.rbs +0 -0
  16. data/{stdlib/builtin → core}/data.rbs +0 -0
  17. data/{stdlib/builtin → core}/deprecated.rbs +0 -0
  18. data/{stdlib/builtin → core}/dir.rbs +0 -0
  19. data/{stdlib/builtin → core}/encoding.rbs +0 -0
  20. data/{stdlib/builtin → core}/enumerable.rbs +0 -0
  21. data/{stdlib/builtin → core}/enumerator.rbs +0 -0
  22. data/{stdlib/builtin → core}/errno.rbs +0 -0
  23. data/{stdlib/builtin → core}/errors.rbs +0 -0
  24. data/{stdlib/builtin → core}/exception.rbs +0 -0
  25. data/{stdlib/builtin → core}/false_class.rbs +0 -0
  26. data/{stdlib/builtin → core}/fiber.rbs +0 -0
  27. data/{stdlib/builtin → core}/fiber_error.rbs +0 -0
  28. data/{stdlib/builtin → core}/file.rbs +0 -0
  29. data/{stdlib/builtin → core}/file_test.rbs +0 -0
  30. data/{stdlib/builtin → core}/float.rbs +0 -0
  31. data/{stdlib/builtin → core}/gc.rbs +0 -0
  32. data/{stdlib/builtin → core}/hash.rbs +0 -0
  33. data/{stdlib/builtin → core}/integer.rbs +0 -0
  34. data/{stdlib/builtin → core}/io.rbs +0 -0
  35. data/{stdlib/builtin → core}/kernel.rbs +0 -0
  36. data/{stdlib/builtin → core}/marshal.rbs +0 -0
  37. data/{stdlib/builtin → core}/match_data.rbs +0 -0
  38. data/{stdlib/builtin → core}/math.rbs +0 -0
  39. data/{stdlib/builtin → core}/method.rbs +0 -0
  40. data/{stdlib/builtin → core}/module.rbs +0 -0
  41. data/{stdlib/builtin → core}/nil_class.rbs +0 -0
  42. data/{stdlib/builtin → core}/numeric.rbs +0 -0
  43. data/{stdlib/builtin → core}/object.rbs +0 -0
  44. data/{stdlib/builtin → core}/proc.rbs +0 -0
  45. data/{stdlib/builtin → core}/process.rbs +0 -0
  46. data/{stdlib/builtin → core}/random.rbs +0 -0
  47. data/{stdlib/builtin → core}/range.rbs +0 -0
  48. data/{stdlib/builtin → core}/rational.rbs +0 -0
  49. data/{stdlib/builtin → core}/rb_config.rbs +0 -0
  50. data/{stdlib/builtin → core}/regexp.rbs +0 -0
  51. data/{stdlib/builtin → core}/ruby_vm.rbs +0 -0
  52. data/{stdlib/builtin → core}/signal.rbs +0 -0
  53. data/{stdlib/builtin → core}/string.rbs +0 -0
  54. data/{stdlib/builtin → core}/string_io.rbs +0 -0
  55. data/{stdlib/builtin → core}/struct.rbs +0 -0
  56. data/{stdlib/builtin → core}/symbol.rbs +0 -0
  57. data/{stdlib/builtin → core}/thread.rbs +0 -0
  58. data/{stdlib/builtin → core}/thread_group.rbs +0 -0
  59. data/{stdlib/builtin → core}/time.rbs +0 -0
  60. data/{stdlib/builtin → core}/trace_point.rbs +0 -0
  61. data/{stdlib/builtin → core}/true_class.rbs +0 -0
  62. data/{stdlib/builtin → core}/unbound_method.rbs +0 -0
  63. data/{stdlib/builtin → core}/warning.rbs +0 -0
  64. data/docs/repo.md +125 -0
  65. data/lib/rbs.rb +1 -0
  66. data/lib/rbs/cli.rb +105 -103
  67. data/lib/rbs/environment_loader.rb +79 -105
  68. data/lib/rbs/repository.rb +121 -0
  69. data/lib/rbs/test/setup.rb +5 -3
  70. data/lib/rbs/type_name.rb +2 -1
  71. data/lib/rbs/vendorer.rb +38 -16
  72. data/lib/rbs/version.rb +1 -1
  73. data/sig/cli.rbs +58 -0
  74. data/sig/definition_builder.rbs +2 -0
  75. data/sig/environment_loader.rbs +92 -46
  76. data/sig/polyfill.rbs +42 -0
  77. data/sig/rbs.rbs +8 -0
  78. data/sig/repository.rbs +79 -0
  79. data/sig/vendorer.rbs +44 -0
  80. data/stdlib/abbrev/{abbrev.rbs → 0/abbrev.rbs} +0 -0
  81. data/stdlib/base64/{base64.rbs → 0/base64.rbs} +0 -0
  82. data/stdlib/benchmark/{benchmark.rbs → 0/benchmark.rbs} +0 -0
  83. data/stdlib/{bigdecimal/math → bigdecimal-math/0}/big_math.rbs +0 -0
  84. data/stdlib/bigdecimal/{big_decimal.rbs → 0/big_decimal.rbs} +0 -0
  85. data/stdlib/coverage/{coverage.rbs → 0/coverage.rbs} +0 -0
  86. data/stdlib/csv/{csv.rbs → 0/csv.rbs} +0 -0
  87. data/stdlib/date/{date.rbs → 0/date.rbs} +0 -0
  88. data/stdlib/date/{date_time.rbs → 0/date_time.rbs} +0 -0
  89. data/stdlib/dbm/0/dbm.rbs +277 -0
  90. data/stdlib/erb/{erb.rbs → 0/erb.rbs} +0 -0
  91. data/stdlib/fiber/{fiber.rbs → 0/fiber.rbs} +0 -0
  92. data/stdlib/find/{find.rbs → 0/find.rbs} +0 -0
  93. data/stdlib/forwardable/{forwardable.rbs → 0/forwardable.rbs} +0 -0
  94. data/stdlib/ipaddr/{ipaddr.rbs → 0/ipaddr.rbs} +0 -0
  95. data/stdlib/json/{json.rbs → 0/json.rbs} +0 -0
  96. data/stdlib/logger/{formatter.rbs → 0/formatter.rbs} +0 -0
  97. data/stdlib/logger/{log_device.rbs → 0/log_device.rbs} +0 -0
  98. data/stdlib/logger/{logger.rbs → 0/logger.rbs} +0 -0
  99. data/stdlib/logger/{period.rbs → 0/period.rbs} +0 -0
  100. data/stdlib/logger/{severity.rbs → 0/severity.rbs} +0 -0
  101. data/stdlib/mutex_m/{mutex_m.rbs → 0/mutex_m.rbs} +0 -0
  102. data/stdlib/pathname/{pathname.rbs → 0/pathname.rbs} +0 -0
  103. data/stdlib/prime/{integer-extension.rbs → 0/integer-extension.rbs} +0 -0
  104. data/stdlib/prime/{prime.rbs → 0/prime.rbs} +0 -0
  105. data/stdlib/pstore/{pstore.rbs → 0/pstore.rbs} +0 -0
  106. data/stdlib/pty/{pty.rbs → 0/pty.rbs} +0 -0
  107. data/stdlib/securerandom/{securerandom.rbs → 0/securerandom.rbs} +0 -0
  108. data/stdlib/set/{set.rbs → 0/set.rbs} +0 -0
  109. data/stdlib/tmpdir/{tmpdir.rbs → 0/tmpdir.rbs} +0 -0
  110. data/stdlib/uri/{file.rbs → 0/file.rbs} +0 -0
  111. data/stdlib/uri/{generic.rbs → 0/generic.rbs} +0 -0
  112. data/stdlib/uri/{http.rbs → 0/http.rbs} +0 -0
  113. data/stdlib/uri/{https.rbs → 0/https.rbs} +0 -0
  114. data/stdlib/uri/{ldap.rbs → 0/ldap.rbs} +0 -0
  115. data/stdlib/uri/{ldaps.rbs → 0/ldaps.rbs} +0 -0
  116. data/stdlib/zlib/{zlib.rbs → 0/zlib.rbs} +0 -0
  117. metadata +100 -94
@@ -1,156 +1,130 @@
1
1
  module RBS
2
2
  class EnvironmentLoader
3
- class UnknownLibraryNameError < StandardError
4
- attr_reader :name
3
+ class UnknownLibraryError < StandardError
4
+ attr_reader :library
5
5
 
6
- def initialize(name:)
7
- @name = name
8
- super "Cannot find a library or gem: `#{name}`"
6
+ def initialize(lib:)
7
+ @library = lib
8
+
9
+ super("Cannot find type definitions for library: #{lib.name} (#{lib.version || "[nil]"})")
9
10
  end
10
11
  end
11
12
 
12
- LibraryPath = _ = Struct.new(:name, :path, keyword_init: true)
13
- GemPath = _ = Struct.new(:name, :version, :path, keyword_init: true)
13
+ Library = _ = Struct.new(:name, :version, keyword_init: true)
14
+
15
+ attr_reader :core_root
16
+ attr_reader :repository
14
17
 
15
- attr_reader :paths
16
- attr_reader :stdlib_root
17
- attr_reader :gem_vendor_path
18
+ attr_reader :libs
19
+ attr_reader :dirs
18
20
 
19
- STDLIB_ROOT = Pathname(_ = __dir__) + "../../stdlib"
21
+ DEFAULT_CORE_ROOT = Pathname(_ = __dir__) + "../../core"
20
22
 
21
23
  def self.gem_sig_path(name, version)
22
- Pathname(Gem::Specification.find_by_name(name, version).gem_dir) + "sig"
24
+ spec = Gem::Specification.find_by_name(name, version)
25
+ path = Pathname(spec.gem_dir) + "sig"
26
+ if path.directory?
27
+ [spec, path]
28
+ end
23
29
  rescue Gem::MissingSpecError
24
30
  nil
25
31
  end
26
32
 
27
- def initialize(stdlib_root: STDLIB_ROOT, gem_vendor_path: nil)
28
- @stdlib_root = stdlib_root
29
- @gem_vendor_path = gem_vendor_path
30
- @paths = []
31
- @no_builtin = false
33
+ def initialize(core_root: DEFAULT_CORE_ROOT, repository: Repository.new)
34
+ @core_root = core_root
35
+ @repository = repository
36
+
37
+ @libs = []
38
+ @dirs = []
32
39
  end
33
40
 
34
- def add(path: nil, library: nil)
41
+ def add(path: nil, library: nil, version: nil)
35
42
  case
36
43
  when path
37
- @paths << path
44
+ dirs << path
38
45
  when library
39
- name, version = self.class.parse_library(library)
40
-
41
- case
42
- when !version && path = stdlib?(name)
43
- @paths << LibraryPath.new(name: name, path: path)
44
- when (path = gem?(name, version))
45
- @paths << GemPath.new(name: name, version: version, path: path)
46
- else
47
- raise UnknownLibraryNameError.new(name: library)
48
- end
46
+ libs << Library.new(name: library, version: version)
49
47
  end
50
48
  end
51
49
 
52
- def self.parse_library(lib)
53
- _ = lib.split(/:/)
50
+ def has_library?(library:, version:)
51
+ self.class.gem_sig_path(library, version) || repository.lookup(library, version)
54
52
  end
55
53
 
56
- def stdlib?(name)
57
- path = stdlib_root + name
58
- if path.directory?
59
- path
54
+ def load(env:)
55
+ # @type var loaded: Array[[AST::Declarations::t, Pathname, source]]
56
+ loaded = []
57
+
58
+ each_decl do |decl, buf, source, path|
59
+ env << decl
60
+ loaded << [decl, path, source]
60
61
  end
62
+
63
+ loaded
61
64
  end
62
65
 
63
- def gem?(name, version)
64
- if path = gem_vendor_path
65
- # Try vendored RBS first
66
- gem_dir = path + name
67
- if gem_dir.directory?
68
- return gem_dir
69
- end
66
+ def each_dir
67
+ if root = core_root
68
+ yield :core, root
70
69
  end
71
70
 
72
- # Try ruby gem library
73
- self.class.gem_sig_path(name, version)
74
- end
71
+ libs.each do |lib|
72
+ unless has_library?(version: lib.version, library: lib.name)
73
+ raise UnknownLibraryError.new(lib: lib)
74
+ end
75
75
 
76
- def each_signature(path, immediate: true, &block)
77
- if block
78
76
  case
79
- when path.file?
80
- if path.extname == ".rbs" || immediate
81
- yield path
82
- end
83
- when path.directory?
84
- path.children.each do |child|
85
- each_signature child, immediate: false, &block
86
- end
77
+ when from_gem = self.class.gem_sig_path(lib.name, lib.version)
78
+ yield lib, from_gem[1]
79
+ when from_repo = repository.lookup(lib.name, lib.version)
80
+ yield lib, from_repo
87
81
  end
88
- else
89
- enum_for :each_signature, path, immediate: immediate
90
82
  end
91
- end
92
83
 
93
- def each_library_path
94
- paths.each do |path|
95
- case path
96
- when Pathname
97
- yield path, path
98
- when LibraryPath
99
- yield path, path.path
100
- when GemPath
101
- yield path, path.path
102
- end
84
+ dirs.each do |dir|
85
+ yield dir, dir
103
86
  end
104
87
  end
105
88
 
106
- def no_builtin!(skip = true)
107
- @no_builtin = skip
108
- self
109
- end
110
-
111
- def no_builtin?
112
- @no_builtin
113
- end
114
-
115
- def each_decl
116
- if block_given?
117
- # @type var signature_files: Array[[path | :stdlib, Pathname]]
118
- signature_files = []
119
-
120
- unless no_builtin?
121
- each_signature(stdlib_root + "builtin") do |path|
122
- signature_files << [:stdlib, path]
123
- end
89
+ def each_file(path, immediate:, skip_hidden:, &block)
90
+ case
91
+ when path.file?
92
+ if path.extname == ".rbs" || immediate
93
+ yield path
124
94
  end
125
95
 
126
- each_library_path do |library_path, pathname|
127
- each_signature(pathname) do |path|
128
- signature_files << [library_path, path]
96
+ when path.directory?
97
+ if path.basename.to_s.start_with?("_")
98
+ if skip_hidden
99
+ unless immediate
100
+ return
101
+ end
129
102
  end
130
103
  end
131
104
 
132
- signature_files.each do |lib_path, file_path|
133
- buffer = Buffer.new(name: file_path.to_s, content: file_path.read)
134
- Parser.parse_signature(buffer).each do |decl|
135
- yield decl, buffer, file_path, lib_path
136
- end
105
+ path.each_child do |child|
106
+ each_file(child, immediate: false, skip_hidden: skip_hidden, &block)
137
107
  end
138
- else
139
- enum_for :each_decl
140
108
  end
141
109
  end
142
110
 
143
- def load(env:)
144
- # @type var loadeds: Array[[AST::Declarations::t, Pathname, path | :stdlib]]
145
- loadeds = []
111
+ def each_decl
112
+ files = Set[]
146
113
 
147
- each_decl do |decl, buffer, file_path, lib_path|
148
- env.buffers.push(buffer)
149
- env << decl
150
- loadeds << [decl, file_path, lib_path]
151
- end
114
+ each_dir do |source, dir|
115
+ skip_hidden = !source.is_a?(Pathname)
116
+
117
+ each_file(dir, skip_hidden: skip_hidden, immediate: true) do |path|
118
+ next if files.include?(path)
152
119
 
153
- loadeds
120
+ files << path
121
+ buffer = Buffer.new(name: path.to_s, content: path.read)
122
+
123
+ Parser.parse_signature(buffer).each do |decl|
124
+ yield decl, buffer, source, path
125
+ end
126
+ end
127
+ end
154
128
  end
155
129
  end
156
130
  end
@@ -0,0 +1,121 @@
1
+ module RBS
2
+ class Repository
3
+ DEFAULT_STDLIB_ROOT = Pathname(_ = __dir__) + "../../stdlib"
4
+
5
+ class GemRBS
6
+ attr_reader :name
7
+ attr_reader :paths
8
+
9
+ def initialize(name:)
10
+ @name = name
11
+ @paths = []
12
+ @versions = nil
13
+ end
14
+
15
+ def versions
16
+ load! unless @versions
17
+ @versions or raise
18
+ end
19
+
20
+ def load!
21
+ @versions = {}
22
+ versions = @versions or raise
23
+
24
+ paths.each do |gem_path|
25
+ gem_path.each_child(false) do |child|
26
+ next unless Gem::Version.correct?(child.to_s)
27
+
28
+ if version = Gem::Version.create(child.to_s)
29
+ unless version.prerelease?
30
+ path = gem_path + child
31
+
32
+ if prev = versions[version]
33
+ RBS.logger.info { "Overwriting gem RBS in repository: gem=#{name}, prev_path=#{prev.path}, new_path=#{path}" }
34
+ end
35
+
36
+ versions[version] = VersionPath.new(gem: self, version: version, path: path)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def version_names
44
+ versions.keys.sort_by(&:version)
45
+ end
46
+
47
+ def oldest_version
48
+ oldest = version_names.first or raise
49
+ versions[oldest] or raise
50
+ end
51
+
52
+ def latest_version
53
+ latest = version_names.last or raise
54
+ versions[latest] or raise
55
+ end
56
+
57
+ def find_best_version(version)
58
+ return latest_version unless version
59
+
60
+ if v = version_names.reverse.bsearch {|v| v <= version ? true : false }
61
+ versions[v]
62
+ else
63
+ oldest_version
64
+ end
65
+ end
66
+
67
+ def empty?
68
+ versions.empty?
69
+ end
70
+ end
71
+
72
+ VersionPath = _ = Struct.new(:gem, :version, :path, keyword_init: true)
73
+
74
+ attr_reader :dirs
75
+ attr_reader :gems
76
+
77
+ def initialize(no_stdlib: false)
78
+ @dirs = []
79
+ @gems = {}
80
+
81
+ unless no_stdlib
82
+ add(DEFAULT_STDLIB_ROOT)
83
+ end
84
+ end
85
+
86
+ def self.default
87
+ new().tap do |repo|
88
+ repo.add(DEFAULT_STDLIB_ROOT)
89
+ end
90
+ end
91
+
92
+ def add(dir)
93
+ dirs << dir
94
+
95
+ dir.each_child(false) do |child|
96
+ gem_name = child.to_s
97
+ gem_rbs = (gems[gem_name] ||= GemRBS.new(name: gem_name))
98
+ gem_rbs.paths << dir + child
99
+ end
100
+ end
101
+
102
+ def lookup(gem, version)
103
+ _, set = lookup_path(gem, version)
104
+ set&.path
105
+ end
106
+
107
+ def lookup_path(gem, version)
108
+ if gem_rbs = gems[gem]
109
+ unless gem_rbs.empty?
110
+ set = if v = Gem::Version.create(version)&.release
111
+ gem_rbs.find_best_version(v)
112
+ else
113
+ gem_rbs.latest_version
114
+ end
115
+
116
+ [gem_rbs, set]
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -2,6 +2,7 @@ require "rbs"
2
2
  require "rbs/test"
3
3
  require "optparse"
4
4
  require "shellwords"
5
+ require "rbs/cli"
5
6
 
6
7
  include RBS::Test::SetupHelper
7
8
 
@@ -32,12 +33,13 @@ if filter.empty?
32
33
  exit 1
33
34
  end
34
35
 
35
- loader = RBS::EnvironmentLoader.new
36
+ options = RBS::CLI::LibraryOptions.new()
37
+
36
38
  OptionParser.new do |opts|
37
- opts.on("-r [LIB]") do |name| loader.add(library: name) end
38
- opts.on("-I [DIR]") do |dir| loader.add(path: Pathname(dir)) end
39
+ options.setup_library_options(opts)
39
40
  end.parse!(opts)
40
41
 
42
+ loader = options.loader
41
43
  env = RBS::Environment.from_loader(loader).resolve_type_names
42
44
 
43
45
  def match(filter, name)
@@ -16,7 +16,8 @@ module RBS
16
16
  when "_"
17
17
  :interface
18
18
  else
19
- raise
19
+ # Defaults to :class
20
+ :class
20
21
  end
21
22
  end
22
23
 
@@ -1,9 +1,11 @@
1
1
  module RBS
2
2
  class Vendorer
3
3
  attr_reader :vendor_dir
4
+ attr_reader :loader
4
5
 
5
- def initialize(vendor_dir:)
6
+ def initialize(vendor_dir:, loader:)
6
7
  @vendor_dir = vendor_dir
8
+ @loader = loader
7
9
  end
8
10
 
9
11
  def ensure_dir
@@ -21,27 +23,47 @@ module RBS
21
23
  end
22
24
  end
23
25
 
24
- def stdlib!()
25
- ensure_dir do
26
- RBS.logger.info "Vendoring stdlib: #{EnvironmentLoader::STDLIB_ROOT} => #{vendor_dir + "stdlib"}..."
27
- FileUtils.copy_entry EnvironmentLoader::STDLIB_ROOT, vendor_dir + "stdlib"
26
+ def copy!
27
+ # @type var paths: Set[[Pathname, Pathname]]
28
+ paths = Set[]
29
+
30
+ if core_root = loader.core_root
31
+ RBS.logger.info "Vendoring core RBSs in #{vendor_dir + "core"}..."
32
+ loader.each_file(core_root, immediate: false, skip_hidden: true) do |file_path|
33
+ paths << [file_path, Pathname("core") + file_path.relative_path_from(core_root)]
34
+ end
28
35
  end
29
- end
30
36
 
31
- def gem!(name, version)
32
- ensure_dir do
33
- sig_path = EnvironmentLoader.gem_sig_path(name, version)
34
- RBS.logger.debug "Checking gem signature path: name=#{name}, version=#{version}, path=#{sig_path}"
37
+ loader.libs.each do |lib|
38
+ case
39
+ when (spec, path = EnvironmentLoader.gem_sig_path(lib.name, lib.version))
40
+ dest_dir = Pathname("#{lib.name}-#{spec.version}")
41
+
42
+ RBS.logger.info "Vendoring #{lib.name}(#{spec.version}) RBSs in #{vendor_dir + dest_dir}..."
35
43
 
36
- if sig_path&.directory?
37
- gems_dir = vendor_dir + "gems"
38
- gems_dir.mkpath unless gems_dir.directory?
44
+ loader.each_file(path, skip_hidden: true, immediate: false) do |file_path|
45
+ paths << [file_path, dest_dir + file_path.relative_path_from(path)]
46
+ end
39
47
 
40
- gem_dir = gems_dir + name
41
- RBS.logger.info "Vendoring gem(#{name}:#{version}): #{sig_path} => #{gem_dir}..."
42
- FileUtils.copy_entry sig_path, gem_dir
48
+ when (rbs, path = loader.repository.lookup_path(lib.name, lib.version))
49
+ dest_dir = Pathname("#{rbs.name}-#{path.version}")
50
+
51
+ RBS.logger.info "Vendoring #{lib.name}(#{path.version}) RBSs in #{vendor_dir + dest_dir}..."
52
+
53
+ loader.each_file(path.path, skip_hidden: true, immediate: false) do |file_path|
54
+ paths << [file_path, dest_dir + file_path.relative_path_from(path.path)]
55
+ end
56
+ else
57
+ RBS.logger.error "Couldn't find RBSs for #{lib.name} (#{lib.version}); skipping..."
43
58
  end
44
59
  end
60
+
61
+ paths.each do |from, to|
62
+ dest = vendor_dir + to
63
+ dest.parent.mkpath unless dest.parent.directory?
64
+
65
+ FileUtils.copy_file(from.to_s, dest.to_s)
66
+ end
45
67
  end
46
68
  end
47
69
  end