Completed
Pull Request — master (#1098)
by Mischa
01:54
created

coalib.bearlib.languages.documentation.DocstyleDefinition   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 148
Duplicated Lines 0 %
Metric Value
dl 0
loc 148
rs 10
wmc 12

5 Methods

Rating   Name   Duplication   Size   Complexity  
A docstyle() 0 9 1
B __init__() 0 23 4
A language() 0 9 1
B markers() 0 38 1
B load() 0 52 5
1
import os.path
2
3
from coalib.misc.Compatability import FileNotFoundError
4
from coalib.misc.Decorators import generate_eq, generate_repr
5
from coalib.parsing.ConfParser import ConfParser
6
7
8
@generate_repr()
9
@generate_eq("language", "docstyle", "markers")
10
class DocstyleDefinition:
11
    """
12
    The DocstyleDefinition class holds values that identify a certain type of
13
    documentation comment (for which language, documentation style/tool used
14
    etc.).
15
    """
16
17
    # TODO: Allow flattened tuple when providing a single marker_set.
18
    #       TEST THAT!
19
    # TODO: Type checks? This class is not involved in critical processes, a
20
    #       robust user friendly frontend would be good... TEST THAT!
21
    def __init__(self, language, docstyle, markers):
22
        """
23
        Instantiates a new DocstyleDefinition.
24
25
        :param language: The case insensitive programming language of the
26
                         documentation comment, i.e. For example `"CPP"` for
27
                         C++ or `"PYTHON3"`.
28
        :param docstyle: The case insensitive documentation style/tool used
29
                         to document code, i.e. `"default"` or `"doxygen"`.
30
        :param markers:  An iterable of marker/delimiter string iterables that
31
                         identify a documentation comment. See `markers`
32
                         property for more details on markers.
33
        """
34
        self._language = language.lower()
35
        self._docstyle = docstyle.lower()
36
        self._markers = tuple(tuple(marker_set) for marker_set in markers)
37
38
        # Check marker set dimensions.
39
        for marker_set in self._markers:
40
            length = len(marker_set)
41
            if length != 3:
42
                raise ValueError("Length of a given marker set was not 3 (was "
43
                                 "actually {}).".format(length))
44
45
    @property
46
    def language(self):
47
        """
48
        The programming language.
49
50
        :return: A lower-case string defining the programming language (i.e.
51
                 "cpp" or "python").
52
        """
53
        return self._language
54
55
    @property
56
    def docstyle(self):
57
        """
58
        The documentation style/tool used to document code.
59
60
        :return: A lower-case string defining the docstyle (i.e. "default" or
61
                 "doxygen").
62
        """
63
        return self._docstyle
64
65
    @property
66
    def markers(self):
67
        """
68
        A tuple of marker sets that identify a documentation comment.
69
70
        Marker sets consist of 3 entries where the first is the start-marker,
71
        the second one the each-line marker and the last one the end-marker.
72
        For example a marker tuple with a single marker set
73
        `(("/**", "*", "*/"),)` would match following documentation comment:
74
75
        ```
76
        /**
77
         * This is documentation.
78
         */
79
        ```
80
81
        It's also possible to supply an empty each-line marker
82
        (`("/**", "", "*/")`):
83
84
        ```
85
        /**
86
         This is more documentation.
87
         */
88
        ```
89
90
        Markers are matched "greedy", that means it will match as many
91
        each-line markers as possible. I.e. for `("///", "///", "///")`):
92
93
        ```
94
        /// Brief documentation.
95
        ///
96
        /// Detailed documentation.
97
        ```
98
99
        :return: A tuple of marker/delimiter string tuples that identify a
100
                 documentation comment.
101
        """
102
        return self._markers
103
104
    @classmethod
105
    def load(cls, language, docstyle):
106
        """
107
        Returns a `DocstyleDefinition` defined for the given language and
108
        docstyle from the coala docstyle definition files.
109
110
        The marker settings are loaded from the according coalang-files. Each
111
        setting inside them are considered a marker setting.
112
113
        :param language:           The programming language. For example
114
                                   `"CPP"` for C++ or `"PYTHON3"` for Python 3.
115
                                   The given string is automatically lowered,
116
                                   so passing i.e. "CPP" or "cpp" makes no
117
                                   difference.
118
        :param docstyle:           The documentation style/tool used. For
119
                                   example `"default"` or `"doxygen"`.
120
                                   The given string is automatically lowered,
121
                                   so passing i.e. "default" or "DEFAULT" makes
122
                                   no difference.
123
        :raises FileNotFoundError: Raised when the given docstyle was not
124
                                   found. This is a compatability exception
125
                                   from `coalib.misc.Compatability` module.
126
        :raises KeyError:          Raised when the given language is not
127
                                   defined for given docstyle.
128
        :return:                   The `DocstyleDefinition` for giving language
129
                                   and docstyle.
130
        """
131
132
        docstyle = docstyle.lower()
133
134
        language_config_parser = ConfParser(remove_empty_iter_elements=False)
135
        try:
136
            docstyle_settings = language_config_parser.parse(
137
                os.path.dirname(__file__) + "/" + docstyle + ".coalang")
138
        except FileNotFoundError as ex:
139
            raise type(ex)("Docstyle definition " + repr(docstyle) + " not "
140
                           "found.")
141
142
        language = language.lower()
143
144
        try:
145
            docstyle_settings = docstyle_settings[language]
146
        except KeyError:
147
            raise KeyError("Language {} is not defined for docstyle {}."
148
                           .format(repr(language), repr(docstyle)))
149
150
        marker_sets = (tuple(value)
151
                       for key, value in
152
                           filter(lambda kv: not kv[0].startswith("comment"),
153
                                  docstyle_settings.contents.items()))
154
155
        return cls(language, docstyle, marker_sets)
156