ruby-lsp 0.26.4 → 0.26.6

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp-launcher +4 -3
  4. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +3 -2
  5. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +19 -0
  6. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +33 -27
  7. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +1 -0
  8. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +6 -2
  9. data/lib/ruby_lsp/global_state.rb +65 -33
  10. data/lib/ruby_lsp/listeners/definition.rb +34 -14
  11. data/lib/ruby_lsp/listeners/document_link.rb +1 -6
  12. data/lib/ruby_lsp/listeners/hover.rb +2 -2
  13. data/lib/ruby_lsp/requests/code_action_resolve.rb +33 -11
  14. data/lib/ruby_lsp/requests/code_actions.rb +20 -5
  15. data/lib/ruby_lsp/requests/completion_resolve.rb +8 -6
  16. data/lib/ruby_lsp/requests/support/source_uri.rb +7 -6
  17. data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
  18. data/lib/ruby_lsp/setup_bundler.rb +39 -25
  19. metadata +2 -16
  20. data/lib/ruby_indexer/test/class_variables_test.rb +0 -140
  21. data/lib/ruby_indexer/test/classes_and_modules_test.rb +0 -770
  22. data/lib/ruby_indexer/test/configuration_test.rb +0 -279
  23. data/lib/ruby_indexer/test/constant_test.rb +0 -402
  24. data/lib/ruby_indexer/test/enhancements_test.rb +0 -325
  25. data/lib/ruby_indexer/test/global_variable_test.rb +0 -49
  26. data/lib/ruby_indexer/test/index_test.rb +0 -2276
  27. data/lib/ruby_indexer/test/instance_variables_test.rb +0 -264
  28. data/lib/ruby_indexer/test/method_test.rb +0 -990
  29. data/lib/ruby_indexer/test/prefix_tree_test.rb +0 -150
  30. data/lib/ruby_indexer/test/rbs_indexer_test.rb +0 -381
  31. data/lib/ruby_indexer/test/reference_finder_test.rb +0 -395
  32. data/lib/ruby_indexer/test/test_case.rb +0 -57
  33. data/lib/ruby_indexer/test/uri_test.rb +0 -85
@@ -283,10 +283,10 @@ module RubyLsp
283
283
  content = KEYWORD_DOCS[keyword]
284
284
  return unless content
285
285
 
286
- doc_path = File.join(STATIC_DOCS_PATH, "#{keyword}.md")
286
+ doc_uri = URI::Generic.from_path(path: File.join(STATIC_DOCS_PATH, "#{keyword}.md"))
287
287
 
288
288
  @response_builder.push("```ruby\n#{keyword}\n```", category: :title)
289
- @response_builder.push("[Read more](#{doc_path})", category: :links)
289
+ @response_builder.push("[Read more](#{doc_uri})", category: :links)
290
290
  @response_builder.push(content, category: :documentation)
291
291
  end
292
292
 
@@ -51,20 +51,42 @@ module RubyLsp
51
51
  #: -> (Interface::CodeAction)
52
52
  def switch_block_style
53
53
  source_range = @code_action.dig(:data, :range)
54
- raise EmptySelectionError, "Invalid selection for refactor" if source_range[:start] == source_range[:end]
54
+ if source_range[:start] == source_range[:end]
55
+ block_context = @document.locate_node(
56
+ source_range[:start],
57
+ node_types: [Prism::BlockNode],
58
+ )
59
+ node = block_context.node
60
+ unless node.is_a?(Prism::BlockNode)
61
+ raise InvalidTargetRangeError, "Cursor is not inside a block"
62
+ end
55
63
 
56
- target = @document.locate_first_within_range(
57
- @code_action.dig(:data, :range),
58
- node_types: [Prism::CallNode],
59
- )
64
+ # Find the call node at the block node's start position.
65
+ # This should be the call node whose block the cursor is inside of.
66
+ call_context = RubyDocument.locate(
67
+ @document.ast,
68
+ node.location.cached_start_code_units_offset(@document.code_units_cache),
69
+ node_types: [Prism::CallNode],
70
+ code_units_cache: @document.code_units_cache,
71
+ )
72
+ target = call_context.node
73
+ unless target.is_a?(Prism::CallNode) && target.block == node
74
+ raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
75
+ end
76
+ else
77
+ target = @document.locate_first_within_range(
78
+ @code_action.dig(:data, :range),
79
+ node_types: [Prism::CallNode],
80
+ )
60
81
 
61
- unless target.is_a?(Prism::CallNode)
62
- raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
63
- end
82
+ unless target.is_a?(Prism::CallNode)
83
+ raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
84
+ end
64
85
 
65
- node = target.block
66
- unless node.is_a?(Prism::BlockNode)
67
- raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
86
+ node = target.block
87
+ unless node.is_a?(Prism::BlockNode)
88
+ raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
89
+ end
68
90
  end
69
91
 
70
92
  indentation = " " * target.location.start_column unless node.opening_loc.slice == "do"
@@ -63,12 +63,8 @@ module RubyLsp
63
63
  kind: Constant::CodeActionKind::REFACTOR_EXTRACT,
64
64
  data: { range: @range, uri: @uri.to_s },
65
65
  )
66
- code_actions << Interface::CodeAction.new(
67
- title: TOGGLE_BLOCK_STYLE_TITLE,
68
- kind: Constant::CodeActionKind::REFACTOR_REWRITE,
69
- data: { range: @range, uri: @uri.to_s },
70
- )
71
66
  end
67
+ code_actions.concat(toggle_block_style_action)
72
68
  code_actions.concat(attribute_actions)
73
69
 
74
70
  code_actions
@@ -113,6 +109,25 @@ module RubyLsp
113
109
  ),
114
110
  ]
115
111
  end
112
+
113
+ #: -> Array[Interface::CodeAction]
114
+ def toggle_block_style_action
115
+ if @range[:start] == @range[:end]
116
+ block_context = @document.locate_node(
117
+ @range[:start],
118
+ node_types: [Prism::BlockNode],
119
+ )
120
+ return [] unless block_context.node.is_a?(Prism::BlockNode)
121
+ end
122
+
123
+ [
124
+ Interface::CodeAction.new(
125
+ title: TOGGLE_BLOCK_STYLE_TITLE,
126
+ kind: Constant::CodeActionKind::REFACTOR_REWRITE,
127
+ data: { range: @range, uri: @uri.to_s },
128
+ ),
129
+ ]
130
+ end
116
131
  end
117
132
  end
118
133
  end
@@ -68,10 +68,12 @@ module RubyLsp
68
68
  "[Learn more about guessed types](#{GUESSED_TYPES_URL})"
69
69
  end
70
70
 
71
- @item[:documentation] = Interface::MarkupContent.new(
72
- kind: "markdown",
73
- value: markdown_from_index_entries(label, entries, MAX_DOCUMENTATION_ENTRIES, extra_links: extra_links),
74
- )
71
+ unless @item[:kind] == Constant::CompletionItemKind::FILE
72
+ @item[:documentation] = Interface::MarkupContent.new(
73
+ kind: "markdown",
74
+ value: markdown_from_index_entries(label, entries, MAX_DOCUMENTATION_ENTRIES, extra_links: extra_links),
75
+ )
76
+ end
75
77
 
76
78
  @item
77
79
  end
@@ -84,7 +86,7 @@ module RubyLsp
84
86
  content = KEYWORD_DOCS[keyword]
85
87
 
86
88
  if content
87
- doc_path = File.join(STATIC_DOCS_PATH, "#{keyword}.md")
89
+ doc_uri = URI::Generic.from_path(path: File.join(STATIC_DOCS_PATH, "#{keyword}.md"))
88
90
 
89
91
  @item[:documentation] = Interface::MarkupContent.new(
90
92
  kind: "markdown",
@@ -93,7 +95,7 @@ module RubyLsp
93
95
  #{keyword}
94
96
  ```
95
97
 
96
- [Read more](#{doc_path})
98
+ [Read more](#{doc_uri})
97
99
 
98
100
  #{content}
99
101
  MARKDOWN
@@ -5,6 +5,7 @@ require "uri/file"
5
5
 
6
6
  module URI
7
7
  # Must be kept in sync with the one in Tapioca
8
+ # https://github.com/Shopify/tapioca/blob/main/lib/tapioca/helpers/source_uri.rb
8
9
  class Source < URI::File
9
10
  COMPONENT = [
10
11
  :scheme,
@@ -21,16 +22,14 @@ module URI
21
22
  # have the uri gem in their own bundle and thus not use a compatible version.
22
23
  PARSER = const_defined?(:RFC2396_PARSER) ? RFC2396_PARSER : DEFAULT_PARSER #: RFC2396_Parser
23
24
 
24
- self #: as untyped # rubocop:disable Style/RedundantSelf
25
- .alias_method(:gem_name, :host)
26
- self #: as untyped # rubocop:disable Style/RedundantSelf
27
- .alias_method(:line_number, :fragment)
25
+ alias_method(:gem_name, :host)
26
+ alias_method(:line_number, :fragment)
28
27
 
29
28
  #: String?
30
29
  attr_reader :gem_version
31
30
 
32
31
  class << self
33
- #: (gem_name: String, gem_version: String?, path: String, line_number: String?) -> URI::Source
32
+ #: (gem_name: String, gem_version: String?, path: String, line_number: String?) -> instance
34
33
  def build(gem_name:, gem_version:, path:, line_number:)
35
34
  super(
36
35
  {
@@ -67,12 +66,14 @@ module URI
67
66
 
68
67
  #: -> String
69
68
  def to_s
70
- "source://#{gem_name}/#{gem_version}#{path}##{line_number}"
69
+ "source://#{gem_name}/#{gem_version}/#{path}##{line_number}"
71
70
  end
72
71
 
73
72
  if URI.respond_to?(:register_scheme)
73
+ # Handle URI 0.11.0 and newer https://github.com/ruby/uri/pull/26
74
74
  URI.register_scheme("SOURCE", self)
75
75
  else
76
+ # Fallback for URI <0.11.0
76
77
  @@schemes = @@schemes #: Hash[String, untyped] # rubocop:disable Style/ClassVars
77
78
  @@schemes["SOURCE"] = self
78
79
  end
@@ -5,7 +5,7 @@ def compose(raw_initialize)
5
5
  require_relative "../setup_bundler"
6
6
  require "json"
7
7
  require "uri"
8
- require "ruby_indexer/lib/ruby_indexer/uri"
8
+ require_relative "../../ruby_indexer/lib/ruby_indexer/uri"
9
9
 
10
10
  initialize_request = JSON.parse(raw_initialize, symbolize_names: true)
11
11
  workspace_uri = initialize_request.dig(:params, :workspaceFolders, 0, :uri)
@@ -31,12 +31,16 @@ module RubyLsp
31
31
 
32
32
  FOUR_HOURS = 4 * 60 * 60 #: Integer
33
33
 
34
+ # Gems that should be kept up to date in the composed bundle. When updating, any of these gems that are not
35
+ # already in the user's Gemfile will be updated together.
36
+ GEMS_TO_UPDATE = ["ruby-lsp", "debug", "prism", "rbs"].freeze #: Array[String]
37
+
34
38
  #: (String project_path, **untyped options) -> void
35
39
  def initialize(project_path, **options)
36
40
  @project_path = project_path
37
41
  @branch = options[:branch] #: String?
38
42
  @launcher = options[:launcher] #: bool?
39
- patch_thor_to_print_progress_to_stderr! if @launcher
43
+ force_output_to_stderr! if @launcher
40
44
 
41
45
  # Regular bundle paths
42
46
  @gemfile = begin
@@ -282,14 +286,25 @@ module RubyLsp
282
286
 
283
287
  return update(env) if @needs_update_path.exist?
284
288
 
285
- # The ENV can only be merged after checking if an update is required because we depend on the original value of
286
- # ENV["BUNDLE_GEMFILE"], which gets overridden after the merge
287
289
  FileUtils.touch(@needs_update_path) if needs_update
288
290
 
289
291
  $stderr.puts("Ruby LSP> Checking if the composed bundle is satisfied...")
290
- missing_gems = bundle_check
291
292
 
292
- unless missing_gems.empty?
293
+ begin
294
+ missing_gems = bundle_check
295
+ rescue Errno::EPIPE, Bundler::HTTPError
296
+ # These are errors cases where we cannot recover
297
+ raise
298
+ rescue => e
299
+ # If anything fails with bundle check, try to bundle install
300
+ $stderr.puts("Ruby LSP> Running bundle install because #{e.message}")
301
+ bundle_install
302
+ return env
303
+ end
304
+
305
+ if missing_gems.empty?
306
+ $stderr.puts("Ruby LSP> Bundle already satisfied")
307
+ else
293
308
  $stderr.puts(<<~MESSAGE)
294
309
  Ruby LSP> Running bundle install because the following gems are not installed:
295
310
  #{missing_gems.map { |g| "#{g.name}: #{g.version}" }.join("\n")}
@@ -298,11 +313,6 @@ module RubyLsp
298
313
  bundle_install
299
314
  end
300
315
 
301
- $stderr.puts("Ruby LSP> Bundle already satisfied")
302
- env
303
- rescue => e
304
- $stderr.puts("Ruby LSP> Running bundle install because #{e.message}")
305
- bundle_install
306
316
  env
307
317
  end
308
318
 
@@ -325,7 +335,7 @@ module RubyLsp
325
335
  def update(env)
326
336
  # Try to auto upgrade the gems we depend on, unless they are in the Gemfile as that would result in undesired
327
337
  # source control changes
328
- gems = ["ruby-lsp", "debug", "prism"].reject { |dep| @dependencies[dep] }
338
+ gems = GEMS_TO_UPDATE.reject { |dep| @dependencies[dep] }
329
339
  gems << "ruby-lsp-rails" if @rails_app && !@dependencies["ruby-lsp-rails"]
330
340
 
331
341
  Bundler::CLI::Update.new({ conservative: true }, gems).run
@@ -337,14 +347,14 @@ module RubyLsp
337
347
 
338
348
  #: (Hash[String, String] env) -> Hash[String, String]
339
349
  def run_bundle_install_through_command(env)
340
- # If `ruby-lsp` and `debug` (and potentially `ruby-lsp-rails`) are already in the Gemfile, then we shouldn't try
341
- # to upgrade them or else we'll produce undesired source control changes. If the composed bundle was just created
342
- # and any of `ruby-lsp`, `ruby-lsp-rails` or `debug` weren't a part of the Gemfile, then we need to run `bundle
343
- # install` for the first time to generate the Gemfile.lock with them included or else Bundler will complain that
344
- # they're missing. We can only update if the custom `.ruby-lsp/Gemfile.lock` already exists and includes all gems
350
+ # If the gems in GEMS_TO_UPDATE (and potentially `ruby-lsp-rails`) are already in the Gemfile, then we shouldn't
351
+ # try to upgrade them or else we'll produce undesired source control changes. If the composed bundle was just
352
+ # created and any of those gems weren't a part of the Gemfile, then we need to run `bundle install` for the first
353
+ # time to generate the Gemfile.lock with them included or else Bundler will complain that they're missing. We can
354
+ # only update if the custom `.ruby-lsp/Gemfile.lock` already exists and includes all gems
345
355
 
346
356
  # When not updating, we run `(bundle check || bundle install)`
347
- # When updating, we run `((bundle check && bundle update ruby-lsp debug) || bundle install)`
357
+ # When updating, we run `((bundle check && bundle update <GEMS_TO_UPDATE>) || bundle install)`
348
358
  bundler_path = File.join(Gem.default_bindir, "bundle")
349
359
  base_command = (!Gem.win_platform? && File.exist?(bundler_path) ? "#{Gem.ruby} #{bundler_path}" : "bundle").dup
350
360
 
@@ -355,12 +365,11 @@ module RubyLsp
355
365
  command = +"(#{base_command} check"
356
366
 
357
367
  if should_bundle_update?
358
- # If any of `ruby-lsp`, `ruby-lsp-rails` or `debug` are not in the Gemfile, try to update them to the latest
359
- # version
368
+ # If any of the gems in GEMS_TO_UPDATE (or `ruby-lsp-rails` for Rails apps) are not in the Gemfile, try to
369
+ # update them to the latest version
360
370
  command.prepend("(")
361
371
  command << " && #{base_command} update "
362
- command << "ruby-lsp " unless @dependencies["ruby-lsp"]
363
- command << "debug " unless @dependencies["debug"]
372
+ GEMS_TO_UPDATE.each { |gem| command << "#{gem} " unless @dependencies[gem] }
364
373
  command << "ruby-lsp-rails " if @rails_app && !@dependencies["ruby-lsp-rails"]
365
374
  command.delete_suffix!(" ")
366
375
  command << ")"
@@ -489,11 +498,16 @@ module RubyLsp
489
498
  end
490
499
 
491
500
  #: -> void
492
- def patch_thor_to_print_progress_to_stderr!
493
- return unless defined?(Bundler::Thor::Shell::Basic)
501
+ def force_output_to_stderr!
502
+ # Bundler and RubyGems have different UI objects used for printing. We need to ensure that both are configured to
503
+ # print only to stderr or else they'll break the connection with the editor
504
+ Gem::DefaultUserInteraction.ui = Gem::StreamUI.new($stdin, $stderr, $stderr, false)
505
+
506
+ ui = Bundler.ui
507
+ ui.output_stream = :stderr if ui.respond_to?(:output_stream=)
508
+ ui.level = :info
494
509
 
495
- Bundler::Thor::Shell::Basic.prepend(ThorPatch)
496
- Bundler.ui.level = :info
510
+ Bundler::Thor::Shell::Basic.prepend(ThorPatch) if defined?(Bundler::Thor::Shell::Basic)
497
511
  end
498
512
  end
499
513
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.26.4
4
+ version: 0.26.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
@@ -96,20 +96,6 @@ files:
96
96
  - lib/ruby_indexer/lib/ruby_indexer/uri.rb
97
97
  - lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb
98
98
  - lib/ruby_indexer/ruby_indexer.rb
99
- - lib/ruby_indexer/test/class_variables_test.rb
100
- - lib/ruby_indexer/test/classes_and_modules_test.rb
101
- - lib/ruby_indexer/test/configuration_test.rb
102
- - lib/ruby_indexer/test/constant_test.rb
103
- - lib/ruby_indexer/test/enhancements_test.rb
104
- - lib/ruby_indexer/test/global_variable_test.rb
105
- - lib/ruby_indexer/test/index_test.rb
106
- - lib/ruby_indexer/test/instance_variables_test.rb
107
- - lib/ruby_indexer/test/method_test.rb
108
- - lib/ruby_indexer/test/prefix_tree_test.rb
109
- - lib/ruby_indexer/test/rbs_indexer_test.rb
110
- - lib/ruby_indexer/test/reference_finder_test.rb
111
- - lib/ruby_indexer/test/test_case.rb
112
- - lib/ruby_indexer/test/uri_test.rb
113
99
  - lib/ruby_lsp/addon.rb
114
100
  - lib/ruby_lsp/base_server.rb
115
101
  - lib/ruby_lsp/client_capabilities.rb
@@ -217,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
203
  - !ruby/object:Gem::Version
218
204
  version: '0'
219
205
  requirements: []
220
- rubygems_version: 3.7.2
206
+ rubygems_version: 4.0.3
221
207
  specification_version: 4
222
208
  summary: An opinionated language server for Ruby
223
209
  test_files: []
@@ -1,140 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- require_relative "test_case"
5
-
6
- module RubyIndexer
7
- class ClassVariableTest < TestCase
8
- def test_class_variable_and_write
9
- index(<<~RUBY)
10
- class Foo
11
- @@bar &&= 1
12
- end
13
- RUBY
14
-
15
- assert_entry("@@bar", Entry::ClassVariable, "/fake/path/foo.rb:1-2:1-7")
16
-
17
- entry = @index["@@bar"]&.first #: as Entry::ClassVariable
18
- owner = entry.owner #: as !nil
19
- assert_instance_of(Entry::Class, owner)
20
- assert_equal("Foo", owner.name)
21
- end
22
-
23
- def test_class_variable_operator_write
24
- index(<<~RUBY)
25
- class Foo
26
- @@bar += 1
27
- end
28
- RUBY
29
-
30
- assert_entry("@@bar", Entry::ClassVariable, "/fake/path/foo.rb:1-2:1-7")
31
- end
32
-
33
- def test_class_variable_or_write
34
- index(<<~RUBY)
35
- class Foo
36
- @@bar ||= 1
37
- end
38
- RUBY
39
-
40
- assert_entry("@@bar", Entry::ClassVariable, "/fake/path/foo.rb:1-2:1-7")
41
- end
42
-
43
- def test_class_variable_target_node
44
- index(<<~RUBY)
45
- class Foo
46
- @@foo, @@bar = 1
47
- end
48
- RUBY
49
-
50
- assert_entry("@@foo", Entry::ClassVariable, "/fake/path/foo.rb:1-2:1-7")
51
- assert_entry("@@bar", Entry::ClassVariable, "/fake/path/foo.rb:1-9:1-14")
52
-
53
- entry = @index["@@foo"]&.first #: as Entry::ClassVariable
54
- owner = entry.owner #: as !nil
55
- assert_instance_of(Entry::Class, owner)
56
- assert_equal("Foo", owner.name)
57
-
58
- entry = @index["@@bar"]&.first #: as Entry::ClassVariable
59
- owner = entry.owner #: as !nil
60
- assert_instance_of(Entry::Class, owner)
61
- assert_equal("Foo", owner.name)
62
- end
63
-
64
- def test_class_variable_write
65
- index(<<~RUBY)
66
- class Foo
67
- @@bar = 1
68
- end
69
- RUBY
70
-
71
- assert_entry("@@bar", Entry::ClassVariable, "/fake/path/foo.rb:1-2:1-7")
72
- end
73
-
74
- def test_empty_name_class_variable
75
- index(<<~RUBY)
76
- module Foo
77
- @@ = 1
78
- end
79
- RUBY
80
-
81
- refute_entry("@@")
82
- end
83
-
84
- def test_top_level_class_variable
85
- index(<<~RUBY)
86
- @@foo = 123
87
- RUBY
88
-
89
- entry = @index["@@foo"]&.first #: as Entry::ClassVariable
90
- assert_nil(entry.owner)
91
- end
92
-
93
- def test_class_variable_inside_self_method
94
- index(<<~RUBY)
95
- class Foo
96
- def self.bar
97
- @@bar = 123
98
- end
99
- end
100
- RUBY
101
-
102
- entry = @index["@@bar"]&.first #: as Entry::ClassVariable
103
- owner = entry.owner #: as !nil
104
- assert_instance_of(Entry::Class, owner)
105
- assert_equal("Foo", owner.name)
106
- end
107
-
108
- def test_class_variable_inside_singleton_class
109
- index(<<~RUBY)
110
- class Foo
111
- class << self
112
- @@bar = 123
113
- end
114
- end
115
- RUBY
116
-
117
- entry = @index["@@bar"]&.first #: as Entry::ClassVariable
118
- owner = entry.owner #: as !nil
119
- assert_instance_of(Entry::Class, owner)
120
- assert_equal("Foo", owner.name)
121
- end
122
-
123
- def test_class_variable_in_singleton_class_method
124
- index(<<~RUBY)
125
- class Foo
126
- class << self
127
- def self.bar
128
- @@bar = 123
129
- end
130
- end
131
- end
132
- RUBY
133
-
134
- entry = @index["@@bar"]&.first #: as Entry::ClassVariable
135
- owner = entry.owner #: as !nil
136
- assert_instance_of(Entry::Class, owner)
137
- assert_equal("Foo", owner.name)
138
- end
139
- end
140
- end