Extract classes, methods, singleton methods, and calls from a .rb file.
(path: Path)
| 1247 | |
| 1248 | |
| 1249 | def extract_ruby(path: Path) -> dict: |
| 1250 | """Extract classes, methods, singleton methods, and calls from a .rb file.""" |
| 1251 | try: |
| 1252 | import tree_sitter_ruby as tsruby |
| 1253 | from tree_sitter import Language, Parser |
| 1254 | except ImportError: |
| 1255 | return {"nodes": [], "edges": [], "error": "tree-sitter-ruby not installed"} |
| 1256 | |
| 1257 | try: |
| 1258 | language = Language(tsruby.language()) |
| 1259 | parser = Parser(language) |
| 1260 | source = path.read_bytes() |
| 1261 | tree = parser.parse(source) |
| 1262 | root = tree.root_node |
| 1263 | except Exception as e: |
| 1264 | return {"nodes": [], "edges": [], "error": str(e)} |
| 1265 | |
| 1266 | stem = path.stem |
| 1267 | str_path = str(path) |
| 1268 | nodes: list[dict] = [] |
| 1269 | edges: list[dict] = [] |
| 1270 | seen_ids: set[str] = set() |
| 1271 | |
| 1272 | def add_node(nid: str, label: str, line: int) -> None: |
| 1273 | if nid not in seen_ids: |
| 1274 | seen_ids.add(nid) |
| 1275 | nodes.append({ |
| 1276 | "id": nid, |
| 1277 | "label": label, |
| 1278 | "file_type": "code", |
| 1279 | "source_file": str_path, |
| 1280 | "source_location": f"L{line}", |
| 1281 | }) |
| 1282 | |
| 1283 | def add_edge_raw(src: str, tgt: str, relation: str, line: int, confidence: str = "EXTRACTED", weight: float = 1.0) -> None: |
| 1284 | edges.append({ |
| 1285 | "source": src, |
| 1286 | "target": tgt, |
| 1287 | "relation": relation, |
| 1288 | "confidence": confidence, |
| 1289 | "source_file": str_path, |
| 1290 | "source_location": f"L{line}", |
| 1291 | "weight": weight, |
| 1292 | }) |
| 1293 | |
| 1294 | file_nid = _make_id(stem) |
| 1295 | add_node(file_nid, path.name, 1) |
| 1296 | |
| 1297 | function_bodies: list[tuple[str, object]] = [] |
| 1298 | |
| 1299 | def walk(node, parent_class_nid: str | None = None) -> None: |
| 1300 | t = node.type |
| 1301 | |
| 1302 | if t == "class": |
| 1303 | # name is a child node (not a field in all versions) |
| 1304 | name_node = node.child_by_field_name("name") |
| 1305 | if name_node is None: |
| 1306 | for child in node.children: |