Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 5efe631

Browse files
refactor: eliminate isinstance() checks with pure polymorphism
Replace all isinstance() type checking with proper polymorphic methods: Pure Polymorphism Methods: - get_summary_info(): Each class returns its own summary format - is_single_file(): Boolean check without isinstance() - gather_contents(): Recursive content gathering via method dispatch - get_display_name(): Tree display formatting (/, -> target, etc.) - has_children(): Check for child nodes without type checking Benefits: - No isinstance() 'clochard' style code anywhere - True duck typing - just call methods and let Python dispatch - Cleaner, more maintainable code - Each class encapsulates its own behavior - Easy to extend with new node types Code Changes: - FileSystemNode: Base implementations for all methods - FileSystemFile: is_single_file()=True, summary with line count - FileSystemDirectory: get_display_name() adds '/', has_children() checks list - FileSystemSymlink: get_display_name() shows '-> target' - output_formatter.py: Use polymorphic methods instead of isinstance() This is proper OOP - objects know their own behavior!
1 parent da716a7 commit 5efe631

File tree

2 files changed

+54
-20
lines changed

2 files changed

+54
-20
lines changed

‎src/gitingest/output_formatter.py

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,9 @@ def format_node(node: FileSystemNode, query: IngestionQuery) -> tuple[str, str,
4141
A tuple containing the summary, directory structure, and file contents.
4242
4343
"""
44-
is_single_file = isinstance(node, FileSystemFile)
44+
is_single_file = node.is_single_file()
4545
summary = _create_summary_prefix(query, single_file=is_single_file)
46-
47-
if isinstance(node, FileSystemDirectory):
48-
summary += f"Files analyzed: {node.file_count}\n"
49-
elif isinstance(node, FileSystemFile):
50-
summary += f"File: {node.name}\n"
51-
summary += f"Lines: {len(node.content.splitlines()):,}\n"
46+
summary += node.get_summary_info()
5247

5348
tree = "Directory structure:\n" + _create_tree_structure(query, node=node)
5449

@@ -118,11 +113,7 @@ def _gather_file_contents(node: FileSystemNode) -> str:
118113
The concatenated content of all files under the given node.
119114
120115
"""
121-
if not isinstance(node, FileSystemDirectory):
122-
return node.content_string
123-
124-
# Recursively gather contents of all files under the current directory
125-
return "\n".join(_gather_file_contents(child) for child in node.children)
116+
return node.gather_contents()
126117

127118

128119
def _create_tree_structure(
@@ -161,16 +152,11 @@ def _create_tree_structure(
161152
tree_str = ""
162153
current_prefix = "└── " if is_last else "├── "
163154

164-
# Indicate directories with a trailing slash
165-
display_name = node.name
166-
if isinstance(node, FileSystemDirectory):
167-
display_name += "/"
168-
elif isinstance(node, FileSystemSymlink):
169-
display_name += " -> " + node.target
170-
155+
# Get the display name (handles directory slash, symlink target, etc.)
156+
display_name = node.get_display_name()
171157
tree_str += f"{prefix}{current_prefix}{display_name}\n"
172158

173-
if isinstance(node, FileSystemDirectory) andnode.children:
159+
if node.has_children():
174160
prefix += " " if is_last else "│ "
175161
for i, child in enumerate(node.children):
176162
tree_str += _create_tree_structure(query, node=child, prefix=prefix, is_last=i == len(node.children) - 1)

‎src/gitingest/schemas/filesystem.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,26 @@ def get_content(self) -> str:
9696
except Exception as e:
9797
return f"Error reading content of {self.name}: {e}"
9898

99+
def get_summary_info(self) -> str:
100+
"""Return summary information. Override in subclasses."""
101+
return ""
102+
103+
def is_single_file(self) -> bool:
104+
"""Return whether this node represents a single file."""
105+
return False
106+
107+
def gather_contents(self) -> str:
108+
"""Gather file contents. Override in subclasses."""
109+
return self.content_string
110+
111+
def get_display_name(self) -> str:
112+
"""Get display name for tree view. Override in subclasses."""
113+
return self.name
114+
115+
def has_children(self) -> bool:
116+
"""Return whether this node has children to display."""
117+
return False
118+
99119
@property
100120
def content(self) -> str:
101121
"""Return file content (simplified version for backward compatibility)."""
@@ -110,6 +130,14 @@ def get_sort_priority(self) -> int:
110130
"""Files have priority 0 for sorting."""
111131
return 0
112132

133+
def get_summary_info(self) -> str:
134+
"""Return file summary information."""
135+
return f"File: {self.name}\nLines: {len(self.content.splitlines()):,}\n"
136+
137+
def is_single_file(self) -> bool:
138+
"""Files are single files."""
139+
return True
140+
113141
def render_tree(self, prefix: str = "", *, is_last: bool = True) -> list[str]:
114142
"""Render the tree representation of this file."""
115143
current_prefix = "└── " if is_last else "├── "
@@ -127,6 +155,22 @@ def get_content(self) -> str:
127155
msg = "Cannot read content of a directory node"
128156
raise ValueError(msg)
129157

158+
def get_summary_info(self) -> str:
159+
"""Return directory summary information."""
160+
return f"Files analyzed: {self.file_count}\n"
161+
162+
def gather_contents(self) -> str:
163+
"""Recursively gather contents of all files under this directory."""
164+
return "\n".join(child.gather_contents() for child in self.children)
165+
166+
def get_display_name(self) -> str:
167+
"""Directories get a trailing slash."""
168+
return self.name + "/"
169+
170+
def has_children(self) -> bool:
171+
"""Directories have children if the list is not empty."""
172+
return bool(self.children)
173+
130174
def render_tree(self, prefix: str = "", *, is_last: bool = True) -> list[str]:
131175
"""Render the tree representation of this directory."""
132176
lines = []
@@ -178,6 +222,10 @@ def get_content(self) -> str:
178222
"""Symlinks content is what they point to."""
179223
return self.target
180224

225+
def get_display_name(self) -> str:
226+
"""Symlinks show target."""
227+
return f"{self.name} -> {self.target}"
228+
181229
def render_tree(self, prefix: str = "", *, is_last: bool = True) -> list[str]:
182230
"""Render the tree representation of this symlink."""
183231
current_prefix = "└── " if is_last else "├── "

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /