template_data_source.py revision 58537e28ecd584eab876aee8be7156509866d23a
1# Copyright (c) 2012 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6
7from docs_server_utils import FormatKey
8from file_system import FileNotFoundError
9from third_party.handlebar import Handlebar
10import url_constants
11
12_EXTENSIONS_URL = '/chrome/extensions'
13
14class TemplateDataSource(object):
15  '''Renders Handlebar templates, providing them with the context in which to
16  render.
17
18  Also acts as a data source itself, providing partial Handlebar templates to
19  those it renders.
20
21  Each instance of TemplateDataSource is bound to a Request so that it can
22  render templates with request-specific data (such as Accept-Language); use
23  a Factory to cheaply construct these.
24  '''
25
26  class Factory(object):
27    '''A factory to create lightweight TemplateDataSource instances bound to
28    individual Requests.
29    '''
30    def __init__(self,
31                 api_data_source_factory,
32                 api_list_data_source_factory,
33                 intro_data_source_factory,
34                 samples_data_source_factory,
35                 compiled_fs_factory,
36                 ref_resolver_factory,
37                 permissions_data_source,
38                 public_template_path,
39                 private_template_path,
40                 base_path):
41      self._api_data_source_factory = api_data_source_factory
42      self._api_list_data_source_factory = api_list_data_source_factory
43      self._intro_data_source_factory = intro_data_source_factory
44      self._samples_data_source_factory = samples_data_source_factory
45      self._cache = compiled_fs_factory.Create(self._CreateTemplate,
46                                               TemplateDataSource)
47      self._ref_resolver = ref_resolver_factory.Create()
48      self._permissions_data_source = permissions_data_source
49      self._public_template_path = public_template_path
50      self._private_template_path = private_template_path
51      self._base_path = base_path
52
53    def _CreateTemplate(self, template_name, text):
54      return Handlebar(self._ref_resolver.ResolveAllLinks(text))
55
56    def Create(self, request, data_sources):
57      '''Bind a new TemplateDataSource to a servlet.Request |request| and a
58      dictionary of instantiated DataSources*. Keys in |data_sources| are the
59      names that templates will use to access the corresponding DataSource.
60
61      * this is temporary until the data source registry transition is complete.
62      '''
63      return TemplateDataSource(
64          self._api_data_source_factory.Create(request),
65          self._api_list_data_source_factory.Create(),
66          self._intro_data_source_factory.Create(),
67          self._samples_data_source_factory.Create(request),
68          self._cache,
69          self._permissions_data_source,
70          self._public_template_path,
71          self._private_template_path,
72          self._base_path,
73          data_sources)
74
75  def __init__(self,
76               api_data_source,
77               api_list_data_source,
78               intro_data_source,
79               samples_data_source,
80               cache,
81               permissions_data_source,
82               public_template_path,
83               private_template_path,
84               base_path,
85               data_sources):
86    self._api_list_data_source = api_list_data_source
87    self._intro_data_source = intro_data_source
88    self._samples_data_source = samples_data_source
89    self._api_data_source = api_data_source
90    self._cache = cache
91    self._public_template_path = public_template_path
92    self._private_template_path = private_template_path
93    self._permissions_data_source = permissions_data_source
94    self._base_path = base_path
95    self._data_sources = data_sources
96
97  def Render(self, template_name):
98    '''This method will render a template named |template_name|, fetching all
99    the partial templates needed from |self._cache|. Partials are retrieved
100    from the TemplateDataSource with the |get| method.
101    '''
102    template = self.GetTemplate(self._public_template_path, template_name)
103    if template is None:
104      return None
105      # TODO error handling
106    render_context = {
107      'api_list': self._api_list_data_source,
108      'apis': self._api_data_source,
109      'intros': self._intro_data_source,
110      'partials': self,
111      'permissions': self._permissions_data_source,
112      'samples': self._samples_data_source,
113      'apps_samples_url': url_constants.GITHUB_BASE,
114      'extensions_samples_url': url_constants.EXTENSIONS_SAMPLES,
115      'static': self._base_path + '/static',
116      'true': True,
117      'false': False
118    }
119    render_context.update(self._data_sources)
120    render_data = template.render(render_context)
121    if render_data.errors:
122      logging.error('Handlebar error(s) rendering %s:\n%s' %
123          (template_name, '  \n'.join(render_data.errors)))
124    return render_data.text
125
126  def get(self, key):
127    return self.GetTemplate(self._private_template_path, key)
128
129  def GetTemplate(self, base_path, template_name):
130    try:
131      return self._cache.GetFromFile(
132          '/'.join((base_path, FormatKey(template_name))))
133    except FileNotFoundError:
134      return None
135