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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5348f41dbf169228104d4ba79ad88098ec3e8e83656b48b0b1c5877fab2e8cb7
4
- data.tar.gz: c79ce48144a85642f974b0973e22f8ed97a072d98ce98e2b62aebf639c8d04f7
3
+ metadata.gz: 5062396fb965f4d6f07ceee4f6b82ef22a12c20897d82c6615d6765d5bf43b7f
4
+ data.tar.gz: 8b30dd2d71e12d56501bafc2ab4ca1d604befbc3ef797f02234b6d6acc95ac71
5
5
  SHA512:
6
- metadata.gz: efb99d0e6476b83dbd1994a71526adab4b5b6aab2fc231a1685407739bb9a3e2f1268fb3effcbe701fa033608a0b872fd3f0011d046c599457bf47a3c3fcdb97
7
- data.tar.gz: 87d13112f6abce7b7ead4e95302978d17c7c08eaf94485bf27c00c5d91e08f8c10458344661b73d518caff095787323d3694512d76796f2d20da8c2bad2e101f
6
+ metadata.gz: ec6b6090f0a93cbfbe2f4ffe5f5bbce253425f3f85a55dcabec2943f724a81c637c441820236aa1dcbff6104d1fe7d215e4cb38ac76c5f827677167e437761f5
7
+ data.tar.gz: 301d1c5a305dce97dfdd6d89c39a4deafcedc405535b13b1846b3d03af83a87747cc44ade7a0148b96af7d07d7a53b4eb7c8954344ae11d574f69ca81c3eb7a8
@@ -13,8 +13,8 @@ jobs:
13
13
  matrix:
14
14
  container_tag:
15
15
  - master-nightly-bionic
16
- - 2.6.5-bionic
17
- - 2.7.0-bionic
16
+ - 2.6-bionic
17
+ - 2.7-bionic
18
18
  job:
19
19
  - test
20
20
  - stdlib_test
@@ -23,6 +23,10 @@ jobs:
23
23
  image: rubylang/ruby:${{ matrix.container_tag }}
24
24
  steps:
25
25
  - uses: actions/checkout@v1
26
+ - name: Install dependencies
27
+ run: |
28
+ apt-get update
29
+ apt-get install -y libdb-dev
26
30
  - name: Install
27
31
  run: |
28
32
  ruby -v
@@ -31,4 +35,4 @@ jobs:
31
35
  - name: Run test
32
36
  run: |
33
37
  bundle exec rake ${{ matrix.job }}
34
- if: "!(matrix.job == 'stdlib_test' && contains(matrix.container_tag, '2.6.5'))"
38
+ if: "!(matrix.job == 'stdlib_test' && contains(matrix.container_tag, '2.6'))"
@@ -2,7 +2,13 @@
2
2
 
3
3
  ## master
4
4
 
5
- ## 0.15.0 (2020-11-2)
5
+ ## 0.16.0 (2020-11-05)
6
+
7
+ * Signature update for `DBM` ([#441](https://github.com/ruby/rbs/pull/441))
8
+ * RBS repository ([#405](https://github.com/ruby/rbs/pull/405))
9
+ * Support `alias` in `rbs prototype rb` ([#457](https://github.com/ruby/rbs/pull/457))
10
+
11
+ ## 0.15.0 (2020-11-02)
6
12
 
7
13
  * Signature updates for `Kernel`, `PStore`, `Enumerable`, and `Array` ([#450](https://github.com/ruby/rbs/pull/450), [#443](https://github.com/ruby/rbs/pull/443), [#438](https://github.com/ruby/rbs/pull/438), [#437](https://github.com/ruby/rbs/pull/437), [#433](https://github.com/ruby/rbs/pull/433), [#432](https://github.com/ruby/rbs/pull/432))
8
14
  * Add helper interfaces ([#434](https://github.com/ruby/rbs/pull/434), [#428](https://github.com/ruby/rbs/pull/428))
data/Gemfile CHANGED
@@ -15,6 +15,7 @@ gem "json"
15
15
  gem "json-schema"
16
16
  gem 'stackprof'
17
17
  gem "goodcheck"
18
+ gem "dbm"
18
19
 
19
20
  # Test gems
20
21
  gem "rbs-amber", path: "test/assets/test-gem"
data/Rakefile CHANGED
@@ -29,7 +29,14 @@ task :validate => :parser do
29
29
 
30
30
  FileList["stdlib/*"].each do |path|
31
31
  next if path =~ %r{stdlib/builtin}
32
- sh "#{ruby} #{rbs} -r#{File.basename(path)} validate --silent"
32
+
33
+ lib = [File.basename(path).to_s]
34
+
35
+ if lib == ["bigdecimal-math"]
36
+ lib << "bigdecimal"
37
+ end
38
+
39
+ sh "#{ruby} #{rbs} #{lib.map {|l| "-r #{l}"}.join(" ")} validate --silent"
33
40
  end
34
41
  end
35
42
 
data/Steepfile CHANGED
@@ -3,7 +3,6 @@ target :lib do
3
3
  check "lib"
4
4
  ignore "lib/rbs/parser.rb"
5
5
 
6
- vendor stdlib: "stdlib"
7
6
  library "set", "pathname", "json", "logger"
8
7
  end
9
8
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  $LOAD_PATH << File.join(__dir__, "../lib")
4
4
 
5
+ require "set"
6
+
5
7
  IS_RUBY_27 = Gem::Version.new(RUBY_VERSION).yield_self do |ruby_version|
6
8
  Gem::Version.new('2.7.0') <= ruby_version &&
7
9
  ruby_version <= Gem::Version.new('2.8.0')
@@ -11,6 +13,18 @@ unless IS_RUBY_27
11
13
  STDERR.puts "⚠️⚠️⚠️⚠️ stdlib test assumes Ruby 2.7 but RUBY_VERSION==#{RUBY_VERSION} ⚠️⚠️⚠️⚠️"
12
14
  end
13
15
 
16
+ KNOWN_FAILS = %w(dbm).map do |lib|
17
+ /cannot load such file -- #{lib}/
18
+ end
19
+
14
20
  ARGV.each do |arg|
15
- load arg
21
+ begin
22
+ load arg
23
+ rescue LoadError => exn
24
+ if KNOWN_FAILS.any? {|pat| pat =~ exn.message }
25
+ STDERR.puts "Loading #{arg} failed, ignoring it: #{exn.inspect}"
26
+ else
27
+ raise
28
+ end
29
+ end
16
30
  end
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,125 @@
1
+ # Third-party RBS Repository
2
+
3
+ This is the spec of the directory structure for RBS files of gems without RBS files. It allows distributing RBS type definitions of gems separately from the `.gemspec` files so that the Ruby developers can type check their Ruby programs even if the dependent gems don't ship with their type definitions.
4
+
5
+ The spec includes:
6
+
7
+ * The directory structure, and
8
+ * The RBS file lookup rules given _repository root_, gem name, and version.
9
+
10
+ ## Motivating Example
11
+
12
+ Assume there is a rubygem called `bug-free-doodle` and our application depends on the library. We are trying to type check our application and we need RBS files of `bug-free-doodle`. The problem is that the `bug-free-doodle` gem doesn't ship with RBS files. The type checkers cannot resolve the type of constant `Bug::Free::Doodle` and its methods.
13
+
14
+ One workaround is to add type definitions of the library in the application signatures.
15
+
16
+ ```
17
+ # sig/polyfill/bug-free-doodle.rbs
18
+
19
+ module Bug
20
+ module Free
21
+ class Doodle
22
+ attr_reader name: Symbol
23
+ attr_reader strokes: Array[Stroke]
24
+
25
+ def initialize: (name: Symbol) -> void
26
+ end
27
+ end
28
+ end
29
+ ```
30
+
31
+ You may want to distribute the RBS file to anyone who needs it. Which version do we support? Testing it? How to load the RBS files? This is the spec you need!
32
+
33
+ ### Third-party RBS repository
34
+
35
+ Make a directory (or you may want to `git init`) to put your _third party RBSs_.
36
+
37
+ ```sh
38
+ $ make my-rbs # Or you may want a git repository: git init my-rbs
39
+ $ cd my-rbs
40
+ $ mkdir gems
41
+ ```
42
+
43
+ We call the `my-rbs/gems` directory _repository root_. Note that it is different from the root of the git repository. The RBS repository root is the directory that contains directories of gem names.
44
+
45
+ Make a directory for the gem and the version.
46
+
47
+ ```sh
48
+ $ mkdir gems/bug-free-doodle
49
+ $ mkdir gems/bug-free-doodle/1.2.3
50
+ ```
51
+
52
+ And copy the RBS file in it.
53
+
54
+ ```sh
55
+ $ cp your-app/sig/polyfill/bug-free-doodle.rbs gems/bug-free-doodle/1.2.3
56
+ ```
57
+
58
+ ### Reading Third-party RBS
59
+
60
+ `rbs` command accepts `--repo` option which points to a _repository root_. You can specify `-r` option to let the command know which gems you want to load.
61
+
62
+ In this case, the _repository root_ is `./gems` and we are trying to load `bug-free-doodle` gem.
63
+
64
+ ```sh
65
+ $ rbs --repo=gems -r bug-free-doodle paths
66
+ ```
67
+
68
+ The `-r` option also accepts gem name with version.
69
+
70
+ ```sh
71
+ $ rbs --repo=gems -r bug-free-doodle:1.2.3 paths
72
+ ```
73
+
74
+ Note that the version resolution is not compatible with semantic versioning. It is optimistic. It resolves to some version unless no version for the gem is available.
75
+
76
+ ## Directory Structure
77
+
78
+ There are directories for each gem under _repository root_. We also have directories for each version of each gem.
79
+
80
+ - $REPO_ROOT/bug-free-doodle/0.2.0
81
+ - $REPO_ROOT/bug-free-doodle/1.0
82
+ - $REPO_ROOT/bug-free-doodle/1.2.3
83
+ - $REPO_ROOT/bug-free-doodle/2.0
84
+
85
+ Note that we assume that we have git repositories for each RBS repository, and we have a directory at the root of the git repository for _repository root_.
86
+
87
+ So the git repository structure would be something like the following:
88
+
89
+ - /Gemfile
90
+ - /Gemfile.lock
91
+ - /README.md
92
+ - /LICENSE
93
+ - /gems/bug-free-doodle/1.2.3/bug-free-doodle.rbs
94
+
95
+ You should have `Gemfile` and `Gemfile.lock` to manage dependencies, `README.md` and `LICENSE` to documentation, and `gems` directory as _repository root_.
96
+
97
+ (We call _repository root_ `gems` in this doc, but the name can be anything you like.)
98
+
99
+ ## Version Resolution
100
+
101
+ The version resolution in RBS is optimistic. We don't block loading RBS files for _incompatible_ version in terms of semantic versioning.
102
+
103
+ It tries to resolve version _n_ as follows:
104
+
105
+ 1. It resolves to _m_ such that _m_ is the latest version available and _m_ <= _n_ holds.
106
+ 2. It resolves to the oldest version when rule 1 cannot find version _m_.
107
+
108
+ If two versions, `0.4.0`, `1.0.0` are available for a gem:
109
+
110
+ | Requested version | Resolved version |
111
+ |-------------------|------------------|
112
+ | `0.3.0` | `0.4.0` (Rule 2) |
113
+ | `0.4.0` | `0.4.0` |
114
+ | `0.5.0` | `0.4.0` |
115
+ | `1.0.0` | `1.0.0` |
116
+ | `2.0.0` | `1.0.0` |
117
+
118
+ This is not compatible with the concept of semantic versioning. We don't want to block users to load RBS even for incompatible versions of gems.
119
+
120
+ We believe this makes more sense because:
121
+
122
+ * Using (potentially) incompatible type definitions are better than no type definition.
123
+ * Users can stop loading RBS if incompatibility causes an issue and falling back to hand-written polyfills.
124
+
125
+
data/lib/rbs.rb CHANGED
@@ -37,6 +37,7 @@ require "rbs/environment_walker"
37
37
  require "rbs/vendorer"
38
38
  require "rbs/validator"
39
39
  require "rbs/factory"
40
+ require "rbs/repository"
40
41
 
41
42
  begin
42
43
  require "rbs/parser"
@@ -5,29 +5,59 @@ require "shellwords"
5
5
  module RBS
6
6
  class CLI
7
7
  class LibraryOptions
8
+ attr_accessor :core_root
9
+ attr_reader :repos
8
10
  attr_reader :libs
9
11
  attr_reader :dirs
10
- attr_accessor :no_stdlib
11
12
 
12
13
  def initialize()
14
+ @core_root = EnvironmentLoader::DEFAULT_CORE_ROOT
15
+ @repos = []
16
+
13
17
  @libs = []
14
18
  @dirs = []
15
- @no_stdlib = false
16
19
  end
17
20
 
18
- def setup(loader)
19
- libs.each do |lib|
20
- loader.add(library: lib)
21
+ def loader
22
+ repository = Repository.new(no_stdlib: core_root.nil?)
23
+ repos.each do |repo|
24
+ repository.add(Pathname(repo))
21
25
  end
22
26
 
27
+ loader = EnvironmentLoader.new(core_root: core_root, repository: repository)
28
+
23
29
  dirs.each do |dir|
24
30
  loader.add(path: Pathname(dir))
25
31
  end
26
32
 
27
- loader.no_builtin! if no_stdlib
33
+ libs.each do |lib|
34
+ name, version = lib.split(/:/, 2)
35
+ next unless name
36
+ loader.add(library: name, version: version)
37
+ end
28
38
 
29
39
  loader
30
40
  end
41
+
42
+ def setup_library_options(opts)
43
+ opts.on("-r LIBRARY", "Load RBS files of the library") do |lib|
44
+ libs << lib
45
+ end
46
+
47
+ opts.on("-I DIR", "Load RBS files from the directory") do |dir|
48
+ dirs << dir
49
+ end
50
+
51
+ opts.on("--no-stdlib", "Skip loading standard library signatures") do
52
+ self.core_root = nil
53
+ end
54
+
55
+ opts.on("--repo DIR", "Add RBS repository") do |dir|
56
+ repos << dir
57
+ end
58
+
59
+ opts
60
+ end
31
61
  end
32
62
 
33
63
  attr_reader :stdout
@@ -40,29 +70,14 @@ module RBS
40
70
 
41
71
  COMMANDS = [:ast, :list, :ancestors, :methods, :method, :validate, :constant, :paths, :prototype, :vendor, :parse, :test]
42
72
 
43
- def library_parse(opts, options:)
44
- opts.on("-r LIBRARY", "Load RBS files of the library") do |lib|
45
- options.libs << lib
46
- end
47
-
48
- opts.on("-I DIR", "Load RBS files from the directory") do |dir|
49
- options.dirs << dir
50
- end
51
-
52
- opts.on("--no-stdlib", "Skip loading standard library signatures") do
53
- options.no_stdlib = true
54
- end
55
-
56
- opts
57
- end
58
-
59
73
  def parse_logging_options(opts)
60
74
  opts.on("--log-level LEVEL", "Specify log level (defaults to `warn`)") do |level|
61
75
  RBS.logger_level = level
62
76
  end
63
77
 
64
78
  opts.on("--log-output OUTPUT", "Specify the file to output log (defaults to stderr)") do |output|
65
- RBS.logger_output = File.open(output, "a")
79
+ io = File.open(output, "a") or raise
80
+ RBS.logger_output = io
66
81
  end
67
82
 
68
83
  opts
@@ -83,7 +98,7 @@ module RBS
83
98
 
84
99
  Options:
85
100
  USAGE
86
- library_parse(opts, options: options)
101
+ options.setup_library_options(opts)
87
102
  parse_logging_options(opts)
88
103
  opts.version = RBS::VERSION
89
104
 
@@ -129,13 +144,14 @@ EOB
129
144
  end
130
145
  end
131
146
 
132
- loader = EnvironmentLoader.new()
133
- options.setup(loader)
147
+ loader = options.loader()
134
148
 
135
149
  env = Environment.from_loader(loader).resolve_type_names
136
150
 
137
151
  decls = env.declarations.select do |decl|
138
- name = decl.location.buffer.name
152
+ loc = decl.location or raise
153
+ # @type var name: String
154
+ name = loc.buffer.name
139
155
 
140
156
  patterns.empty? || patterns.any? do |pat|
141
157
  case pat
@@ -152,6 +168,7 @@ EOB
152
168
  end
153
169
 
154
170
  def run_list(args, options)
171
+ # @type var list: Set[:class | :module | :interface]
155
172
  list = Set[]
156
173
 
157
174
  OptionParser.new do |opts|
@@ -172,10 +189,9 @@ EOB
172
189
  opts.on("--interface", "List interfaces") { list << :interface }
173
190
  end.order!(args)
174
191
 
175
- list.merge([:class, :module, :interface]) if list.empty?
192
+ list.merge(_ = [:class, :module, :interface]) if list.empty?
176
193
 
177
- loader = EnvironmentLoader.new()
178
- options.setup(loader)
194
+ loader = options.loader()
179
195
 
180
196
  env = Environment.from_loader(loader).resolve_type_names
181
197
 
@@ -202,6 +218,7 @@ EOB
202
218
  end
203
219
 
204
220
  def run_ancestors(args, options)
221
+ # @type var kind: :instance | :singleton
205
222
  kind = :instance
206
223
 
207
224
  OptionParser.new do |opts|
@@ -221,13 +238,12 @@ EOU
221
238
  opts.on("--singleton", "Ancestors of singleton of the given type_name") { kind = :singleton }
222
239
  end.order!(args)
223
240
 
224
- loader = EnvironmentLoader.new()
225
- options.setup(loader)
241
+ loader = options.loader()
226
242
 
227
243
  env = Environment.from_loader(loader).resolve_type_names
228
244
 
229
245
  builder = DefinitionBuilder.new(env: env)
230
- type_name = parse_type_name(args[0]).absolute!
246
+ type_name = TypeName(args[0]).absolute!
231
247
 
232
248
  if env.class_decls.key?(type_name)
233
249
  ancestors = case kind
@@ -235,6 +251,8 @@ EOU
235
251
  builder.instance_ancestors(type_name)
236
252
  when :singleton
237
253
  builder.singleton_ancestors(type_name)
254
+ else
255
+ raise
238
256
  end
239
257
 
240
258
  ancestors.ancestors.each do |ancestor|
@@ -255,6 +273,7 @@ EOU
255
273
  end
256
274
 
257
275
  def run_methods(args, options)
276
+ # @type var kind: :instance | :singleton
258
277
  kind = :instance
259
278
  inherit = true
260
279
 
@@ -281,13 +300,12 @@ EOU
281
300
  return
282
301
  end
283
302
 
284
- loader = EnvironmentLoader.new()
285
- options.setup(loader)
303
+ loader = options.loader()
286
304
 
287
305
  env = Environment.from_loader(loader).resolve_type_names
288
306
 
289
307
  builder = DefinitionBuilder.new(env: env)
290
- type_name = parse_type_name(args[0]).absolute!
308
+ type_name = TypeName(args[0]).absolute!
291
309
 
292
310
  if env.class_decls.key?(type_name)
293
311
  definition = case kind
@@ -295,6 +313,8 @@ EOU
295
313
  builder.build_instance(type_name)
296
314
  when :singleton
297
315
  builder.build_singleton(type_name)
316
+ else
317
+ raise
298
318
  end
299
319
 
300
320
  definition.methods.keys.sort.each do |name|
@@ -309,6 +329,7 @@ EOU
309
329
  end
310
330
 
311
331
  def run_method(args, options)
332
+ # @type var kind: :instance | :singleton
312
333
  kind = :instance
313
334
 
314
335
  OptionParser.new do |opts|
@@ -333,13 +354,11 @@ EOU
333
354
  return
334
355
  end
335
356
 
336
- loader = EnvironmentLoader.new()
337
- options.setup(loader)
338
-
357
+ loader = options.loader()
339
358
  env = Environment.from_loader(loader).resolve_type_names
340
359
 
341
360
  builder = DefinitionBuilder.new(env: env)
342
- type_name = parse_type_name(args[0]).absolute!
361
+ type_name = TypeName(args[0]).absolute!
343
362
  method_name = args[1].to_sym
344
363
 
345
364
  unless env.class_decls.key?(type_name)
@@ -352,6 +371,8 @@ EOU
352
371
  builder.build_instance(type_name)
353
372
  when :singleton
354
373
  builder.build_singleton(type_name)
374
+ else
375
+ raise
355
376
  end
356
377
 
357
378
  method = definition.methods[method_name]
@@ -391,10 +412,7 @@ EOU
391
412
  end
392
413
  end.parse!(args)
393
414
 
394
- loader = EnvironmentLoader.new()
395
-
396
- options.setup(loader)
397
-
415
+ loader = options.loader()
398
416
  env = Environment.from_loader(loader).resolve_type_names
399
417
 
400
418
  builder = DefinitionBuilder.new(env: env)
@@ -437,6 +455,7 @@ EOU
437
455
  end
438
456
 
439
457
  def run_constant(args, options)
458
+ # @type var context: String?
440
459
  context = nil
441
460
 
442
461
  OptionParser.new do |opts|
@@ -461,10 +480,7 @@ EOU
461
480
  return
462
481
  end
463
482
 
464
- loader = EnvironmentLoader.new()
465
-
466
- options.setup(loader)
467
-
483
+ loader = options.loader()
468
484
  env = Environment.from_loader(loader).resolve_type_names
469
485
 
470
486
  builder = DefinitionBuilder.new(env: env)
@@ -498,11 +514,10 @@ Examples:
498
514
  EOU
499
515
  end.parse!(args)
500
516
 
501
- loader = EnvironmentLoader.new()
502
-
503
- options.setup(loader)
517
+ loader = options.loader()
504
518
 
505
519
  kind_of = -> (path) {
520
+ # @type var path: Pathname
506
521
  case
507
522
  when path.file?
508
523
  "file"
@@ -515,19 +530,14 @@ EOU
515
530
  end
516
531
  }
517
532
 
518
- if loader.stdlib_root
519
- path = loader.stdlib_root
520
- stdout.puts "#{path}/builtin (#{kind_of[path]}, stdlib)"
521
- end
522
-
523
- loader.paths.each do |path|
524
- case path
533
+ loader.each_dir do |source, dir|
534
+ case source
535
+ when :core
536
+ stdout.puts "#{dir} (#{kind_of[dir]}, core)"
525
537
  when Pathname
526
- stdout.puts "#{path} (#{kind_of[path]})"
527
- when EnvironmentLoader::GemPath
528
- stdout.puts "#{path.path} (#{kind_of[path.path]}, gem, name=#{path.name}, version=#{path.version})"
529
- when EnvironmentLoader::LibraryPath
530
- stdout.puts "#{path.path} (#{kind_of[path.path]}, library, name=#{path.name})"
538
+ stdout.puts "#{dir} (#{kind_of[dir]})"
539
+ when EnvironmentLoader::Library
540
+ stdout.puts "#{dir} (#{kind_of[dir]}, library, name=#{source.name})"
531
541
  end
532
542
  end
533
543
  end
@@ -573,10 +583,7 @@ EOU
573
583
  end
574
584
  end.parse!(args)
575
585
 
576
- loader = EnvironmentLoader.new()
577
-
578
- options.setup(loader)
579
-
586
+ loader = options.loader()
580
587
  env = Environment.from_loader(loader).resolve_type_names
581
588
 
582
589
  require_libs.each do |lib|
@@ -659,7 +666,6 @@ EOU
659
666
 
660
667
  def run_vendor(args, options)
661
668
  clean = false
662
- vendor_stdlib = false
663
669
  vendor_dir = Pathname("vendor/sigs")
664
670
 
665
671
  OptionParser.new do |opts|
@@ -682,10 +688,6 @@ Options:
682
688
  clean = v
683
689
  end
684
690
 
685
- opts.on("--[no-]stdlib", "Vendor stdlib signatures or not (default: no)") do |v|
686
- vendor_stdlib = v
687
- end
688
-
689
691
  opts.on("--vendor-dir [DIR]", "Specify the directory for vendored signatures (default: vendor/sigs)") do |path|
690
692
  vendor_dir = Pathname(path)
691
693
  end
@@ -693,28 +695,26 @@ Options:
693
695
 
694
696
  stdout.puts "Vendoring signatures to #{vendor_dir}..."
695
697
 
696
- vendorer = Vendorer.new(vendor_dir: vendor_dir)
698
+ loader = options.loader()
697
699
 
698
- if clean
699
- stdout.puts " Deleting #{vendor_dir}..."
700
- vendorer.clean!
701
- end
700
+ args.each do |gem|
701
+ name, version = gem.split(/:/, 2)
702
+
703
+ next unless name
702
704
 
703
- if vendor_stdlib
704
- stdout.puts " Vendoring standard libraries..."
705
- vendorer.stdlib!
705
+ stdout.puts " Loading library: #{name}, version=#{version}..."
706
+ loader.add(library: name, version: version)
706
707
  end
707
708
 
708
- args.each do |gem|
709
- name, version = EnvironmentLoader.parse_library(gem)
709
+ vendorer = Vendorer.new(vendor_dir: vendor_dir, loader: loader)
710
710
 
711
- unless EnvironmentLoader.gem_sig_path(name, version)
712
- stdout.puts " ⚠️ Cannot find rubygem: name=#{name}, version=#{version} 🚨"
713
- else
714
- stdout.puts " Vendoring gem: name=#{name}, version=#{version}..."
715
- vendorer.gem!(name, version)
716
- end
711
+ if clean
712
+ stdout.puts " Deleting #{vendor_dir}..."
713
+ vendorer.clean!
717
714
  end
715
+
716
+ stdout.puts " Copying RBS files..."
717
+ vendorer.copy!
718
718
  end
719
719
 
720
720
  def run_parse(args, options)
@@ -730,20 +730,20 @@ Examples:
730
730
  EOB
731
731
  end.parse!(args)
732
732
 
733
- loader = EnvironmentLoader.new()
733
+ loader = options.loader()
734
734
 
735
735
  syntax_error = false
736
736
  args.each do |path|
737
737
  path = Pathname(path)
738
- loader.each_signature(path) do |sig_path|
739
- Parser.parse_signature(sig_path.read)
738
+ loader.each_file(path, skip_hidden: false, immediate: true) do |file_path|
739
+ Parser.parse_signature(file_path.read)
740
740
  rescue RBS::Parser::SyntaxError => ex
741
741
  loc = ex.error_value.location
742
- stdout.puts "#{sig_path}:#{loc.start_line}:#{loc.start_column}: parse error on value: (#{ex.token_str})"
742
+ stdout.puts "#{file_path}:#{loc.start_line}:#{loc.start_column}: parse error on value: (#{ex.token_str})"
743
743
  syntax_error = true
744
744
  rescue RBS::Parser::SemanticsError => ex
745
745
  loc = ex.location
746
- stdout.puts "#{sig_path}:#{loc.start_line}:#{loc.start_column}: #{ex.original_message}"
746
+ stdout.puts "#{file_path}:#{loc.start_line}:#{loc.start_column}: #{ex.original_message}"
747
747
  syntax_error = true
748
748
  end
749
749
  end
@@ -751,22 +751,24 @@ Examples:
751
751
  exit 1 if syntax_error
752
752
  end
753
753
 
754
- def parse_type_name(string)
755
- Namespace.parse(string).yield_self do |namespace|
756
- last = namespace.path.last
757
- TypeName.new(name: last, namespace: namespace.parent)
758
- end
759
- end
760
-
761
754
  def test_opt options
762
- opt_string = options.dirs.map { |dir| "-I #{Shellwords.escape(dir)}"}.concat(options.libs.map { |lib| "-r#{Shellwords.escape(lib)}"}).join(' ')
763
- opt_string.empty? ? nil : opt_string
755
+ opts = []
756
+
757
+ opts.push(*options.repos.map {|dir| "--repo #{Shellwords.escape(dir)}"})
758
+ opts.push(*options.dirs.map {|dir| "-I #{Shellwords.escape(dir)}"})
759
+ opts.push(*options.libs.map {|lib| "-r#{Shellwords.escape(lib)}"})
760
+
761
+ opts.empty? ? nil : opts.join(" ")
764
762
  end
765
763
 
766
764
  def run_test(args, options)
765
+ # @type var unchecked_classes: Array[String]
767
766
  unchecked_classes = []
767
+ # @type var targets: Array[String]
768
768
  targets = []
769
+ # @type var sample_size: String?
769
770
  sample_size = nil
771
+ # @type var double_suite: String?
770
772
  double_suite = nil
771
773
 
772
774
  (opts = OptionParser.new do |opts|
@@ -796,7 +798,6 @@ EOB
796
798
  opts.on("--double-suite DOUBLE_SUITE", "Sets the double suite in use (currently supported: rspec | minitest)") do |suite|
797
799
  double_suite = suite
798
800
  end
799
-
800
801
  end).order!(args)
801
802
 
802
803
  if args.length.zero?
@@ -804,6 +805,7 @@ EOB
804
805
  exit 1
805
806
  end
806
807
 
808
+ # @type var env_hash: Hash[String, String?]
807
809
  env_hash = {
808
810
  'RUBYOPT' => "#{ENV['RUBYOPT']} -rrbs/test/setup",
809
811
  'RBS_TEST_OPT' => test_opt(options),