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