summaryrefslogtreecommitdiff
path: root/pystache/template_spec.py
blob: 1e3695f6ae8811360a15e59105fe4a4aa9dab0f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# coding: utf-8

"""
This module supports customized (aka special or specified) template loading.

"""

import os.path

from .loader import Loader


# TODO: consider putting TemplateSpec and SpecLoader in separate modules.

# TODO: finish the class docstring.
class TemplateSpec(object):

    """
    A mixin or interface for specifying custom template information.

    The "spec" in TemplateSpec can be taken to mean that the template
    information is either "specified" or "special."

    A view should subclass this class only if customized template loading
    is needed.  The following attributes allow one to customize/override
    template information on a per view basis.  A None value means to use
    default behavior for that value and perform no customization.  All
    attributes are initialized to None.

    Attributes:

      template: the template as a string.

      template_rel_path: the path to the template file, relative to the
        directory containing the module defining the class.

      template_rel_directory: the directory containing the template file, relative
        to the directory containing the module defining the class.

      template_extension: the template file extension.  Defaults to "mustache".
        Pass False for no extension (i.e. extensionless template files).

    """

    template = None
    # TODO: remove template_path.
    template_path = None
    template_rel_path = None
    template_rel_directory = None
    template_name = None
    template_extension = None
    template_encoding = None


# TODO: add test cases for this class.
class SpecLoader(object):

    """
    Supports loading a custom-specified template.

    """

    def __init__(self, loader=None):
        if loader is None:
            loader = Loader()

        self.loader = loader

    def _find_relative(self, spec):
        """
        Return the path to the template as a relative (dir, file_name) pair.

        The directory returned is relative to the directory containing the
        class definition of the given object.  The method returns None for
        this directory if the directory is unknown without first searching
        the search directories.

        """
        if spec.template_rel_path is not None:
            return os.path.split(spec.template_rel_path)

        # Otherwise, determine the file name separately.
        locator = self.loader._make_locator()

        template_name = (spec.template_name if spec.template_name is not None else
                         locator.make_template_name(spec))

        file_name = locator.make_file_name(template_name, spec.template_extension)

        return (spec.template_rel_directory, file_name)

    def _find(self, spec):
        """
        Find and return the path to the template associated to the instance.

        """
        dir_path, file_name = self._find_relative(spec)

        locator = self.loader._make_locator()

        if dir_path is None:
            # Then we need to search for the path.
            path = locator.find_object(spec, self.loader.search_dirs, file_name=file_name)
        else:
            obj_dir = locator.get_object_directory(spec)
            path = os.path.join(obj_dir, dir_path, file_name)

        return path

    def load(self, spec):
        """
        Find and return the template associated to a TemplateSpec instance.

        Returns the template as a unicode string.

        Arguments:

          spec: a TemplateSpec instance.

        """
        if spec.template is not None:
            return self.loader.unicode(spec.template, spec.template_encoding)

        path = self._find(spec)

        return self.loader.read(path, spec.template_encoding)