mirror of
https://github.com/safishamsi/graphify.git
synced 2026-09-23 14:05:43 +00:00
fix(ruby): emit inherits edge for class superclass
`class Dog < Animal` exposes the base in the `superclass` field, but the inheritance handler in `_extract_generic` had branches for java/kotlin/c#/scala/cpp/php/swift/python and none for Ruby, so every Ruby `inherits` edge was silently dropped (contains/methods/calls unaffected). Add a Ruby branch that reads the `superclass` field, handling both a bare `constant` (`< Animal`) and a `scope_resolution` (`< Foo::Bar` -> Bar). Adds a subclass to the Ruby fixture and a regression test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
safishamsi
co-authored by
Claude Opus 4.8
parent
879c05894d
commit
a19b9e90ec
@@ -3426,6 +3426,37 @@ def _extract_generic(
|
||||
add_edge(class_nid, target, "references", line,
|
||||
context="generic_arg")
|
||||
|
||||
# Ruby: `class Dog < Animal` puts the base class in the `superclass`
|
||||
# field (a `<` token followed by a constant or scope_resolution).
|
||||
# There was no Ruby branch, so every Ruby inherits edge was dropped.
|
||||
if config.ts_module == "tree_sitter_ruby":
|
||||
sup = node.child_by_field_name("superclass")
|
||||
if sup is not None:
|
||||
base = ""
|
||||
for sub in sup.children:
|
||||
if sub.type == "constant":
|
||||
base = _read_text(sub, source)
|
||||
break
|
||||
if sub.type == "scope_resolution":
|
||||
consts = [c for c in sub.children if c.type == "constant"]
|
||||
if consts:
|
||||
base = _read_text(consts[-1], source)
|
||||
break
|
||||
if base:
|
||||
base_nid = _make_id(stem, base)
|
||||
if base_nid not in seen_ids:
|
||||
base_nid = _make_id(base)
|
||||
if base_nid not in seen_ids:
|
||||
nodes.append({
|
||||
"id": base_nid,
|
||||
"label": base,
|
||||
"file_type": "code",
|
||||
"source_file": "",
|
||||
"source_location": "",
|
||||
})
|
||||
seen_ids.add(base_nid)
|
||||
add_edge(class_nid, base_nid, "inherits", line)
|
||||
|
||||
# C#-specific: inheritance / interface implementation via base_list
|
||||
if config.ts_module == "tree_sitter_c_sharp":
|
||||
csharp_type_params = _csharp_type_parameters_in_scope(node, source)
|
||||
|
||||
Vendored
+6
@@ -22,6 +22,12 @@ class ApiClient
|
||||
end
|
||||
end
|
||||
|
||||
class TimeoutApiClient < ApiClient
|
||||
def fetch(path, method)
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def parse_response(raw)
|
||||
JSON.parse(raw)
|
||||
end
|
||||
|
||||
@@ -299,6 +299,22 @@ def test_ruby_finds_function():
|
||||
assert any("parse_response" in l for l in _labels(r))
|
||||
|
||||
|
||||
def test_ruby_inherits_edge():
|
||||
"""`class Sub < Base` must emit an inherits edge.
|
||||
|
||||
Ruby exposes the base class in the `superclass` field, but there was no
|
||||
Ruby branch in the inheritance handler, so the edge was silently dropped.
|
||||
"""
|
||||
r = extract_ruby(FIXTURES / "sample.rb")
|
||||
node_by_id = {n["id"]: n["label"] for n in r["nodes"]}
|
||||
found = any(
|
||||
"TimeoutApiClient" in node_by_id.get(e["source"], "")
|
||||
and node_by_id.get(e["target"], "") == "ApiClient"
|
||||
for e in r["edges"] if e["relation"] == "inherits"
|
||||
)
|
||||
assert found, "TimeoutApiClient should have inherits edge to ApiClient"
|
||||
|
||||
|
||||
# ── C# ───────────────────────────────────────────────────────────────────────
|
||||
|
||||
def test_csharp_no_error():
|
||||
|
||||
Reference in New Issue
Block a user