diff --git a/texla/Renderers/MediaWikiRenderer.py b/texla/Renderers/MediaWikiRenderer.py index b77947b..dfff645 100644 --- a/texla/Renderers/MediaWikiRenderer.py +++ b/texla/Renderers/MediaWikiRenderer.py @@ -1,605 +1,560 @@ import logging from .Renderer import Renderer +from .Renderer import render_hook from ..PageTree.PageTree import * class MediaWikiRenderer(Renderer): def __init__(self, configs, reporter): super().__init__(configs, reporter) self.configs = configs self.doc_title = configs['doc_title'] - #saving the hooks - self.render_hooks = { - #root - 'root-block': self.r_document, - 'default': self.default, - #text - 'par': self.r_par, - 'newpage': self.r_newpage, - 'newline': self.r_newline, - '\\': self.r_newline, - 'text': self.r_text, - 'clearpage': self.r_newpage, - 'cleardoublepage': self.r_newpage, - #formatting - 'emph': self.r_textit, - 'textbf': self.r_textbf, - 'textit': self.r_textit, - 'textsc': self.r_textsc, - 'textsuperscript': self.r_superscript, - 'textsubscript': self.r_subscript, - 'underline': self.r_underline, - 'uline': self.r_underline, - '%': self.r_special_character, - '&': self.r_special_character, - '$': self.r_special_character, - '{': self.r_special_character, - '}': self.r_special_character, - '#': self.r_special_character, - '_': self.r_special_character, - 'dots': self.r_dots, - 'ldots': self.r_dots, - 'flushright': self.r_flushright, - 'flushleft': self.r_flushleft, - 'center': self.r_center, - 'centerline': self.r_center, - 'abstract': self.r_abstract, - 'linebreak': self.r_break, - 'pagebreak': self.r_break, - 'nolinebreak': self.r_break, - 'nopagebreak': self.r_break, - 'verbatim': self.r_verbatim, - 'verb': self.r_verb, - #spaces - 'vspace': self.r_vspace, - 'mandatory_space': self.r_mandatory_space, - #theorems - 'theorem' : self.r_theorem, - 'proof' : self.r_proof, - #sectioning - 'part': self.sectioning, - 'chapter': self.sectioning, - 'section': self.sectioning, - 'subsection': self.sectioning, - 'subsubsection': self.sectioning, - 'paragraph': self.sectioning, - 'subparagraph': self.sectioning, - #math - 'displaymath': self.r_display_math, - 'inlinemath': self.r_inline_math, - 'ensuremath': self.r_inline_math, - 'equation': self.r_display_math, - 'eqnarray': self.r_align, - 'multline': self.r_align, - 'align': self.r_align, - 'alignat': self.r_align, - 'gather': self.r_gather, - #lists - 'itemize': self.r_itemize, - 'enumerate': self.r_enumerate, - 'description': self.r_description, - #quotes - 'quotation': self.r_quotes, - 'quote': self.r_quotes, - 'verse': self.r_verse, - 'footnote': self.r_footnote, - #labels - 'label': self.r_label, - 'ref': self.r_ref, - 'vref': self.r_ref, - 'pageref': self.r_ref, - 'eqref': self.r_ref, - #accents - "accented_letter": self.r_accented_letter, - #figures - "figure": self.r_figure, - #code - "lstlisting": self.r_lstlisting - } - #PageTree object + #PageTree object self.tree = PageTree(configs, reporter) #parameter for list formatting self.list_level = '' #parameters for theorem handling self.in_theorem = False self.theorem_number = 0 self.th_numbering = {} ######################################## #STARTING POINT def start_rendering(self, parser_tree_explorer): """ Entrypoint for rendering. It requires the tree of parsed blocks as parameter """ #start rendering of Rendering base class to activate plugins... super(MediaWikiRenderer, self).start_rendering(parser_tree_explorer) root_block = self.parser_tree_explorer.root_block #start the rendering from root_block self.render_block(root_block) #after rendering for PageTree structure self.tree.after_render() #end rendering of base class to stop plugins super(MediaWikiRenderer, self).end_rendering() #return the PageTree as a result return self.tree ####### ROOT BLOCK + @render_hook("root-block") def r_document(self, block): #we trigger the rendering of content text = self.render_children_blocks(block) #text is the tex outside sections self.tree.addText(text) #returning the text to respect the interface return text ######################################## #DEFAULT + @render_hook("default") def default(self, block): #we don't print anything return '' ######################################### #TEXT - + @render_hook("text") def r_text(self, block): text = block.attributes['text'] # The following replace happens as ~ is the latex symbol # for unbreakable space return text.replace("~", " ") + @render_hook("newline") def r_newline(self, block): return '\n' + @render_hook("newpage") def r_newpage(self, block): return '\n\n' + @render_hook("par") def r_par(self, block): return '\n\n' ######################################### #SECTIONING + @render_hook("part", "chapter", "section", "subsection", + "subsubsection", "paragraph", "subparagraph") def sectioning(self, block): title = block.attributes['title'] section_name = block.attributes['section_name'] #remove the \n insiede title title = re.sub('\\n*', '', title) #creation of the new page self.tree.createPage(title, section_name) #content processing text = self.render_children_blocks(block) #adding text to current page self.tree.addText(text) #exiting the section self.tree.exitPage() return '' ######################################### #MATH + @render_hook("displaymath") def r_display_math(self, block): s = block.attributes['content'] #rendering labels self.render_blocks(block.labels) return '' + s + '' + @render_hook("inlinemath", "ensuremath") def r_inline_math(self, block): s = block.attributes['content'] #rendering labels self.render_blocks(block.labels) return '' + s + '' + @render_hook("align", "eqnarray", "multiline", "alignat") def r_align(self, block): s = block.attributes['content'] #rendering labels self.render_blocks(block.labels) return '\\begin{align}' +\ s + '\end{align}' + @render_hook("gather") def r_gather(self, block): s = block.attributes['content'] output = [] for eq in s.split("\\\\"): eq = eq.replace("\n","").strip() output.append('' +\ eq + '') #rendering labels self.render_blocks(block.labels) return '\n'.join(output) ######################################### #LABELS and refs + @render_hook("label") def r_label(self, block): label = block.attributes['label'] self.tree.addLabel(label) return '' + @render_hook("ref", "vref", "pageref", "eqref") def r_ref(self, block): ref = block.attributes['ref'] #saving ref in Babel of PageTree self.tree.addReference(ref) return "{{ref@"+ ref+ "}}" ######################################### #FIGURE + @render_hook("figure") def r_figure(self, block): captions = block.get_children("caption") includegraphics = block.get_children("includegraphics") s = "[[File:" if len(includegraphics): inc = includegraphics[0] s += inc.attributes["img_name"] else: return "" if len(block.get_children("centering")): s += "|" + self.configs["keywords"]["center"] if len(captions): cap = captions[0] s += "|" + cap.attributes["caption"] s += "]]" return s ######################################### #FORMATTING + @render_hook("%", "&", "$", "{", "}", "#", "_") def r_special_character(self, block): return block.attributes['character'] + @render_hook("dots", "ldots") def r_dots(self, block): return '...' + @render_hook("textbf") def r_textbf(self, block): s = [] s.append("\'\'\'") s.append(self.render_children_blocks(block)) s.append("\'\'\'") return ''.join(s) + @render_hook("textit", "emph") def r_textit(self, block): s = [] s.append("\'\'") s.append(self.render_children_blocks(block)) s.append("\'\'") return ''.join(s) + @render_hook("textsc") def r_textsc(self, block): return self.render_children_blocks(block).upper() + @render_hook("textsuperscript") def r_superscript(self, block): s = [] s.append('') s.append(self.render_children_blocks(block)) s.append('') return ''.join(s) + @render_hook("textsubscript") def r_subscript(self, block): s = [] s.append('') s.append(self.render_children_blocks(block)) s.append('') return ''.join(s) + @render_hook("underline", "uline") def r_underline(self, block): s = [] s.append('{{Sottolineato|') s.append(self.render_children_blocks(block)) s.append('}}') return ''.join(s) + @render_hook("abstract") def r_abstract(self, block): s = [] s.append('{{Abstract|') s.append(self.render_children_blocks(block)) s.append('}}') return ''.join(s) + @render_hook("linebreak", "pagebreak", "nolinebreak", "nopagebreak") def r_break(self, block): return '' + @render_hook("vspace") def r_vspace(self,block): return '\n\n' + @render_hook("mandatory_space") def r_mandatory_space(self,block): return ' ' + @render_hook("verbatim") def r_verbatim(self, block): return '
' + block.attributes['content'] +'
' + @render_hook("verb") def r_verb(self, block): return '' + block.attributes['content'] +'' ######################################### #ALIGNMENT + @render_hook("center", "centerline") def r_center(self, block): s = [] s.append('{{Center|') s.append(self.render_children_blocks(block)) s.append('}}') return ''.join(s) + @render_hook("flushleft") def r_flushleft(self, block): s = [] s.append('{{Flushleft|') s.append(self.render_children_blocks(block)) s.append('}}') return ''.join(s) + @render_hook("flushright") def r_flushright(self, block): s = [] s.append('{{Flushright|') s.append(self.render_children_blocks(block)) s.append('}}') return ''.join(s) ######################################### #LISTS + @render_hook("itemize") def r_itemize(self, block): self.list_level += '*' s = ['\n'] for item in block.ch_blocks: s.append(self.list_level) s.append(self.render_children_blocks(item).strip()) s.append("\n") self.list_level = self.list_level[:-1] return ''.join(s) + @render_hook("enumerate") def r_enumerate(self, block): self.list_level += '#' s = ['\n'] for item in block.ch_blocks: s.append(self.list_level) s.append(self.render_children_blocks(item).replace('\n', '')) s.append("\n") self.list_level = self.list_level[:-1] return ''.join(s) + @render_hook("description") def r_description(self, block): s = ['\n'] for item in block.ch_blocks: s.append(';') s.append(item.attributes['word']) s.append(':') s.append(self.render_children_blocks(item)) s.append("\n") return ''.join(s) ######################################### #QUOTES + @render_hook("quotation", "quote") def r_quotes(self, block): s = [] s.append('
') s.append(self.render_children_blocks(block)) s.append('
') return ''.join(s) + @render_hook("verse") def r_verse(self, block): s = [] s.append('
') s.append('\n'.join(self.render_children_blocks(block).split('//'))) s.append('
') return ''.join(s) + @render_hook("footnote") def r_footnote(self, block): s = [] s.append("") s.append(self.render_children_blocks(block)) s.append("") return ''.join(s) ######################################## #Code + @render_hook("lstlisting") def r_lstlisting(self, block): s = [] if "language" in block.options: s.append(''.format(block.options["language"])) else: #check if there are any lstset block query = self.parser_tree_explorer.query_block_by_name("lstset") if len(query) == 0: s.append('') else: s.append(''.format(query[0].options["language"])) s.append(block.content) s.append('') return '\n'.join(s) ######################################### #Theorems + @render_hook("theorem") def r_theorem(self, block): #the label in theorems is not working for now th_definition = block.attributes['definition'] th_title = '' if block.attributes['title'] != None: th_title +=" "+ block.attributes['title'] s = [] #adding the theorem to the tree self.theorem_number += 1 self.tree.addTheorem(str(self.theorem_number), th_definition) #checking if the Environment template is used environ = False if self.configs['lang'] =='it': if th_definition.lower() == 'teorema': #adding content to page through a template s.append("\n{{InizioTeorema|titolo=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{FineTeorema}}\n") elif th_definition.lower() == 'definizione': s.append("\n{{InizioDefinizione|titolo=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{FineDefinizione}}\n") elif th_definition.lower() == 'proposizione': s.append("\n{{InizioProposizione|titolo=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{FineProposizione}}\n") elif th_definition.lower() == 'lemma': s.append("\n{{InizioLemma|title=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{FineLemma}}\n") elif th_definition.lower() == 'corollario': s.append("\n{{InizioCorollario|titolo=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{FineCorollario}}\n") elif th_definition.lower()[:-2] == 'eserciz': s.append("\n{{InizioEsercizio|titolo=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{FineEsercizio}}\n") elif th_definition.lower()[:-1] == 'osservazion': s.append("\n{{InizioOsservazione|titolo=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{FineOsservazione}}\n") elif th_definition.lower()[:-2] == 'esemp': s.append("\n{{InizioEsempio|titolo=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{FineEsempio}}\n") elif th_definition.lower() == 'dimostrazione': s.append("\n{{InizioDimostrazione|titolo=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{FineDimostrazione}}\n") else: s.append("\n{{Environment|name="+ th_definition + \ "|title=" + th_title +\ "|content=") s.append(self.render_children_blocks(block)) s.append("}}\n") elif self.configs['lang'] =='en': if th_definition.lower() == 'theorem': #adding content to page through a template s.append("\n{{BeginTheorem|title=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{EndTheorem}}\n") elif th_definition.lower() == 'definition': s.append("\n{{BeginDefinition|title=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{EndDefinition}}\n") elif th_definition.lower() == 'proposition': s.append("\n{{BeginProposition|title=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{EndProposition}}\n") elif th_definition.lower() == 'lemma': s.append("\n{{BeginLemma|title=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{EndLemma}}\n") elif th_definition.lower() == 'corollary': s.append("\n{{BeginCorollary|title=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{EndCorollary}}\n") elif th_definition.lower() == 'exercise': s.append("\n{{BeginExercise|title=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{EndExercise}}\n") elif th_definition.lower() == 'observation': s.append("\n{{BeginObservation|title=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{EndObservation}}\n") elif th_definition.lower() == 'remark': s.append("\n{{BeginRemark|title=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{EndRemark}}\n") elif th_definition.lower() == 'example': s.append("\n{{BeginExample|title=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{EndExample}}\n") elif th_definition.lower() == 'demonstration': s.append("\n{{BeginDemonstration|title=" + \ th_title+"|number={{thnum@"+ str(self.theorem_number)+"}}"+\ "|anchor={{thanchor@"+ str(self.theorem_number) +"}}}}") s.append(self.render_children_blocks(block)) s.append("{{EndDemonstration}}\n") else: s.append("\n{{Environment|name="+ th_definition + \ "|title=" + th_title +\ "|content=") s.append(self.render_children_blocks(block)) s.append("}}\n") #exit from theorem ambient self.tree.exitTheorem() return '\n'.join(s) + @render_hook("proof") def r_proof(self, block): s=[] if self.configs['lang'] == 'it': if block.title !=None: s.append('\n{{InizioDimostrazione|titolo='+\ block.attributes['title']+ "}}") s.append(self.render_children_blocks(block)) s.append("{{FineDimostrazione}}\n") else: s.append('\n{{InizioDimostrazione}}') s.append(self.render_children_blocks(block)) s.append("{{FineDimostrazione}}\n") elif self.configs['lang'] == 'en': if block.title !=None: s.append('\n{{BeginProof|title='+\ block.attributes['title']+"}}") s.append(self.render_children_blocks(block)) s.append("{{EndProof}}\n") else: s.append('\n{{BeginProof}}') s.append(self.render_children_blocks(block)) s.append("{{EndProof}}\n") return '\n'.join(s) ######################################### #ACCENTED letters + + @render_hook("accented_letter") def r_accented_letter(self, block): if block.attributes["accent_type"] == '"' \ and block.attributes["letter"] == "a": return "รค" if block.attributes["accent_type"] in ["'","`"]: return block.attributes["letter"]+\ block.attributes["accent_type"] else: return block.attributes["letter"] diff --git a/texla/Renderers/Renderer.py b/texla/Renderers/Renderer.py index a2a2ee9..c05fb3f 100644 --- a/texla/Renderers/Renderer.py +++ b/texla/Renderers/Renderer.py @@ -1,189 +1,225 @@ from ..Parser import Blocks from ..Parser.TreeExplorer import TreeExplorer import logging import importlib +from functools import wraps class Renderer(): + """ Base class for Renderers """ + def __init__(self, configs, reporter): self.configs = configs self.reporter = reporter #Parser TreeExplorer with parsed blocks tree. It will be filled at start self.parser_tree_explorer = None - #hooks implemented directly by the Renderer class. + #hooks dictionary self.render_hooks = {} + #Read the render hooks of the Renderer. It reads the hook of the derived Renderer. + self.parse_render_hooks() #plugins hooks self.pre_render_hooks = {} self.post_render_hooks = {} self.start_hooks = [] self.end_hooks = [] self.loaded_plugins = {} #registering plugins from the configs self.register_plugins() def register_plugins(self): + """This function loads the plugins declared in the configuration.""" for plugin in self.configs["plugins"]: module = importlib.import_module("..plugins"+'.'+ plugin, __name__) if hasattr(module, "plugin_render_hooks"): self.loaded_plugins[plugin] = module self.register_render_plugin_hooks(module.plugin_render_hooks) logging.debug("Renderer.register_plugins "\ "@ Loaded plugin: {}".format(plugin)) logging.debug("Plugin {} render hooks: {}".format( plugin, list(module.plugin_render_hooks.keys()))) if hasattr(module, "plugin_lifecycle_hooks"): self.register_lifecyle_plugin_hooks(module.plugin_lifecycle_hooks) logging.debug("Plugin {} lifecycle hooks: {}".format( plugin, list(module.plugin_lifecycle_hooks.keys()))) #adding the configurations to the plugin if "plugins_configs" in self.configs: if plugin in self.configs["plugins_configs"]: logging.debug("Plugin {} passing configs...".format(plugin)) module.configs = self.configs["plugins_configs"][plugin] def register_render_plugin_hooks(self, hooks): '''This function registers the hooks for renderer plugins. The plugins can define hooks for pre and post render actions. The pre hook receives the block before the rendering and can only return the block itself, modified. The post hook receive the block and the text from the renderer: it has to return the final text only. The keyword ALL creates a hooks for all the blocks. Note that it is always called after all the other hooks.''' for bl in hooks: if "pre" in hooks[bl]: self.register_pre_renderer_hook(bl, hooks[bl]["pre"]) if "post" in hooks[bl]: self.register_post_renderer_hook(bl, hooks[bl]["post"]) #checking ALL keyword if "ALL" in hooks: if "pre" in hooks["ALL"]: self.register_pre_renderer_hook(bl, hooks["ALL"]["pre"]) if "post" in hooks["ALL"]: self.register_post_renderer_hook(bl, hooks["ALL"]["post"]) def register_lifecyle_plugin_hooks(self, hooks): ''' This function registers the hooks for the renderer lifecycle. Plugins can register hooks for the start and end actions. The start hook is called with the root_block of the chain. The end hook is called without arguments. These hooks must be used only to signal the actions to the plugins.''' if "start" in hooks: self.register_start_hook(hooks["start"]) if "end" in hooks: self.register_end_hook(hooks["end"]) def register_pre_renderer_hook(self, block, hook): if block not in self.pre_render_hooks: self.pre_render_hooks[block] = [] self.pre_render_hooks[block].append(hook) def register_post_renderer_hook(self, block, hook): if block not in self.post_render_hooks: self.post_render_hooks[block] = [] self.post_render_hooks[block].append(hook) def register_start_hook(self, hook): self.start_hooks.append(hook) def register_end_hook(self, hook): self.end_hooks.append(hook) + def parse_render_hooks(self): + """ + The function scans the Renderer (sub)class to find the functions + annotated with @render_hooks(list_of_block_names). It inserts + the function in the render_hooks using the provided block_names. + """ + for member_name in dir(self): + member = getattr(self, member_name) + if hasattr(member, "block_names"): + for hook in getattr(member, "block_names"): + logging.debug("Renderer @ render_hook registered: {} -> {}" + .format(hook, member_name)) + self.render_hooks[hook] = member + def start_rendering(self, parser_tree_explorer): ''' Entrypoing for the rendering process. This function requests the TreeExplorer containing the parsed blocks and passes it to the plugins that have the variable needs_tree_explorer=True. Then it starts the plugins''' self.parser_tree_explorer = parser_tree_explorer #passing the tree_explorer for pl in self.loaded_plugins.values(): if hasattr(pl, "needs_tree_explorer"): if pl.needs_tree_explorer: logging.debug("Renderer @ Inserting "\ "TreeExplorer into plugin {}".format(pl)) pl.tree_explorer = self.parser_tree_explorer #starting the plugins for hook in self.start_hooks: hook() def end_rendering(self): #ending plugins for hook in self.end_hooks: hook() def render_children_blocks(self, block, collapse=True): '''This is one of the most important funciont of the rendering process. This function takes all the children blocks of a block and get they rendering output. If collapsed=True it returns a unique string, otherwise it returns a list of tuples with[(block_name, output)] ''' output = [] for bl in block.ch_blocks: #it's not necessary checking for renderer_hook #because default hook is mandatory output.append((bl.block_name, self.render_block(bl))) if collapse: return ''.join([x[1] for x in output]) else: return output def render_block(self, bl): '''This function calls the right render_hook for the block. If there isn't an hook it calld the default, that is mandatory''' output = "" ######### pre hooks ############ #hooks executed in the order of inserction #They receive the block and they can only modify the block object if bl.block_name in self.pre_render_hooks: for prehook in self.pre_render_hooks[bl.block_name]: #calling prehook with the block prehook(bl) #calling after the others the ALL hooks if "ALL" in self.pre_render_hooks: for prehook in self.pre_render_hooks["ALL"]: #calling prehook with the block prehook(bl) ######## rendering ############# if bl.block_name in self.render_hooks: logging.debug('Render @ block: ' + bl.block_name) output = self.render_hooks[bl.block_name](bl) else: #default hook is mandatory logging.debug('Render @ block: default@' + bl.block_name) #reporting to the Reporter if bl.block_name != "default": self.reporter.add_not_rendered_block(bl) output = self.render_hooks['default'](bl) ######## post hooks ########### #hooks executed in the order of inserction. #They receive the block and text. They have to return the #output text, that is passed to the next posthook if bl.block_name in self.post_render_hooks: for posthook in self.post_render_hooks[bl.block_name]: #calling posthook with the block and output output = posthook(bl, output) #calling ALL hooks after the others if "ALL" in self.post_render_hooks: for posthook in self.post_render_hooks["ALL"]: #calling posthook with the block and output output = posthook(bl, output) #final output return output def render_blocks(self, bls, collapse=False): '''This function renderes a list of blocks. It's the same as render_children_blocks but with a generic list''' output = [] for bl in bls: output.append((bl.block_name,self.render_block(bl))) if collapse: return ''.join([x[1] for x in output]) else: return output + + +############################################################################### +# Decorators for renderers + +def render_hook(*block_names): + """This decorate assigns to a function the list of block_names + that it will handle as a render_hook.""" + def decorate(func): + #adding the list of block names as an attribute of the function + setattr(func, "block_names", block_names) + @wraps(func) + def wrapper(*args,**kwargs): + return func(*args, **kwargs) + return wrapper + return decorate