1 #!/usr/bin/env python 2 3 """ 4 Metadata for document conversion. 5 6 Copyright (C) 2018, 2019, 2021, 2023 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from moinformat.input import get_input 23 from moinformat.links import get_linker 24 from moinformat.output import get_output 25 from moinformat.parsers import get_parser, parsers 26 from moinformat.serialisers import get_serialiser, serialisers 27 from moinformat.themes import get_theme 28 from moinformat.translators import get_translator, translators 29 30 class Metadata: 31 32 "Metadata employed in the document conversion process." 33 34 defaults = { 35 "attachments" : "attachments", 36 "input_format" : "moin", 37 "output_context" : "standalone", 38 "output_format" : "moin", 39 "root_pagename" : "FrontPage", 40 } 41 42 default_effects = { 43 "output_format" : "link_format", 44 } 45 46 effects = { 47 "input_context" : ["input"], 48 "input_format" : ["parser", "serialiser", "translator"], 49 "input_separator" : ["input"], 50 "link_format" : ["linker"], 51 "output_context" : ["output"], 52 "output_format" : ["serialiser", "translator"], 53 "theme_name" : ["theme"], 54 } 55 56 def __init__(self, parameters=None): 57 58 "Initialise the metadata collection using the 'parameters'." 59 60 self.parameters = parameters or {} 61 62 def __repr__(self): 63 return "Metadata(%r)" % self.parameters 64 65 def copy(self): 66 67 "Return a copy of this instance." 68 69 parameters = {} 70 parameters.update(self.parameters) 71 return self.__class__(parameters) 72 73 def get(self, name, default=None): 74 75 """ 76 Return the setting for 'name', returning 'default' if 'name' is not 77 set. If 'default' is None or omitted and a default is present in the 78 defaults registry, this is returned if no setting is defined. 79 """ 80 81 value = self.parameters.get(name, default) 82 if value is None: 83 return self.defaults.get(name, default) 84 else: 85 return value 86 87 def has_key(self, name): 88 return self.parameters.has_key(name) 89 90 def set(self, name, value): 91 92 "Set 'name' as 'value' in the metadata." 93 94 self.parameters[name] = value 95 96 # Invalidate any affected settings. 97 98 affected = self.effects.get(name) 99 100 if affected: 101 for affected_name in affected: 102 if self.has_key(affected_name): 103 del self.parameters[affected_name] 104 105 # Set any default values. 106 107 affected = self.default_effects.get(name) 108 109 if affected and not self.get(affected): 110 self.set(affected, value) 111 112 def get_update(self, name, value=None): 113 114 """ 115 Obtain the 'name' setting, this being overwritten by 'value' if 116 specified. Return the updated setting. 117 """ 118 119 # Overwrite any existing setting. 120 121 if value: 122 self.set(name, value) 123 return value 124 else: 125 return self.get(name) 126 127 def make_object(self, name, cls): 128 129 """ 130 Make an object to be stored in the setting 'name', using 'cls' as the 131 object class. 132 """ 133 134 # Return any existing, preserved object. Since updates to various 135 # properties will discard objects, any preserved object should still be 136 # applicable. 137 138 obj = self.get(name) 139 if obj: 140 return obj 141 142 # Without any object class, return None. 143 144 if not cls: 145 self.set(name, None) 146 return None 147 148 # Instantiate the class and record the object. 149 150 obj = cls(self) 151 self.set(name, obj) 152 return obj 153 154 def get_input(self, name=None): 155 156 """ 157 Make an input context using any given 'name' or otherwise using the 158 "input_context" setting which will be replaced by any given 'name'. 159 """ 160 161 cls = get_input(self.get_update("input_context", name)) 162 163 return self.make_object("input", cls) 164 165 def get_linker(self, name=None): 166 167 """ 168 Make a linker using any given 'name' or otherwise using the 169 "link_format" setting which will be replaced by any given 'name'. 170 """ 171 172 cls = get_linker(self.get_update("link_format", name)) 173 174 return self.make_object("linker", cls) 175 176 def get_output(self, name=None): 177 178 """ 179 Make an output context using any given 'name' or otherwise using the 180 "output_context" setting which will be replaced by any given 'name'. 181 """ 182 183 cls = get_output(self.get_update("output_context", name)) 184 185 return self.make_object("output", cls) 186 187 def get_parser(self, name=None): 188 189 """ 190 Make a parser using any given 'name' or otherwise using the 191 "input_format" setting which will be replaced by any given 'name'. 192 """ 193 194 cls = get_parser(self.get_update("input_format", name)) 195 196 parser = self.make_object("parser", cls) 197 parser.parsers = parsers 198 return parser 199 200 def get_serialiser(self, name=None): 201 202 """ 203 Make a serialiser using any given 'name' or otherwise using the 204 "output_format" setting which will be replaced by any given 'name'. 205 """ 206 207 cls = get_serialiser(self.get_update("output_format", name), 208 self.get("input_format")) 209 210 serialiser = self.make_object("serialiser", cls) 211 serialiser.serialisers = serialisers 212 return serialiser 213 214 def get_theme(self, name=None): 215 216 """ 217 Make a theme using any given 'name' or otherwise using the "theme_name" 218 setting which will be replaced by any given 'name'. 219 """ 220 221 cls = get_theme(self.get_update("theme_name", name)) 222 223 return self.make_object("theme", cls) 224 225 def get_translator(self, name=None): 226 227 """ 228 Make a translator using any given 'name' or otherwise using the 229 "output_format" setting which will be replaced by any given 'name'. 230 """ 231 232 cls = get_translator(self.get_update("output_format", name), 233 self.get("input_format")) 234 235 translator = self.make_object("translator", cls) 236 translator.translators = translators 237 return translator 238 239 # vim: tabstop=4 expandtab shiftwidth=4