Coverage for pystratum_common/DocBlockReflection.py: 90%
78 statements
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-13 08:46 +0200
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-13 08:46 +0200
1import os
2import re
3from typing import List, Tuple
6class DocBlockReflection:
7 """
8 A simple DocBlock reflection.
9 """
11 # ------------------------------------------------------------------------------------------------------------------
12 def __init__(self, comment: List[str]):
13 """
14 Object constructor.
16 :param comment: The comment as a list of strings.
17 """
18 self._comment: List[str] = comment
19 """
20 The DocBlock as a list of strings.
21 """
23 self._description: str = ''
24 """
25 The description.
26 """
28 self._tags: List[Tuple[str, str]] = list()
29 """
30 The tags in the DocBlock
31 """
33 self.__reflect()
35 # ------------------------------------------------------------------------------------------------------------------
36 def get_description(self) -> str:
37 """
38 Returns the description.
39 """
40 return self._description
42 # ------------------------------------------------------------------------------------------------------------------
43 def get_tag(self, name: str) -> str:
44 """
45 Returns a tag.
47 @param str name: The name of the tag.
48 """
49 for tag in self._tags:
50 if tag[0] == name:
51 return tag[1]
53 return ''
55 # ------------------------------------------------------------------------------------------------------------------
56 def get_tags(self, name: str) -> List[str]:
57 """
58 Returns a list of tags.
60 @param str name: The name of the tag.
61 """
62 tags = list()
63 for tag in self._tags:
64 if tag[0] == name: 64 ↛ 63line 64 didn't jump to line 63, because the condition on line 64 was always true
65 tags.append(tag[1])
67 return tags
69 # ------------------------------------------------------------------------------------------------------------------
70 def __reflect(self) -> None:
71 """
72 Parses the DocBlock.
73 """
74 self.__clean_doc_block()
75 self.__extract_description()
76 self.__extract_tags()
78 # ------------------------------------------------------------------------------------------------------------------
79 @staticmethod
80 def __remove_leading_empty_lines(lines: List[str]) -> List[str]:
81 """
82 Removes leading empty lines from a list of lines.
84 :param lines: The lines.
85 """
86 tmp = list()
87 empty = True
88 for i in range(0, len(lines)):
89 empty = empty and lines[i] == ''
90 if not empty:
91 tmp.append(lines[i])
93 return tmp
95 # ------------------------------------------------------------------------------------------------------------------
96 @staticmethod
97 def __remove_trailing_empty_lines(lines: List[str]) -> List[str]:
98 """
99 Removes leading empty lines from a list of lines.
101 :param lines: The lines.
102 """
103 lines.reverse()
104 tmp = DocBlockReflection.__remove_leading_empty_lines(lines)
105 lines.reverse()
106 tmp.reverse()
108 return tmp
110 # ------------------------------------------------------------------------------------------------------------------
111 def __clean_doc_block(self) -> None:
112 """
113 Cleans the DocBlock from leading and trailing white space and comment tokens.
114 """
115 # Return immediately if the DockBlock is empty.
116 if not self._comment:
117 return
119 for i in range(1, len(self._comment) - 1):
120 self._comment[i] = re.sub(r'^\s*\*', '', self._comment[i])
122 self._comment[0] = re.sub(r'^\s*/\*\*', '', self._comment[0])
124 self._comment[-1] = re.sub(r'\*/\s*$', '', self._comment[-1])
126 for i, line in enumerate(self._comment):
127 self._comment[i] = line.strip()
129 self._comment = self.__remove_leading_empty_lines(self._comment)
130 self._comment = self.__remove_trailing_empty_lines(self._comment)
132 # ------------------------------------------------------------------------------------------------------------------
133 def __extract_description(self) -> None:
134 """
135 Extracts the description from the DocBlock. The description start at the first line and stops at the first tag
136 or the end of the DocBlock.
137 """
138 tmp = list()
139 for line in self._comment:
140 if len(line) >= 1 and line[0] == '@':
141 break
143 tmp.append(line)
145 tmp = self.__remove_trailing_empty_lines(tmp)
147 self._description = os.linesep.join(tmp)
149 # ------------------------------------------------------------------------------------------------------------------
150 def __extract_tags(self) -> None:
151 """
152 Extract tags from the DocBlock.
153 """
154 tags = list()
155 current = None
156 for line in self._comment:
157 parts = re.match(r'^@(\w+)', line)
158 if parts:
159 current = (parts.group(1), list())
160 tags.append(current)
162 if current:
163 if line == '': 163 ↛ 164line 163 didn't jump to line 164, because the condition on line 163 was never true
164 current = None
165 else:
166 current[1].append(line)
168 for tag in tags:
169 self._tags.append((tag[0], os.linesep.join(tag[1])))
171# ----------------------------------------------------------------------------------------------------------------------