template_data_source.py revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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                 file_system,
37                 ref_resolver_factory,
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(file_system,
46                                               self._CreateTemplate,
47                                               TemplateDataSource)
48      self._ref_resolver = ref_resolver_factory.Create()
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._public_template_path,
70          self._private_template_path,
71          self._base_path,
72          data_sources)
73
74  def __init__(self,
75               api_data_source,
76               api_list_data_source,
77               intro_data_source,
78               samples_data_source,
79               cache,
80               public_template_path,
81               private_template_path,
82               base_path,
83               data_sources):
84    self._api_list_data_source = api_list_data_source
85    self._intro_data_source = intro_data_source
86    self._samples_data_source = samples_data_source
87    self._api_data_source = api_data_source
88    self._cache = cache
89    self._public_template_path = public_template_path
90    self._private_template_path = private_template_path
91    self._base_path = base_path
92    self._data_sources = data_sources
93
94  def Render(self, template_name):
95    '''This method will render a template named |template_name|, fetching all
96    the partial templates needed from |self._cache|. Partials are retrieved
97    from the TemplateDataSource with the |get| method.
98    '''
99    template = self.GetTemplate(self._public_template_path, template_name)
100    if template is None:
101      return None
102      # TODO error handling
103    render_context = {
104      'api_list': self._api_list_data_source,
105      'apis': self._api_data_source,
106      'intros': self._intro_data_source,
107      'partials': self,
108      'samples': self._samples_data_source,
109      'apps_samples_url': url_constants.GITHUB_BASE,
110      'extensions_samples_url': url_constants.EXTENSIONS_SAMPLES,
111      'static': self._base_path + 'static',
112      'true': True,
113      'false': False
114    }
115    render_context.update(self._data_sources)
116    render_data = template.render(render_context)
117    if render_data.errors:
118      logging.error('Handlebar error(s) rendering %s:\n%s' %
119          (template_name, '  \n'.join(render_data.errors)))
120    return render_data.text
121
122  def get(self, key):
123    return self.GetTemplate(self._private_template_path, key)
124
125  def GetTemplate(self, base_path, template_name):
126    try:
127      return self._cache.GetFromFile(
128          '/'.join((base_path, FormatKey(template_name)))).Get()
129    except FileNotFoundError:
130      return None
131