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