Completed
Pull Request — master (#2423)
by
unknown
01:59
created

DocumentationComment.assemble_documentation()   B

Complexity

Conditions 7

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
c 1
b 0
f 0
dl 0
loc 16
rs 7.3333
1
from collections import namedtuple
2
3
from coala_decorators.decorators import generate_eq, generate_repr
4
5
6
@generate_repr()
7
@generate_eq("documentation", "language", "docstyle",
8
             "indent", "marker", "range")
9
class DocumentationComment:
10
    """
11
    The DocumentationComment holds information about a documentation comment
12
    inside source-code, like position etc.
13
    """
14
    Parameter = namedtuple('Parameter', 'name, desc')
15
    ReturnValue = namedtuple('ReturnValue', 'desc')
16
    Description = namedtuple('Description', 'desc')
17
18
    def __init__(self, documentation, docstyle_definition,
19
                 indent, marker, range):
20
        """
21
        Instantiates a new DocumentationComment.
22
23
        :param documentation: The documentation text.
24
        :param language:      The language of the documention.
25
        :param docstyle:      The docstyle used in the documentation.
26
        :param indent:        The string of indentation used in front
27
                              of the first marker of the documentation.
28
        :param marker:        The three-element tuple with marker strings,
29
                              that identified this documentation comment.
30
        :param range:         The position range of type TextRange.
31
        """
32
        self.documentation = documentation
33
        self.metadata = docstyle_definition.metadata
34
        self.language = docstyle_definition.language.lower()
35
        self.docstyle = docstyle_definition.docstyle.lower()
36
        self.indent = indent
37
        self.marker = marker
38
        self.range = range
39
40
    def __str__(self):
41
        return self.documentation
42
43
    def parse(self):
44
        """
45
        Parses documentation independent of language and docstyle.
46
47
        :return:
48
            The list of all the parsed sections of the documentation. Every
49
            section is a namedtuple of either ``Description`` or ``Parameter``
50
            or ``ReturnValue``.
51
        :raises NotImplementedError:
52
            When no parsing method is present for the given language and
53
            docstyle.
54
        """
55
        if self.language == "python" and self.docstyle == "default":
56
            return self._parse_documentation_with_symbols(
57
                (":param ", ":"), ":return: ")
58
        elif self.language == "python" and self.docstyle == "doxygen":
59
            return self._parse_documentation_with_symbols(
60
                ("@param ", " "), "@return ")
61
        elif self.language == "java" and self.docstyle == "default":
62
            return self._parse_documentation_with_symbols(
63
                ("@param  ", " "), "@return ")
64
65
    def _parse_documentation_with_symbols(self, param_identifiers,
66
                                          return_identifiers):
67
        """
68
        Parses documentation based on parameter and return symbols.
69
70
        :param param_identifiers:
71
            A tuple of two strings with which a parameter starts and ends.
72
        :param return_identifiers:
73
            The string with which a return description starts.
74
        :return:
75
            The list of all the parsed sections of the documentation. Every
76
            section is a namedtuple of either ``Description`` or ``Parameter``
77
            or ``ReturnValue``.
78
        """
79
        lines = self.documentation.splitlines(keepends=True)
80
81
        parse_mode = self.Description
82
83
        cur_param = ""
84
85
        desc = ""
86
        parsed = []
87
88
        for line in lines:
89
90
            stripped_line = line.strip()
91
92
            print(self.metadata.param_start)
93
            if stripped_line.startswith(self.metadata.param_start):
94
                parse_mode = self.Parameter
95
                param_offset = line.find(
96
                    self.metadata.param_start) + len(self.metadata.param_start)
97
                splitted = line[param_offset:].split(self.metadata.param_end, 1)
98
                cur_param = splitted[0].strip()
99
100
                param_desc = splitted[1]
101
                parsed.append(self.Parameter(name=cur_param, desc=param_desc))
102
103
            elif stripped_line.startswith(return_identifiers):
104
                parse_mode = self.ReturnValue
105
                return_offset = line.find(
106
                    self.metadata.return_sep) + len(self.metadata.return_sep)
107
                retval_desc = line[return_offset:]
108
                parsed.append(self.ReturnValue(desc=retval_desc))
109
110
            elif parse_mode == self.ReturnValue:
111
                retval_desc += line
112
                parsed.pop()
113
                parsed.append(self.ReturnValue(desc=retval_desc))
114
115
            elif parse_mode == self.Parameter:
116
                param_desc += line
117
                parsed.pop()
118
                parsed.append(self.Parameter(name=cur_param, desc=param_desc))
119
120
            else:
121
                desc += line
122
                # This is inside a try-except for cases where the list
123
                # is empty and has nothing to pop.
124
                try:
125
                    parsed.pop()
126
                except IndexError:
127
                    pass
128
                parsed.append(self.Description(desc=desc))
129
130
        return parsed
131
132
    @classmethod
133
    def assemble_documentation(cls, doccomment, param, ret):
134
        assembled_doc = ""
135
        for section in doccomment:
136
            section_desc = section.desc.splitlines(keepends=True)
137
            if isinstance(section, cls.Description):
138
                assembled_doc += section_desc[0]
139
            elif isinstance(section, cls.Parameter):
140
                assembled_doc += (param[0] + section.name + param[1] +
141
                                  section_desc[0])
142
            elif isinstance(section, cls.ReturnValue):
143
                assembled_doc += ret + section_desc[0]
144
            for desc in section_desc[1:]:
145
                if desc != "":
146
                    assembled_doc += desc
147
        return assembled_doc
148