1"""
2Utility functions to return a formatted name and description for a given view.
3"""
4import re
5
6from django.utils.encoding import force_str
7from django.utils.html import escape
8from django.utils.safestring import mark_safe
9
10from rest_framework.compat import apply_markdown
11
12
13def remove_trailing_string(content, trailing):
14    """
15    Strip trailing component `trailing` from `content` if it exists.
16    Used when generating names from view classes.
17    """
18    if content.endswith(trailing) and content != trailing:
19        return content[:-len(trailing)]
20    return content
21
22
23def dedent(content):
24    """
25    Remove leading indent from a block of text.
26    Used when generating descriptions from docstrings.
27
28    Note that python's `textwrap.dedent` doesn't quite cut it,
29    as it fails to dedent multiline docstrings that include
30    unindented text on the initial line.
31    """
32    content = force_str(content)
33    lines = [line for line in content.splitlines()[1:] if line.lstrip()]
34
35    # unindent the content if needed
36    if lines:
37        whitespace_counts = min([len(line) - len(line.lstrip(' ')) for line in lines])
38        tab_counts = min([len(line) - len(line.lstrip('\t')) for line in lines])
39        if whitespace_counts:
40            whitespace_pattern = '^' + (' ' * whitespace_counts)
41            content = re.sub(re.compile(whitespace_pattern, re.MULTILINE), '', content)
42        elif tab_counts:
43            whitespace_pattern = '^' + ('\t' * tab_counts)
44            content = re.sub(re.compile(whitespace_pattern, re.MULTILINE), '', content)
45    return content.strip()
46
47
48def camelcase_to_spaces(content):
49    """
50    Translate 'CamelCaseNames' to 'Camel Case Names'.
51    Used when generating names from view classes.
52    """
53    camelcase_boundary = '(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))'
54    content = re.sub(camelcase_boundary, ' \\1', content).strip()
55    return ' '.join(content.split('_')).title()
56
57
58def markup_description(description):
59    """
60    Apply HTML markup to the given description.
61    """
62    if apply_markdown:
63        description = apply_markdown(description)
64    else:
65        description = escape(description).replace('\n', '<br />')
66        description = '<p>' + description + '</p>'
67    return mark_safe(description)
68
69
70class lazy_format:
71    """
72    Delay formatting until it's actually needed.
73
74    Useful when the format string or one of the arguments is lazy.
75
76    Not using Django's lazy because it is too slow.
77    """
78    __slots__ = ('format_string', 'args', 'kwargs', 'result')
79
80    def __init__(self, format_string, *args, **kwargs):
81        self.result = None
82        self.format_string = format_string
83        self.args = args
84        self.kwargs = kwargs
85
86    def __str__(self):
87        if self.result is None:
88            self.result = self.format_string.format(*self.args, **self.kwargs)
89            self.format_string, self.args, self.kwargs = None, None, None
90        return self.result
91
92    def __mod__(self, value):
93        return str(self) % value
94