rbs 3.0.0.dev.2 → 3.0.0.dev.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/comments.yml +2 -1
  3. data/.github/workflows/ruby.yml +4 -0
  4. data/Gemfile.lock +11 -11
  5. data/Rakefile +2 -2
  6. data/Steepfile +1 -1
  7. data/core/array.rbs +573 -423
  8. data/core/basic_object.rbs +11 -39
  9. data/core/binding.rbs +1 -1
  10. data/core/builtin.rbs +8 -0
  11. data/core/class.rbs +37 -0
  12. data/core/comparable.rbs +7 -18
  13. data/core/complex.rbs +2 -2
  14. data/core/data.rbs +419 -0
  15. data/core/dir.rbs +52 -104
  16. data/core/encoding.rbs +22 -181
  17. data/core/enumerable.rbs +212 -175
  18. data/core/enumerator/product.rbs +96 -0
  19. data/core/enumerator.rbs +57 -8
  20. data/core/errors.rbs +8 -2
  21. data/core/exception.rbs +41 -0
  22. data/core/fiber.rbs +95 -12
  23. data/core/file.rbs +840 -275
  24. data/core/file_test.rbs +34 -19
  25. data/core/float.rbs +40 -96
  26. data/core/gc.rbs +15 -3
  27. data/core/hash.rbs +113 -175
  28. data/core/integer.rbs +85 -145
  29. data/core/io/buffer.rbs +187 -60
  30. data/core/io/wait.rbs +28 -16
  31. data/core/io.rbs +1859 -1389
  32. data/core/kernel.rbs +525 -961
  33. data/core/match_data.rbs +306 -142
  34. data/core/math.rbs +506 -234
  35. data/core/method.rbs +0 -24
  36. data/core/module.rbs +110 -17
  37. data/core/nil_class.rbs +2 -0
  38. data/core/numeric.rbs +76 -144
  39. data/core/object.rbs +88 -212
  40. data/core/proc.rbs +17 -5
  41. data/core/process.rbs +22 -5
  42. data/core/ractor.rbs +1 -1
  43. data/core/random.rbs +20 -3
  44. data/core/range.rbs +91 -89
  45. data/core/rational.rbs +2 -3
  46. data/core/rbs/unnamed/argf.rbs +177 -120
  47. data/core/rbs/unnamed/env_class.rbs +89 -163
  48. data/core/rbs/unnamed/random.rbs +36 -12
  49. data/core/refinement.rbs +8 -0
  50. data/core/regexp.rbs +462 -272
  51. data/core/ruby_vm.rbs +210 -0
  52. data/{stdlib/set/0 → core}/set.rbs +43 -47
  53. data/core/string.rbs +1403 -1332
  54. data/core/string_io.rbs +191 -107
  55. data/core/struct.rbs +67 -63
  56. data/core/symbol.rbs +187 -201
  57. data/core/thread.rbs +40 -35
  58. data/core/time.rbs +902 -826
  59. data/core/trace_point.rbs +55 -6
  60. data/core/unbound_method.rbs +48 -24
  61. data/docs/collection.md +4 -0
  62. data/docs/syntax.md +55 -0
  63. data/ext/rbs_extension/parser.c +5 -6
  64. data/lib/rbs/cli.rb +6 -1
  65. data/lib/rbs/collection/cleaner.rb +8 -1
  66. data/lib/rbs/collection/config/lockfile.rb +3 -1
  67. data/lib/rbs/collection/config/lockfile_generator.rb +16 -14
  68. data/lib/rbs/collection/config.rb +1 -1
  69. data/lib/rbs/collection/sources/git.rb +9 -2
  70. data/lib/rbs/collection/sources/local.rb +79 -0
  71. data/lib/rbs/collection/sources.rb +8 -1
  72. data/lib/rbs/environment.rb +6 -5
  73. data/lib/rbs/environment_loader.rb +3 -2
  74. data/lib/rbs/errors.rb +18 -0
  75. data/lib/rbs/locator.rb +26 -7
  76. data/lib/rbs/sorter.rb +2 -2
  77. data/lib/rbs/version.rb +1 -1
  78. data/sig/collection/sources.rbs +32 -3
  79. data/sig/environment.rbs +2 -3
  80. data/sig/locator.rbs +14 -2
  81. data/sig/shims/{abstract_syntax_tree.rbs → _abstract_syntax_tree.rbs} +0 -0
  82. data/stdlib/bigdecimal/0/big_decimal.rbs +16 -13
  83. data/stdlib/cgi/0/core.rbs +16 -0
  84. data/stdlib/coverage/0/coverage.rbs +50 -8
  85. data/stdlib/csv/0/csv.rbs +1 -1
  86. data/stdlib/date/0/date.rbs +856 -726
  87. data/stdlib/date/0/date_time.rbs +83 -210
  88. data/stdlib/erb/0/erb.rbs +13 -36
  89. data/stdlib/etc/0/etc.rbs +127 -20
  90. data/stdlib/fileutils/0/fileutils.rbs +1290 -381
  91. data/stdlib/logger/0/logger.rbs +466 -316
  92. data/stdlib/net-http/0/net-http.rbs +2211 -534
  93. data/stdlib/nkf/0/nkf.rbs +5 -5
  94. data/stdlib/objspace/0/objspace.rbs +31 -14
  95. data/stdlib/openssl/0/openssl.rbs +11 -7
  96. data/stdlib/optparse/0/optparse.rbs +20 -17
  97. data/stdlib/pathname/0/pathname.rbs +21 -4
  98. data/stdlib/pstore/0/pstore.rbs +378 -154
  99. data/stdlib/pty/0/pty.rbs +24 -8
  100. data/stdlib/ripper/0/ripper.rbs +1650 -0
  101. data/stdlib/socket/0/addrinfo.rbs +9 -15
  102. data/stdlib/socket/0/socket.rbs +36 -3
  103. data/stdlib/strscan/0/string_scanner.rbs +7 -5
  104. data/stdlib/tempfile/0/tempfile.rbs +104 -44
  105. data/stdlib/time/0/time.rbs +2 -2
  106. data/stdlib/uri/0/file.rbs +5 -0
  107. data/stdlib/uri/0/generic.rbs +2 -2
  108. data/stdlib/yaml/0/yaml.rbs +2 -2
  109. data/stdlib/zlib/0/zlib.rbs +1 -1
  110. metadata +8 -6
  111. data/core/deprecated.rbs +0 -9
  112. data/sig/shims/ripper.rbs +0 -8
data/core/trace_point.rbs CHANGED
@@ -114,7 +114,7 @@ class TracePoint < Object
114
114
 
115
115
  # <!--
116
116
  # rdoc-file=trace_point.rb
117
- # - TracePoint.allow_reentry
117
+ # - TracePoint.allow_reentry { block }
118
118
  # -->
119
119
  # In general, while a TracePoint callback is running, other registered callbacks
120
120
  # are not called to avoid confusion by reentrance. This method allows the
@@ -124,6 +124,54 @@ class TracePoint < Object
124
124
  # If this method is called when the reentrance is already allowed, it raises a
125
125
  # RuntimeError.
126
126
  #
127
+ # **Example:**
128
+ #
129
+ # # Without reentry
130
+ # # ---------------
131
+ #
132
+ # line_handler = TracePoint.new(:line) do |tp|
133
+ # next if tp.path != __FILE__ # only work in this file
134
+ # puts "Line handler"
135
+ # binding.eval("class C; end")
136
+ # end.enable
137
+ #
138
+ # class_handler = TracePoint.new(:class) do |tp|
139
+ # puts "Class handler"
140
+ # end.enable
141
+ #
142
+ # class B
143
+ # end
144
+ #
145
+ # # This script will print "Class handler" only once: when inside :line
146
+ # # handler, all other handlers are ignored
147
+ #
148
+ # # With reentry
149
+ # # ------------
150
+ #
151
+ # line_handler = TracePoint.new(:line) do |tp|
152
+ # next if tp.path != __FILE__ # only work in this file
153
+ # next if (__LINE__..__LINE__+3).cover?(tp.lineno) # don't be invoked from itself
154
+ # puts "Line handler"
155
+ # TracePoint.allow_reentry { binding.eval("class C; end") }
156
+ # end.enable
157
+ #
158
+ # class_handler = TracePoint.new(:class) do |tp|
159
+ # puts "Class handler"
160
+ # end.enable
161
+ #
162
+ # class B
163
+ # end
164
+ #
165
+ # # This wil print "Class handler" twice: inside allow_reentry block in :line
166
+ # # handler, other handlers are enabled.
167
+ #
168
+ # Note that the example shows the principal effect of the method, but its
169
+ # practical usage is for debugging libraries that sometimes require other
170
+ # libraries hooks to not be affected by debugger being inside trace point
171
+ # handling. Precautions should be taken against infinite recursion in this case
172
+ # (note that we needed to filter out calls by itself from :line handler,
173
+ # otherwise it will call itself infinitely).
174
+ #
127
175
  def self.allow_reentry: () { () -> void } -> void
128
176
 
129
177
  # <!--
@@ -163,7 +211,7 @@ class TracePoint < Object
163
211
  # binding of the nearest Ruby method calling the C method, since C methods
164
212
  # themselves do not have bindings.
165
213
  #
166
- def binding: () -> Binding
214
+ def binding: () -> Binding?
167
215
 
168
216
  # <!--
169
217
  # rdoc-file=trace_point.rb
@@ -251,7 +299,7 @@ class TracePoint < Object
251
299
  # <!--
252
300
  # rdoc-file=trace_point.rb
253
301
  # - trace.enable(target: nil, target_line: nil, target_thread: nil) -> true or false
254
- # - trace.enable(target: nil, target_line: nil, target_thread: nil) { block } -> obj
302
+ # - trace.enable(target: nil, target_line: nil, target_thread: :default) { block } -> obj
255
303
  # -->
256
304
  # Activates the trace.
257
305
  #
@@ -264,15 +312,16 @@ class TracePoint < Object
264
312
  # trace.enable #=> true (previous state)
265
313
  # # trace is still enabled
266
314
  #
267
- # If a block is given, the trace will only be enabled within the scope of the
268
- # block.
315
+ # If a block is given, the trace will only be enabled during the block call. If
316
+ # target and target_line are both nil, then target_thread will default to the
317
+ # current thread if a block is given.
269
318
  #
270
319
  # trace.enabled?
271
320
  # #=> false
272
321
  #
273
322
  # trace.enable do
274
323
  # trace.enabled?
275
- # # only enabled for this block
324
+ # # only enabled for this block and thread
276
325
  # end
277
326
  #
278
327
  # trace.enabled?
@@ -46,6 +46,22 @@
46
46
  # um.bind(t).call #=> :original
47
47
  #
48
48
  class UnboundMethod
49
+ # <!--
50
+ # rdoc-file=proc.c
51
+ # - meth.eql?(other_meth) -> true or false
52
+ # - meth == other_meth -> true or false
53
+ # -->
54
+ # Two unbound method objects are equal if they refer to the same method
55
+ # definition.
56
+ #
57
+ # Array.instance_method(:each_slice) == Enumerable.instance_method(:each_slice)
58
+ # #=> true
59
+ #
60
+ # Array.instance_method(:sum) == Enumerable.instance_method(:sum)
61
+ # #=> false, Array redefines the method for efficiency
62
+ #
63
+ def ==: (untyped) -> bool
64
+
49
65
  # <!--
50
66
  # rdoc-file=proc.c
51
67
  # - method.clone -> new_method
@@ -141,6 +157,38 @@ class UnboundMethod
141
157
  #
142
158
  def bind: (untyped obj) -> Method
143
159
 
160
+ # <!--
161
+ # rdoc-file=proc.c
162
+ # - meth.to_s -> string
163
+ # - meth.inspect -> string
164
+ # -->
165
+ # Returns a human-readable description of the underlying method.
166
+ #
167
+ # "cat".method(:count).inspect #=> "#<Method: String#count(*)>"
168
+ # (1..3).method(:map).inspect #=> "#<Method: Range(Enumerable)#map()>"
169
+ #
170
+ # In the latter case, the method description includes the "owner" of the
171
+ # original method (`Enumerable` module, which is included into `Range`).
172
+ #
173
+ # `inspect` also provides, when possible, method argument names (call sequence)
174
+ # and source location.
175
+ #
176
+ # require 'net/http'
177
+ # Net::HTTP.method(:get).inspect
178
+ # #=> "#<Method: Net::HTTP.get(uri_or_host, path=..., port=...) <skip>/lib/ruby/2.7.0/net/http.rb:457>"
179
+ #
180
+ # `...` in argument definition means argument is optional (has some default
181
+ # value).
182
+ #
183
+ # For methods defined in C (language core and extensions), location and argument
184
+ # names can't be extracted, and only generic information is provided in form of
185
+ # `*` (any number of arguments) or `_` (some positional argument).
186
+ #
187
+ # "cat".method(:count).inspect #=> "#<Method: String#count(*)>"
188
+ # "cat".method(:+).inspect #=> "#<Method: String#+(_)>""
189
+ #
190
+ def inspect: () -> String
191
+
144
192
  # <!--
145
193
  # rdoc-file=proc.c
146
194
  # - meth.name -> symbol
@@ -188,30 +236,6 @@ class UnboundMethod
188
236
  def parameters: () -> ::Array[[ Symbol, Symbol ]]
189
237
  | () -> ::Array[[ Symbol ]]
190
238
 
191
- # <!--
192
- # rdoc-file=proc.c
193
- # - meth.private? -> true or false
194
- # -->
195
- # Returns whether the method is private.
196
- #
197
- def private?: () -> bool
198
-
199
- # <!--
200
- # rdoc-file=proc.c
201
- # - meth.protected? -> true or false
202
- # -->
203
- # Returns whether the method is protected.
204
- #
205
- def protected?: () -> bool
206
-
207
- # <!--
208
- # rdoc-file=proc.c
209
- # - meth.public? -> true or false
210
- # -->
211
- # Returns whether the method is public.
212
- #
213
- def public?: () -> bool
214
-
215
239
  # <!--
216
240
  # rdoc-file=proc.c
217
241
  # - meth.source_location -> [String, Integer]
data/docs/collection.md CHANGED
@@ -79,6 +79,10 @@ sources:
79
79
  revision: main
80
80
  repo_dir: gems
81
81
 
82
+ # You can also add a local path as a collection source optionaly.
83
+ - type: local
84
+ path: path/to/local/dir
85
+
82
86
  # A directory to install the downloaded RBSs
83
87
  path: .gem_rbs_collection
84
88
 
data/docs/syntax.md CHANGED
@@ -501,6 +501,8 @@ private alias foo bar # Syntax error
501
501
  ```markdown
502
502
  _decl_ ::= _class-decl_ # Class declaration
503
503
  | _module-decl_ # Module declaration
504
+ | _class-alias-decl_ # Class alias declaration
505
+ | _module-alias-decl_ # Module alias declaration
504
506
  | _interface-decl_ # Interface declaration
505
507
  | _type-alias-decl_ # Type alias declaration
506
508
  | _const-decl_ # Constant declaration
@@ -512,6 +514,10 @@ _class-decl_ ::= `class` _class-name_ _module-type-parameters_ _members_ `end`
512
514
  _module-decl_ ::= `module` _module-name_ _module-type-parameters_ _members_ `end`
513
515
  | `module` _module-name_ _module-type-parameters_ `:` _module-self-types_ _members_ `end`
514
516
 
517
+ _class-alias-decl_ ::= `class` _class-name_ `=` _class-name_
518
+
519
+ _module-alias-decl_ ::= `module` _module-name_ `=` _module-name_
520
+
515
521
  _module-self-types_ ::= _class-name_ _type-arguments_ `,` _module-self-types_ (Class instance)
516
522
  | _interface-name_ _type-arguments_ `,` _module-self-types_ (Interface)
517
523
 
@@ -554,6 +560,32 @@ end
554
560
 
555
561
  The `Enumerable` module above requires `each` method for enumerating objects.
556
562
 
563
+ ### Class/module alias declaration
564
+
565
+ An alias of a class or module can be defined in RBS.
566
+
567
+ ```rbs
568
+ module Foo = Kernel
569
+
570
+ class Bar = Array
571
+ ```
572
+
573
+ The syntax defines a class and the definition is equivalent to the right-hand-side.
574
+
575
+ ```
576
+ class Baz < Bar[String] # Class alias can be inherited
577
+ include Foo # Module alias can be included
578
+ end
579
+ ```
580
+
581
+ This is a definition corresponding to the following Ruby code.
582
+
583
+ ```ruby
584
+ Foo = Kernel
585
+
586
+ Bar = Array
587
+ ```
588
+
557
589
  ### Interface declaration
558
590
 
559
591
  Interface declaration can have parameters but allows only a few of the members.
@@ -696,6 +728,29 @@ type int_printer = PrettyPrint[Integer] # Type error
696
728
 
697
729
  The upper bound must be one of a class instance type, interface type, or class singleton type.
698
730
 
731
+ ### Directives
732
+
733
+ Directives are placed at the top of a file and provides per-file-basis features.
734
+
735
+ ```
736
+ _use-directive_ ::= `use` _use-clauses_
737
+
738
+ _use-clauses_ ::= _use-clause_ `,` ... `,` _use-clause_
739
+
740
+ _use-clause_ ::= _type-name_ # Single use clause
741
+ | _type-name_ `as` _simple-type-name_ # Single use clause with alias
742
+ | _namespace_ # Wildcard use clause
743
+ ```
744
+
745
+ The *use directive* defines relative type names that is an alias of other type names.
746
+ We can use the simple type names if it is declared with *use*.
747
+
748
+ ```
749
+ use RBS::Namespace # => Defines `Namespace`
750
+ use RBS::TypeName as TN # => Defines `TN`
751
+ use RBS::AST::* # => Defines modules under `::RBS::AST::` namespace
752
+ ```
753
+
699
754
  ### Comments
700
755
 
701
756
  You can write single line comments. Comments must be on their own line. Comments can lead with whitespace.
@@ -2724,13 +2724,12 @@ VALUE parse_signature(parserstate *state) {
2724
2724
  VALUE dirs = rb_ary_new();
2725
2725
  VALUE decls = rb_ary_new();
2726
2726
 
2727
+ while (state->next_token.type == kUSE) {
2728
+ rb_ary_push(dirs, parse_use_directive(state));
2729
+ }
2730
+
2727
2731
  while (state->next_token.type != pEOF) {
2728
- if (state->next_token.type == kUSE) {
2729
- VALUE use = parse_use_directive(state);
2730
- rb_ary_push(dirs, use);
2731
- } else {
2732
- rb_ary_push(decls, parse_decl(state));
2733
- }
2732
+ rb_ary_push(decls, parse_decl(state));
2734
2733
  }
2735
2734
 
2736
2735
  VALUE ret = rb_ary_new();
data/lib/rbs/cli.rb CHANGED
@@ -1076,11 +1076,16 @@ EOB
1076
1076
  config_path.write(<<~'YAML')
1077
1077
  # Download sources
1078
1078
  sources:
1079
- - name: ruby/gem_rbs_collection
1079
+ - type: git
1080
+ name: ruby/gem_rbs_collection
1080
1081
  remote: https://github.com/ruby/gem_rbs_collection.git
1081
1082
  revision: main
1082
1083
  repo_dir: gems
1083
1084
 
1085
+ # You can specify local directories as sources also.
1086
+ # - type: local
1087
+ # path: path/to/your/local/repository
1088
+
1084
1089
  # A directory to install the downloaded RBSs
1085
1090
  path: .gem_rbs_collection
1086
1091
 
@@ -16,7 +16,14 @@ module RBS
16
16
  version or raise
17
17
  next if needed? gem_name, version
18
18
 
19
- FileUtils.remove_entry_secure(dir.to_s)
19
+ case
20
+ when dir.symlink?
21
+ dir.unlink
22
+ when dir.directory?
23
+ FileUtils.remove_entry_secure(dir.to_s)
24
+ else
25
+ raise
26
+ end
20
27
  end
21
28
  end
22
29
 
@@ -75,7 +75,7 @@ module RBS
75
75
  if gems = data["gems"]
76
76
  gems.each do |gem|
77
77
  src = gem["source"]
78
- source = Sources.from_config_entry(src)
78
+ source = Sources.from_config_entry(src, base_directory: lockfile_path.dirname)
79
79
  lockfile.gems[gem["name"]] = {
80
80
  name: gem["name"],
81
81
  version: gem["version"],
@@ -106,6 +106,8 @@ module RBS
106
106
  meta_path = fullpath.join(gem[:name], gem[:version], Sources::Git::METADATA_FILENAME)
107
107
  raise CollectionNotAvailable unless meta_path.exist?
108
108
  raise CollectionNotAvailable unless library_data(gem) == YAML.load(meta_path.read)
109
+ when Sources::Local
110
+ raise CollectionNotAvailable unless fullpath.join(gem[:name], gem[:version]).symlink?
109
111
  end
110
112
  end
111
113
  end
@@ -105,27 +105,29 @@ module RBS
105
105
  unless locked
106
106
  source =
107
107
  if src_data
108
- Sources.from_config_entry(src_data)
108
+ Sources.from_config_entry(src_data, base_directory: config.config_path.dirname)
109
109
  else
110
- find_source(name: name) or return
110
+ find_source(name: name)
111
111
  end
112
112
 
113
- installed_version = version
114
- best_version = find_best_version(version: installed_version, versions: source.versions(name))
113
+ if source
114
+ installed_version = version
115
+ best_version = find_best_version(version: installed_version, versions: source.versions(name))
115
116
 
116
- locked = {
117
- name: name,
118
- version: best_version.to_s,
119
- source: source,
120
- }
117
+ locked = {
118
+ name: name,
119
+ version: best_version.to_s,
120
+ source: source,
121
+ }
122
+ end
121
123
  end
122
124
 
123
- locked or raise
124
-
125
- lockfile.gems[name] = locked
125
+ if locked
126
+ lockfile.gems[name] = locked
126
127
 
127
- locked[:source].dependencies_of(locked[:name], locked[:version])&.each do |dep|
128
- assign_stdlib(name: dep["name"], from_gem: name)
128
+ locked[:source].dependencies_of(locked[:name], locked[:version])&.each do |dep|
129
+ assign_stdlib(name: dep["name"], from_gem: name)
130
+ end
129
131
  end
130
132
 
131
133
  gem_hash[name].dependencies.each do |dep|
@@ -66,7 +66,7 @@ module RBS
66
66
  def sources
67
67
  @sources ||= (
68
68
  @data['sources']
69
- .map { |c| Sources.from_config_entry(c) }
69
+ .map { |c| Sources.from_config_entry(c, base_directory: @config_path.dirname) }
70
70
  .push(Sources::Stdlib.instance)
71
71
  .push(Sources::Rubygems.instance)
72
72
  )
@@ -45,7 +45,12 @@ module RBS
45
45
 
46
46
  gem_dir = dest.join(name, version)
47
47
 
48
- if gem_dir.directory?
48
+ case
49
+ when gem_dir.symlink?
50
+ stdout.puts "Updating to #{format_config_entry(name, version)} from a local source"
51
+ gem_dir.unlink
52
+ _install(dest: dest, name: name, version: version)
53
+ when gem_dir.directory?
49
54
  prev = load_metadata(dir: gem_dir)
50
55
 
51
56
  if prev == metadata_content(name: name, version: version)
@@ -55,9 +60,11 @@ module RBS
55
60
  FileUtils.remove_entry_secure(gem_dir.to_s)
56
61
  _install(dest: dest, name: name, version: version)
57
62
  end
58
- else
63
+ when !gem_dir.exist?
59
64
  stdout.puts "Installing #{format_config_entry(name, version)}"
60
65
  _install(dest: dest, name: name, version: version)
66
+ else
67
+ raise
61
68
  end
62
69
  end
63
70
 
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBS
4
+ module Collection
5
+ module Sources
6
+ class Local
7
+ include Base
8
+
9
+ attr_reader :path, :full_path
10
+
11
+ def initialize(path:, base_directory:)
12
+ # TODO: resolve relative path from dir of rbs_collection.yaml
13
+ @path = Pathname(path)
14
+ @full_path = base_directory / path
15
+ end
16
+
17
+ def has?(name, version)
18
+ if version
19
+ @full_path.join(name, version).directory?
20
+ else
21
+ not versions(name).empty?
22
+ end
23
+ end
24
+
25
+ def versions(name)
26
+ @full_path.join(name).glob('*/').map { |path| path.basename.to_s }
27
+ end
28
+
29
+ # Create a symlink instead of copying file to refer files in @path.
30
+ # By avoiding copying RBS files, the users do not need re-run `rbs collection install`
31
+ # when the RBS files are updated.
32
+ def install(dest:, name:, version:, stdout:)
33
+ from = @full_path.join(name, version)
34
+ gem_dir = dest.join(name, version)
35
+
36
+ case
37
+ when gem_dir.symlink? && gem_dir.readlink == from
38
+ stdout.puts "Using #{name}:#{version} (#{from})"
39
+ when gem_dir.symlink?
40
+ prev = gem_dir.readlink
41
+ gem_dir.unlink
42
+ _install(from, dest.join(name, version))
43
+ stdout.puts "Updating #{name}:#{version} to #{from} from #{prev}"
44
+ when gem_dir.directory?
45
+ # TODO: Show version of git source
46
+ FileUtils.remove_entry_secure(gem_dir.to_s)
47
+ _install(from, dest.join(name, version))
48
+ stdout.puts "Updating #{name}:#{version} from git source"
49
+ when !gem_dir.exist?
50
+ _install(from, dest.join(name, version))
51
+ stdout.puts "Installing #{name}:#{version} (#{from})"
52
+ else
53
+ raise
54
+ end
55
+ end
56
+
57
+ private def _install(src, dst)
58
+ dst.dirname.mkpath
59
+ File.symlink(src, dst)
60
+ end
61
+
62
+ def manifest_of(name, version)
63
+ gem_dir = @full_path.join(name, version)
64
+ raise unless gem_dir.exist?
65
+
66
+ manifest_path = gem_dir.join('manifest.yaml')
67
+ YAML.safe_load(manifest_path.read) if manifest_path.exist?
68
+ end
69
+
70
+ def to_lockfile
71
+ {
72
+ 'type' => 'local',
73
+ 'path' => @path.to_s,
74
+ }
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -4,11 +4,12 @@ require_relative './sources/base'
4
4
  require_relative './sources/git'
5
5
  require_relative './sources/stdlib'
6
6
  require_relative './sources/rubygems'
7
+ require_relative './sources/local'
7
8
 
8
9
  module RBS
9
10
  module Collection
10
11
  module Sources
11
- def self.from_config_entry(source_entry)
12
+ def self.from_config_entry(source_entry, base_directory:)
12
13
  case source_entry['type']
13
14
  when 'git', nil # git source by default
14
15
  # @type var source_entry: Git::source_entry
@@ -18,6 +19,12 @@ module RBS
18
19
  remote: source_entry["remote"],
19
20
  repo_dir: source_entry["repo_dir"]
20
21
  )
22
+ when 'local'
23
+ # @type var source_entry: Local::source_entry
24
+ Local.new(
25
+ path: source_entry['path'],
26
+ base_directory: base_directory,
27
+ )
21
28
  when 'stdlib'
22
29
  Stdlib.instance
23
30
  when 'rubygems'
@@ -773,13 +773,14 @@ module RBS
773
773
  hash
774
774
  end
775
775
 
776
- def reject
776
+ def unload(buffers)
777
777
  env = Environment.new
778
778
 
779
- declarations.each do |decl|
780
- unless yield(decl)
781
- env << decl
782
- end
779
+ buffers_decls.each do |buf, decls|
780
+ next if buffers.include?(buf)
781
+
782
+ dirs = buffer_directives.fetch(buf)
783
+ env.add_signature(buffer: buf, directives: dirs, decls: decls)
783
784
  end
784
785
 
785
786
  env
@@ -47,8 +47,9 @@ module RBS
47
47
  when path
48
48
  dirs << path
49
49
  when library
50
- if library == 'rubygems'
51
- RBS.logger.warn '`rubygems` has been moved to core library, so it is always loaded. Remove explicit loading `rubygems`'
50
+ case library
51
+ when 'rubygems', 'set'
52
+ RBS.logger.warn "`#{library}` has been moved to core library, so it is always loaded. Remove explicit loading `#{library}`"
52
53
  return
53
54
  end
54
55
 
data/lib/rbs/errors.rb CHANGED
@@ -20,7 +20,25 @@ module RBS
20
20
  class LoadingError < BaseError; end
21
21
  class DefinitionError < BaseError; end
22
22
 
23
+ module DetailedMessageable
24
+ def detailed_message(highlight: false, **)
25
+ indent = " " * location.start_column
26
+ marker = "^" * (location.end_column - location.start_column)
27
+
28
+ io = StringIO.new
29
+ io.puts super
30
+ io.puts
31
+ io.print "\e[1m" if highlight
32
+ io.puts " #{location.buffer.lines[location.end_line - 1]}"
33
+ io.puts " #{indent}#{marker}"
34
+ io.print "\e[m" if highlight
35
+ io.string
36
+ end
37
+ end
38
+
23
39
  class ParsingError < BaseError
40
+ include DetailedMessageable
41
+
24
42
  attr_reader :location
25
43
  attr_reader :error_message
26
44
  attr_reader :token_type
data/lib/rbs/locator.rb CHANGED
@@ -2,21 +2,24 @@
2
2
 
3
3
  module RBS
4
4
  class Locator
5
- attr_reader :decls
5
+ attr_reader :decls, :dirs, :buffer
6
6
 
7
- def initialize(decls:)
7
+ def initialize(buffer:, dirs:, decls:)
8
+ @buffer = buffer
9
+ @dirs = dirs
8
10
  @decls = decls
9
11
  end
10
12
 
11
- def buffer
12
- decls[0].location&.buffer or raise
13
- end
14
-
15
13
  def find(line:, column:)
16
14
  pos = buffer.loc_to_pos([line, column])
17
15
 
16
+ dirs.each do |dir|
17
+ array = [] #: Array[component]
18
+ find_in_directive(pos, dir, array) and return array
19
+ end
20
+
18
21
  decls.each do |decl|
19
- array = []
22
+ array = [] #: Array[component]
20
23
  find_in_decl(pos, decl: decl, array: array) and return array
21
24
  end
22
25
 
@@ -36,6 +39,22 @@ module RBS
36
39
  end
37
40
  end
38
41
 
42
+ def find_in_directive(pos, dir, array)
43
+ if test_loc(pos, location: dir.location)
44
+ array.unshift(dir)
45
+
46
+ dir.clauses.each do |clause|
47
+ if test_loc(pos, location: clause.location)
48
+ array.unshift(clause)
49
+ find_in_loc(pos, location: clause.location, array: array)
50
+ return true
51
+ end
52
+ end
53
+ end
54
+
55
+ false
56
+ end
57
+
39
58
  def find_in_decl(pos, decl:, array:)
40
59
  if test_loc(pos, location: decl.location)
41
60
  array.unshift(decl)
data/lib/rbs/sorter.rb CHANGED
@@ -34,7 +34,7 @@ module RBS
34
34
  -3
35
35
  when Declarations::Constant
36
36
  -2
37
- when Declarations::Class, Declarations::Module
37
+ when Declarations::Class, Declarations::Module, Declarations::Interface
38
38
  -1
39
39
  when Members::Include
40
40
  0.0
@@ -102,7 +102,7 @@ module RBS
102
102
  member.name.to_s
103
103
  when Declarations::TypeAlias
104
104
  member.name.to_s
105
- when Declarations::Class, Declarations::Module
105
+ when Declarations::Class, Declarations::Module, Declarations::Interface
106
106
  member.name.to_s
107
107
  else
108
108
  raise