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