Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import os 

2import re 

3from typing import List, Tuple 

4 

5 

6class DocBlockReflection: 

7 """ 

8 A simple DocBlock reflection. 

9 """ 

10 

11 # ------------------------------------------------------------------------------------------------------------------ 

12 def __init__(self, comment: List[str]): 

13 """ 

14 Object constructor. 

15 

16 :param list[str] 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 """ 

22 

23 self._description: str = '' 

24 """ 

25 The description. 

26 """ 

27 

28 self._tags: List[Tuple[str, str]] = list() 

29 """ 

30 The tags in the DocBlock 

31 """ 

32 

33 self.__reflect() 

34 

35 # ------------------------------------------------------------------------------------------------------------------ 

36 def get_description(self) -> str: 

37 """ 

38 Returns the description. 

39 

40 :rtype: str 

41 """ 

42 return self._description 

43 

44 # ------------------------------------------------------------------------------------------------------------------ 

45 def get_tag(self, name: str) -> str: 

46 """ 

47 Returns a tag. 

48 

49 @param str name: The name of the tag. 

50 

51 :rtype: str 

52 """ 

53 for tag in self._tags: 

54 if tag[0] == name: 

55 return tag[1] 

56 

57 return '' 

58 

59 # ------------------------------------------------------------------------------------------------------------------ 

60 def get_tags(self, name: str) -> List[str]: 

61 """ 

62 Returns a list of tags. 

63 

64 @param str name: The name of the tag. 

65 

66 :rtype: list[str] 

67 """ 

68 tags = list() 

69 for tag in self._tags: 

70 if tag[0] == name: 70 ↛ 69line 70 didn't jump to line 69, because the condition on line 70 was never false

71 tags.append(tag[1]) 

72 

73 return tags 

74 

75 # ------------------------------------------------------------------------------------------------------------------ 

76 def __reflect(self) -> None: 

77 """ 

78 Parses the DocBlock. 

79 """ 

80 self.__clean_doc_block() 

81 self.__extract_description() 

82 self.__extract_tags() 

83 

84 # ------------------------------------------------------------------------------------------------------------------ 

85 @staticmethod 

86 def __remove_leading_empty_lines(lines: List[str]) -> List[str]: 

87 """ 

88 Removes leading empty lines from a list of lines. 

89 

90 :param list[str] lines: The lines. 

91 """ 

92 tmp = list() 

93 empty = True 

94 for i in range(0, len(lines)): 

95 empty = empty and lines[i] == '' 

96 if not empty: 

97 tmp.append(lines[i]) 

98 

99 return tmp 

100 

101 # ------------------------------------------------------------------------------------------------------------------ 

102 @staticmethod 

103 def __remove_trailing_empty_lines(lines: List[str]) -> List[str]: 

104 """ 

105 Removes leading empty lines from a list of lines. 

106 

107 :param list[str] lines: The lines. 

108 """ 

109 lines.reverse() 

110 tmp = DocBlockReflection.__remove_leading_empty_lines(lines) 

111 lines.reverse() 

112 tmp.reverse() 

113 

114 return tmp 

115 

116 # ------------------------------------------------------------------------------------------------------------------ 

117 def __clean_doc_block(self) -> None: 

118 """ 

119 Cleans the DocBlock from leading and trailing white space and comment tokens. 

120 """ 

121 # Return immediately if the DockBlock is empty. 

122 if not self._comment: 

123 return 

124 

125 for i in range(1, len(self._comment) - 1): 

126 self._comment[i] = re.sub(r'^\s*\*', '', self._comment[i]) 

127 

128 self._comment[0] = re.sub(r'^\s*/\*\*', '', self._comment[0]) 

129 

130 self._comment[-1] = re.sub(r'\*/\s*$', '', self._comment[-1]) 

131 

132 for i, line in enumerate(self._comment): 

133 self._comment[i] = line.strip() 

134 

135 self._comment = self.__remove_leading_empty_lines(self._comment) 

136 self._comment = self.__remove_trailing_empty_lines(self._comment) 

137 

138 # ------------------------------------------------------------------------------------------------------------------ 

139 def __extract_description(self) -> None: 

140 """ 

141 Extracts the description from the DocBlock. The description start at the first line and stops at the first tag 

142 or the end of the DocBlock. 

143 """ 

144 tmp = list() 

145 for line in self._comment: 

146 if len(line) >= 1 and line[0] == '@': 

147 break 

148 

149 tmp.append(line) 

150 

151 tmp = self.__remove_trailing_empty_lines(tmp) 

152 

153 self._description = os.linesep.join(tmp) 

154 

155 # ------------------------------------------------------------------------------------------------------------------ 

156 def __extract_tags(self) -> None: 

157 """ 

158 Extract tags from the DocBlock. 

159 """ 

160 tags = list() 

161 current = None 

162 for line in self._comment: 

163 parts = re.match(r'^@(\w+)', line) 

164 if parts: 

165 current = (parts.group(1), list()) 

166 tags.append(current) 

167 

168 if current: 

169 if line == '': 169 ↛ 170line 169 didn't jump to line 170, because the condition on line 169 was never true

170 current = None 

171 else: 

172 current[1].append(line) 

173 

174 for tag in tags: 

175 self._tags.append((tag[0], os.linesep.join(tag[1]))) 

176 

177# ----------------------------------------------------------------------------------------------------------------------