Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"mcpServers": {
"rubydex": {
"command": "${HOME}/.cargo/bin/rubydex_mcp"
}
}
}
13 changes: 11 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
PATH
remote: .
specs:
ruby-lsp (0.26.9)
ruby-lsp (0.27.0.beta1)
language_server-protocol (~> 3.17.0)
prism (>= 1.2, < 2.0)
rbs (>= 3, < 5)
rubydex (~> 0.1.0.beta1)

GEM
remote: https://rubygems.org/
Expand Down Expand Up @@ -91,6 +92,10 @@ GEM
rubocop (>= 1)
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
rubydex (0.1.0.beta13-arm64-darwin)
rubydex (0.1.0.beta13-x64-mingw-ucrt)
rubydex (0.1.0.beta13-x86_64-darwin)
rubydex (0.1.0.beta13-x86_64-linux)
sorbet (0.6.13055)
sorbet-static (= 0.6.13055)
sorbet-runtime (0.6.13055)
Expand Down Expand Up @@ -197,9 +202,13 @@ CHECKSUMS
rubocop-rake (0.7.1) sha256=3797f2b6810c3e9df7376c26d5f44f3475eda59eb1adc38e6f62ecf027cbae4d
rubocop-shopify (2.17.1) sha256=03850eb1a9c4d1f9f0ac1d8d5aa51bb47a149e532cfb5e8d02ac6a90c8800a5f
rubocop-sorbet (0.8.7) sha256=670b7478425543e808558c5aa9acafeb5c9137af9ac8d3541b69d3d18ea4726b
ruby-lsp (0.26.9)
ruby-lsp (0.27.0.beta1)
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
ruby2_keywords (0.0.5) sha256=ffd13740c573b7301cf7a2e61fc857b2a8e3d3aff32545d6f8300d8bae10e3ef
rubydex (0.1.0.beta13-arm64-darwin) sha256=f840d6ec14368cca6951c093ec19518baa91fa627998ac9ff06653943a6919f1
rubydex (0.1.0.beta13-x64-mingw-ucrt) sha256=c834f3ced16fe5384b138ab8d7aa2335c43043ba4927de904a89b16bfaa05c2a
rubydex (0.1.0.beta13-x86_64-darwin) sha256=be1b16aaa2c933d437049c67f50e8e8c1c778c3a7b9661681d7ba8106b88428c
rubydex (0.1.0.beta13-x86_64-linux) sha256=0d33d3820b0e43402e019e5ae516f7de11f590fd2a1ec50063f1d820e36e1ed1
sorbet (0.6.13055) sha256=5f5e8f37c13c281fa2b2f95e261d2e531d8331ddcc8e2dd8c4f16457935872ec
sorbet-runtime (0.6.13055) sha256=c8ae8c81310e0a28d290b11f44ddca59659b7d7f13752c0ef5d16964bbb84d18
sorbet-static (0.6.13055-universal-darwin) sha256=649c8e79a443be85318922f9ecbb46be72f6c585443f4440c4ec0fb1737c86e8
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.26.9
0.27.0.beta1
4 changes: 2 additions & 2 deletions lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def on_singleton_class_node_enter(node)

if current_owner
expression = node.expression
name = (expression.is_a?(Prism::SelfNode) ? "<Class:#{last_name_in_stack}>" : "<Class:#{expression.slice}>")
name = (expression.is_a?(Prism::SelfNode) ? "<#{last_name_in_stack}>" : "<#{expression.slice}>")
real_nesting = Index.actual_nesting(@stack, name)

existing_entries = @index[real_nesting.join("::")] #: as Array[Entry::SingletonClass]?
Expand Down Expand Up @@ -577,7 +577,7 @@ def handle_class_variable(node, loc)

# set the class variable's owner to the attached context when defined within a singleton scope.
if owner.is_a?(Entry::SingletonClass)
owner = @owner_stack.reverse.find { |entry| !entry.name.include?("<Class:") }
owner = @owner_stack.reverse.find { |entry| !entry.name.include?("<") }
end

@index.add(Entry::ClassVariable.new(
Expand Down
16 changes: 8 additions & 8 deletions lib/ruby_indexer/lib/ruby_indexer/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ def linearized_ancestors_of(fully_qualified_name)
singleton_levels = 0

parts.reverse_each do |part|
break unless part.include?("<Class:")
break unless part.start_with?("<")

singleton_levels += 1
parts.pop
Expand Down Expand Up @@ -551,7 +551,7 @@ def linearized_ancestors_of(fully_qualified_name)

if nesting.any?
singleton_levels.times do
nesting << "<Class:#{nesting.last}>"
nesting << "<#{nesting.last}>"
end
end

Expand Down Expand Up @@ -616,7 +616,7 @@ def instance_variable_completion_candidates(name, owner_name)
if class_variables.any?
name_parts = owner_name.split("::")

if name_parts.last&.start_with?("<Class:")
if name_parts.last&.start_with?("<")
attached_name = name_parts[0..-2] #: as !nil
.join("::")
attached_ancestors = linearized_ancestors_of(attached_name)
Expand Down Expand Up @@ -707,7 +707,7 @@ def length
#: (String name) -> Entry::SingletonClass
def existing_or_new_singleton_class(name)
*_namespace, unqualified_name = name.split("::")
full_singleton_name = "#{name}::<Class:#{unqualified_name}>"
full_singleton_name = "#{name}::<#{unqualified_name}>"
singleton = self[full_singleton_name]&.first #: as Entry::SingletonClass?

unless singleton
Expand Down Expand Up @@ -744,7 +744,7 @@ def entries_for(uri, type = nil)
def linearized_attached_ancestors(name)
name_parts = name.split("::")

if name_parts.last&.start_with?("<Class:")
if name_parts.last&.start_with?("<")
attached_name = name_parts[0..-2] #: as !nil
.join("::")
linearized_ancestors_of(attached_name)
Expand Down Expand Up @@ -866,7 +866,7 @@ def linearize_superclass( # rubocop:disable Metrics/ParameterLists

parent_name_parts = parent_class_name.split("::")
singleton_levels.times do
parent_name_parts << "<Class:#{parent_name_parts.last}>"
parent_name_parts << "<#{parent_name_parts.last}>"
end

ancestors.concat(linearized_ancestors_of(parent_name_parts.join("::")))
Expand All @@ -878,7 +878,7 @@ def linearize_superclass( # rubocop:disable Metrics/ParameterLists
class_class_name_parts = ["Class"]

(singleton_levels - 1).times do
class_class_name_parts << "<Class:#{class_class_name_parts.last}>"
class_class_name_parts << "<#{class_class_name_parts.last}>"
end

ancestors.concat(linearized_ancestors_of(class_class_name_parts.join("::")))
Expand All @@ -892,7 +892,7 @@ def linearize_superclass( # rubocop:disable Metrics/ParameterLists
module_class_name_parts = ["Module"]

(singleton_levels - 1).times do
module_class_name_parts << "<Class:#{module_class_name_parts.last}>"
module_class_name_parts << "<#{module_class_name_parts.last}>"
end

ancestors.concat(linearized_ancestors_of(module_class_name_parts.join("::")))
Expand Down
4 changes: 2 additions & 2 deletions lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def on_singleton_class_node_enter(node)
expression = node.expression
return unless expression.is_a?(Prism::SelfNode)

@stack << "<Class:#{@stack.last}>"
@stack << "<#{@stack.last}>"
end

#: (Prism::SingletonClassNode node) -> void
Expand Down Expand Up @@ -239,7 +239,7 @@ def on_def_node_enter(node)
end

if node.receiver.is_a?(Prism::SelfNode)
@stack << "<Class:#{@stack.last}>"
@stack << "<#{@stack.last}>"
end
end

Expand Down
22 changes: 11 additions & 11 deletions lib/ruby_indexer/test/classes_and_modules_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -489,15 +489,15 @@ class ConstantPathReferences
end
RUBY

foo = @index["Foo::<Class:Foo>"] #: as !nil
foo = @index["Foo::<Foo>"] #: as !nil
.first #: as Entry::Class
assert_equal(["A1", "A2", "A3", "A4", "A5", "A6"], foo.mixin_operation_module_names)

qux = @index["Foo::Qux::<Class:Qux>"] #: as !nil
qux = @index["Foo::Qux::<Qux>"] #: as !nil
.first #: as Entry::Class
assert_equal(["Corge", "Corge", "Baz"], qux.mixin_operation_module_names)

constant_path_references = @index["ConstantPathReferences::<Class:ConstantPathReferences>"] #: as !nil
constant_path_references = @index["ConstantPathReferences::<ConstantPathReferences>"] #: as !nil
.first #: as Entry::Class
assert_equal(["Foo::Bar", "Foo::Bar2"], constant_path_references.mixin_operation_module_names)
end
Expand All @@ -512,7 +512,7 @@ class << self
end
RUBY

foo = @index["Foo::<Class:Foo>"] #: as !nil
foo = @index["Foo::<Foo>"] #: as !nil
.first #: as Entry::SingletonClass
assert_equal(4, foo.location.start_line)
assert_equal("Some extra comments", foo.comments)
Expand All @@ -527,7 +527,7 @@ class << bar
end
RUBY

singleton = @index["Foo::<Class:bar>"] #: as !nil
singleton = @index["Foo::<bar>"] #: as !nil
.first #: as Entry::SingletonClass

# Even though this is not correct, we consider any dynamic singleton class block as a regular singleton class.
Expand All @@ -547,7 +547,7 @@ class Bar
end
RUBY

assert_entry("Foo::<Class:Foo>::Bar", Entry::Class, "/fake/path/foo.rb:2-4:3-7")
assert_entry("Foo::<Foo>::Bar", Entry::Class, "/fake/path/foo.rb:2-4:3-7")
end

def test_name_location_points_to_constant_path_location
Expand Down Expand Up @@ -614,10 +614,10 @@ class << self
entries = @index.instance_variable_get(:@entries)
refute(entries.key?("::Foo"))
refute(entries.key?("::Foo::Bar"))
refute(entries.key?("::Foo::Bar::<Class:Bar>"))
refute(entries.key?("::Foo::Bar::<Bar>"))
assert_entry("Foo", Entry::Module, "/fake/path/foo.rb:0-0:5-3")
assert_entry("Foo::Bar", Entry::Class, "/fake/path/foo.rb:1-2:4-5")
assert_entry("Foo::Bar::<Class:Bar>", Entry::SingletonClass, "/fake/path/foo.rb:2-4:3-7")
assert_entry("Foo::Bar::<Bar>", Entry::SingletonClass, "/fake/path/foo.rb:2-4:3-7")
end

def test_indexing_namespaces_inside_nested_top_level_references
Expand Down Expand Up @@ -683,13 +683,13 @@ def baz; end
RUBY

# Verify we didn't index the incorrect name
assert_nil(@index["Foo::Bar::<Class:Foo::Bar>"])
assert_nil(@index["Foo::Bar::<Foo::Bar>"])

# Verify we indexed the correct name
assert_entry("Foo::Bar::<Class:Bar>", Entry::SingletonClass, "/fake/path/foo.rb:1-2:3-5")
assert_entry("Foo::Bar::<Bar>", Entry::SingletonClass, "/fake/path/foo.rb:1-2:3-5")

method = @index["baz"]&.first #: as Entry::Method
assert_equal("Foo::Bar::<Class:Bar>", method.owner&.name)
assert_equal("Foo::Bar::<Bar>", method.owner&.name)
end

def test_lazy_comments_with_spaces_are_properly_attributed
Expand Down
20 changes: 10 additions & 10 deletions lib/ruby_indexer/test/enhancements_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,18 @@ class User < ActiveRecord::Base

assert_equal(
[
"User::<Class:User>",
"ActiveRecord::Base::<Class:Base>",
"User::<User>",
"ActiveRecord::Base::<Base>",
"ActiveRecord::Associations::ClassMethods",
"Object::<Class:Object>",
"BasicObject::<Class:BasicObject>",
"Object::<Object>",
"BasicObject::<BasicObject>",
"Class",
"Module",
"Object",
"Kernel",
"BasicObject",
],
@index.linearized_ancestors_of("User::<Class:User>"),
@index.linearized_ancestors_of("User::<User>"),
)

assert_entry("new_method", Entry::Method, "/fake/path/foo.rb:10-4:10-33")
Expand Down Expand Up @@ -271,20 +271,20 @@ class User

assert_equal(
[
"User::<Class:User>",
"User::<User>",
"MyConcern::ClassMethods",
"Object::<Class:Object>",
"BasicObject::<Class:BasicObject>",
"Object::<Object>",
"BasicObject::<BasicObject>",
"Class",
"Module",
"Object",
"Kernel",
"BasicObject",
],
@index.linearized_ancestors_of("User::<Class:User>"),
@index.linearized_ancestors_of("User::<User>"),
)

refute_nil(@index.resolve_method("foo", "User::<Class:User>"))
refute_nil(@index.resolve_method("foo", "User::<User>"))
end

def test_creating_anonymous_classes_from_enhancement
Expand Down
Loading
Loading